Search code examples
amazon-web-servicesterraformterraform-provider-awsterraform0.12+terraform-template-file

Terraform - Iterate over a map of Objects in a Template to generate different yaml files


I need to generate around 50 YAML files. Most of the content in the YAML is constant, only name, and port changes. I am using Terraform v1.2.2. I request you to help me correct my issue or suggest an alternate idea/solution achieve my goal

netwrokfile.yaml after generation

    apiVersion: projectcalico.org/v3
    kind: GlobalNetworkPolicy
    metadata:
      name: web-policy # Changes
    spec:
      action: allow    
      rules: 
      - to:
        - operation:
            ports: ["9080", "8080"] # Changes from each application may have one or two or three ports.
    selector:
      matchLabels:
        app: web-policy # Changes

networkfile.yaml.tpl

    apiVersion: projectcalico.org/v3
    kind: GlobalNetworkPolicy
    metadata:
    %{~ for sName, sPort in zipmap(sName, sPort) ~}
      name: ${sName}
    spec:
      action: allow
      rules:
      - to:
         - operation:
           ports: ${sPort}
    selector:
      matchLabels:
        app: ${sName}
    %{~ endfor ~}

main.tf in my module

resource "kubernetes_manifest" "istio-config" {
   manifest = templatefile("${path.module}/templates/networkfile.yaml.tpl",
   {
     sName =  [for v in var.serviceName: v.sName]
     sPort =  [for v in var.serviceName: v.sPort]
   }
    )
  }

main.tf calling my module

module "authorization_policy" {
  source = "../../modules/GlobalNetworkPolicy"

  serviceName = var.serviceName
}

Myy variable.tf

variable "serviceName" {
type = map(object({
  sName  = string
  sPort = list(string)
}))
default = {
  test-vm1 = {
    sName  = "web-policy"
    sPort = ["8080", "8081"]
  },
  test-vm2 = {
    sName  = "db-policy"
    sPort = ["8080", "8081", "443"]
  }
}
}

With the above code, I get the below error

can't unmarshal tftypes.String into *map[string]tftypes.Value, expected map[string]tftypes.Value

I tried using the solution mentioned here (Terraform - Iterate over a List of Objects in a Template). But it didn't help and it gives me the same error.

I also tried (https://www.terraform.io/language/functions/templatefile) it give me a completely different error

Call to function "templatefile" failed: ../../modules/GlobalNetworkPolicy/templates/networkfile.yaml.tpl:5,3-4: Unsupported operator; Bitwise operators are not supported. Did you mean boolean NOT ("!")?,
│ and 4 other diagnostic(s).

Below is the complete error - Fixed by adding yamlencode

╷
│ Error: Failed to extract "manifest" attribute value from resource configuration
│
│   with module.authorization_policy.kubernetes_manifest.istio-config,
│   on ../../modules/GlobalNetworkPolicy/main.tf line 2, in resource "kubernetes_manifest" "istio-config":
│    2:    manifest = templatefile("${path.module}/templates/networkfile.yaml.tpl",
│    3:    {
│    4:      serviceName = var.serviceName
│    5:    }
│    6:     )
│
│ can't unmarshal tftypes.String into *map[string]tftypes.Value, expected map[string]tftypes.Value

Solution

  • You can simply your code as:

    resource "kubernetes_manifest" "istio-config" {
       manifest = yamldecode(templatefile("${path.module}/templates/networkfile.yaml.tpl",
       {
         serviceName = var.serviceName
       }
        ))
      }
    
    apiVersion: projectcalico.org/v3
    kind: GlobalNetworkPolicy
    metadata:
    %{ for k, v in serviceName }
      name: ${v.sName}
    spec:
      action: allow
      rules:
      - to:
         - operation:
           ports: ${jsonencode(v.sPort)}
    selector:
      matchLabels:
        app: ${v.sName}
    %{ endfor }