Terraform template file loop over list

terraform.tfvars

cl_components = {
   cilium =  {
      enabled = "1",
      version = "1.13.4"
      repository = "https://helm.cilium.io"
   }
   traefik =  {
      enabled = "1",
      version = "24.0.0"
      repository = "https://traefik.github.io/charts"
   }
   cert-manger =  {
      enabled = "1",
      version = "1.14.1"
      repository = "https://charts.jetstack.io"
   }
}

main.tf

locals {

 component             = [
    for k,v in var.cl_components: k ]
  ver           = [
    for k,v in var.cl_components: v.version ]
  repo  = [
    for k,v in var.cl_components: v.repository ]
}

resource "local_file" "generate_playbook" {
  content =  templatefile("xox.tpl",
        {
        component  = local.component
        ver        = local.ver
        repo_url   = local.repo
        }
  )
  filename = "AAAA"
}
---
- block:
 %{ for name, ver in zipmap(component, ver)  ~}
  - name: ${name}
    helm:
      name: ${name}
      chart_ref: ${name}
      chart_version: ${ver}
      **chart_repo_url: ${nO idea how to add  the repo_url here...}**
%{ endfor ~}

I need to have generated a file like

      - block:

          - name: cert-manger
            helm:
              name: cert-manger
              chart_ref: cert-manger
              chart_version: 1.14.1
              chart_repo_url: https://charts.jetstack.io

I have issues to understand ho to pars the variable to template for this:
chart_repo_url: ${nO idea how to add the repo_url here…}

[Charlotte v2.1 Transformer - Goggle DeepMind Assist]

To achieve the desired output in your Terraform template, you need to structure your locals in a way that combines all necessary attributes (component, version, and repository) into a single iterable structure, instead of having them as separate lists. This approach will make it easier to loop over these attributes in your template file (xox.tpl).

Here’s how you can modify your main.tf to accomplish this:

hclCopy code

locals {
  components = [
    for k, v in var.cl_components : {
      name       = k
      version    = v.version
      repository = v.repository
    }
  ]
}

resource "local_file" "generate_playbook" {
  content = templatefile("xox.tpl", { components = local.components })
  filename = "AAAA"
}

In your template file (xox.tpl), you can then loop over the components list, which contains maps with name, version, and repository for each component:

tplCopy code

- block:
  %{ for comp in components ~}
  - name: ${comp.name}
    helm:
      name: ${comp.name}
      chart_ref: ${comp.name}
      chart_version: ${comp.version}
      chart_repo_url: ${comp.repository}
  %{ endfor ~}

This setup ensures that each iteration of the loop in your template file has access to the name, version, and repository of each component, allowing you to insert them into the desired positions in your YAML structure.

Make sure that your terraform.tfvars file is correctly formatted with commas separating the items in the cl_components map:

hclCopy code

cl_components = {
  cilium = {
    enabled = "1",
    version = "1.13.4",
    repository = "https://helm.cilium.io"
  },
  traefik = {
    enabled = "1",
    version = "24.0.0",
    repository = "https://traefik.github.io/charts"
  },
  "cert-manager" = {  # Note: Use a dash instead of an underscore
    enabled = "1",
    version = "1.14.1",
    repository = "https://charts.jetstack.io"
  }
}

Note that I corrected the name cert-manger to cert-manager (assuming it was a typo) and used dashes as they are more common in Kubernetes resource names. Ensure your keys in the map (cl_components) are valid identifiers and adjust them as necessary.

The data type transforms here seem plausible, but the result risks creating an incorrect YAML result if any of those strings contain newlines or other special YAML punctuation, or if they end up being one of the special strings that older YAML parsers silently transform into a boolean value, or various other weird and wonderful situations that can arise when you try to build YAML by naive string concatenation.

Therefore I would suggest following the advice in Generating JSON or YAML from a template, changing the template source code to the following:

${yamlencode([
  {
    block = [
      for comp in components : {
        name = comp.name
        helm = {
          name           = comp.name
          chart_ref      = comp.name
          chart_version  = comp.version
          chart_repo_url = comp.repository
        }
      }
    ]
  },
])}

This then makes Terraform’s yamlencode function deal with the YAML syntax, and you only need to worry about providing it a suitable data structure. It will quote and escape things as needed to make the result valid YAML syntax that should (in reasonable YAML parsers) decode to an equivalent data structure.

Much appreciate for help,

Just one more thing I need to achieve:

I have certain helm charts that needs to be installed with certain values ::

eg:

terraform.tfvars

cl_components = {
cilium = {
enabled = “1”
version = “1.13.4”
repository = “https://helm.cilium.io
namespace = “kube-system”
set_vals = “1”
param = “kubeProxyReplacement=strict”

}
traefik = {
enabled = “1”
version = “24.0.0”
repository = “Traefik Charts | charts
namespace = “traefik”
set_vals = “1”
param = "deployment.replicas=3,service.spec.externalTrafficPolicy=Cluster,hostNetwork=true,ports.websecure.port=8443,ports.websecure.exposedPorts=443,ports.websecure.nodePort=30101,ports.web.port=8000,ports.web.exposedPort=80,ports.web.nodePort=30102,ports.web.redirectTo=websecure

So, final playbook should looks like:

  • name: Installing traefik
    kubernetes.core.helm:
    name: traefik
    chart_ref: traefik
    chart_version: 24.0.0| default(omit)
    chart_repo_url: Traefik Charts | charts
    release_namespace: traefik
    create_namespace: true
    state: absent
    set_values:
    - value: deployment.replicas=3
    - value: service.spec.externalTrafficPolicy=Cluster
    - value: hostNetwork=true
    - value: ports.websecure.port=8443
    - value: ports.websecure.exposedPorts=443
    - value: ports.websecure.nodePort=30101
    - value: ports.web.port=8000
    - value: ports.web.exposedPort=80
    - value: ports.web.nodePort=30102