I have a scaffolding module that I have created to auto-generate some of the files that we need across our environments and projects - it automatically creates the backend file, providers file and variables file.
I have this config that generates a variables file:
resource "local_file" "generated_variables" {
for_each = { for kv in local.distinct_envs_and_regions : "${kv.env}.${kv.region}" => kv }
content = <<EOF
variable "supported_regions" { default = ${jsonencode(distinct([
for region in var.regions :
"rg-${each.value.env}-${var.project}-${region.region_short} = ${region.region_name}"
]
))
} }
variable "region_info" { default = "${each.value.region}" }
variable "project" { default = "${var.project}" }
variable "environment" { default = "${each.value.env}" }
variable "tenant_id" { default = "${var.tenant_id}" }
variable "subscription_id" { default = "${var.subscription_id}" }
variable "common_tags" {
default = {
environment = "${each.value.env}"
project = "${var.project}"
managed_by = "terraform"
}
}
EOF
filename = "../${var.project}-iac/environments/category/${var.environment_category}/${each.value.env}/core/variables_generated.tf"
}
However, I cannot get the supported_regions variable in the format that I need - I need it to look something like this:
variable "supported_regions" {
default = {
rg-prd-adm-suk = "uksouth",
rg-prd-adm-wuk = "ukwest"
}
}
Instead the output looks something like this:
variable "supported_regions" { default = ["rg-prd-adm-suk = uksouth","rg-prd-adm-wuk = ukwest"] }
I am sure I am missing something in the for loop but cannot work out what that is... Any ideas?
EDIT A better solution using string templates
content = <<EOF
variable "supported_regions" {
default = {
%{ for region in var.regions ~}
rg-${each.value.env}-${var.project}-${region.region_short} = "${region.region_name}"
%{ endfor ~}
}
EOF
Output:
variable "supported_regions" {
default = {
rg-dev-prd-adm-suk = "uksouth"
rg-dev-prd-adm-wuk = "ukwest"
}
}
Full working main.tf
:
# providers
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "2.4.0"
}
}
}
locals {
distinct_envs_and_regions = [
{
env = "dev",
region = "us-east-1",
},
{
env = "dev",
region = "us-west-2",
},
{
env = "prod",
region = "us-west-2",
},
{
env = "test",
region = "us-east-1",
},
# Add more environments and regions as needed
]
}
resource "local_file" "generated_variables" {
for_each = {
for kv in local.distinct_envs_and_regions: "${kv.env}.${kv.region}" => kv
}
content = <<EOF
variable "supported_regions" {
default = {
%{ for region in var.regions ~}
rg-${each.value.env}-${var.project}-${region.region_short} = "${region.region_name}"
%{ endfor ~}
}
EOF
filename = "variables_generated.tf"
}
variable "project" {
default = "prd-adm"
}
variable "regions" {
type = list(object({
env = string
region_short = string
region_name = string
}))
default = [
{
env = "dev"
region_short = "suk"
region_name = "uksouth"
},
{
env = "dev"
region_short = "wuk"
region_name = "ukwest"
}
]
}
This should also do it (note that I had to substitute "=" to ":" in the output of jsonencode
(which is a string):
content = <<EOF
variable "supported_regions" {
default = ${
replace(
jsonencode({
for region in var.regions :
"rg-${each.value.env}-${var.project}-${region.region_short}" => region.region_name
}),
":", "="
)
}
}
EOF
Output:
variable "supported_regions" {
default = {"rg-prod-prd-adm-suk"="uksouth","rg-prod-prd-adm-wuk"="ukwest"}
}