mm3398145
mm3398145

Reputation: 23

How to iterate through nested list of objects in Terraform

I'm creating TF module, which downloads specified yaml files and then uses the yamls as a source for data field in k8s configmaps. I have working solution to create multiple configmaps with one data key-value pair(yaml file), but need also add support for multiple key-value pairs (yaml files) per one configmap.

main.tf

data "http" "config-map" {
  for_each = var.cloud-configmap

  url = format("https://%s", each.value.url)

  request_headers = {
    Accept = "text/plain"
  }
}

resource "kubernetes_config_map" "configmap" {
  for_each = var.cloud-configmap

  metadata {
    name = each.value.name
    namespace = each.value.namespace
  }

  data = {
    "${each.value.data-keyname}" = data.http.config-map[each.key].body
  }
}

variables.tf

variable "cloud-configmap" {
  type = map(object({
    url = string
    name = string
    namespace = string
    data-keyname = string
  }))
  default = {
    "cm1" = {
      url = "someurl.com/file1.yaml"
      name = "cm-name"
      namespace = "test"
      data-keyname = "file1.yml"
    },
    "cm2" = {
      url = "someurl.com/file2.yaml"
      name = "cm-name2"
      namespace = "default"
      data-keyname = "file2.yml"
    }
  }
}

This code till now is working, but I would like to change the variables.tf file to this:

variable "cloud-configmap" {
  type = map(object({
    name = string
    namespace = string
    cm-files = list(object({
      url = string
      data-keyname = string 
    }))
  }))
  default = {
    "cm1" = {
      name = "cm-name"
      namespace = "testnamespace"
      cm-files = [{
        url = "someurl.com/file1.yaml"
        data-keyname = "file1.yml"
      },
      {
        url = "someurl.com/file2.yaml"
        data-keyname = "file2.yml"
      }]
    },
    "cm2" = {
      name = "cm-name2"
      namespace = "default"
      cm-files = [{
        url = "someurl.com/file3.yaml"
        data-keyname = "file3.yml"
      },
      {
        url = "someurl.com/file4.yaml"
        data-keyname = "file4.yml"
      }]
    }
  }
}

And after this change, I don't know how to iterate through the nested list of objects cm-files to create configmap with multiple key-value pairs in data field. Any help or pointers would be much appreciated!

Upvotes: 2

Views: 3148

Answers (1)

Tyler
Tyler

Reputation: 501

You'll be doing quite a bit with nested for loops in this one. Here's what I was able to come up with given your variable constraints.

  • Update your variables.tf to the desired state you have in your original question. This solution used that input as a requirement

  • Update your http resource to this. Note this will fail your initial terraform plan because these are dummy urls and Terraform attempts to make a request as it builds this resource. A good way to test how the urls look is the sample locals {} block I also have in this snippet. This locals block isn't needed, but illustrates how the URLs are created.

data "http" "config-map" {
  for_each = toset(flatten([
    for cm in var.cloud-configmap : [
      for cm-file in cm.cm-files :
        cm-file.url
    ]
  ]))

  url = format("https://%s", each.key)

  request_headers = {
    Accept = "text/plain"
  }
}

# EXAMPLE showing how the URLs are created
locals {
  urls = toset(flatten([
    for cm in var.cloud-configmap : [
      for cm-file in cm.cm-files :
        format("https://%s", cm-file.url)
    ]
  ]))
}
output "urls" { value = local.urls }
  • Update your kubernetes_config_map resource to this:
resource "kubernetes_config_map" "configmap" {
  for_each = var.cloud-configmap

  metadata {
    name = each.value.name
    namespace = each.value.namespace
  }

  data = {
    for cm-file in each.value.cm-files :
      cm-file.url => cm-file.data-keyname
  }
}

Notice in each of these cases the use of for loops, and in the http case it's for_each being nested with for.

Upvotes: 2

Related Questions