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!
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 }
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.