Terragrunt generate块for_each配置字符串插值报错求助
Terragrunt Generate块结合for_each批量调用模块的问题解决
问题场景
尝试使用Terragrunt的generate块,结合for_each根据Terragrunt本地变量local.s3中的条目批量调用S3模块,但配置报错,关键代码如下:
locals { s3 = { "companies-data-service" = { enable_cloudfront = true cloudfront_allowed_paths = ["logos/*"] cors_rules = { "local" = { methods = ["POST", "HEAD", "PUT", "GET"] origins = ["http://localhost:*", "https://*.test.io"] } } } } } generate "cdn" { path = "cdn.tf" if_exists = "overwrite" contents = <<EOF module "cdn" { source = "git::git@github.com:my-org/terraform-modules.git//s3?ref=v0.0.21" for_each = { for $${k}, $${v} in "${local.s3}" : $${k} => $${v} } name = "${local.s3}" != {} ? $${each.value} : "" // 其他配置项... } EOF }
运行后报错:
local.s3 as object with 1 attribute "companies-data-service" ERRO[0010] Cannot include the given value in a string template: string required. ERRO[0010] Error: Invalid template interpolation value
测试发现,若将local.s3直接写在生成的Terraform代码内(而非通过Terragrunt变量传递),配置可正常运行,问题出在Terragrunt向generate块传递变量的方式上。
错误原因
- 对象转字符串的错误插值:在
for_each中使用"${local.s3}"尝试将Terragrunt的对象类型变量local.s3插入字符串模板,但Terragrunt无法将对象直接转换为合法的字符串,导致类型错误。 - 错误的条件判断与属性引用:
"${local.s3}" != {}是将对象转为字符串后和空对象比较,逻辑不成立;同时$${each.value}是整个对象,若name字段需要的是bucket名称(即local.s3的key),此处引用错误。
解决方案
- 使用Terragrunt的
hclencode函数,将Terragrunt的local.s3对象转换为合法的HCL格式字符串,注入到生成的Terraform代码中。 - 修正
for_each的写法,直接引用转换后的HCL对象,无需额外的字符串包裹。 - 修正
name字段的引用,根据实际需求使用$${each.key}(对应local.s3的键名)或$${each.value}中的具体属性。
修正后的代码示例
locals { s3 = { "companies-data-service" = { enable_cloudfront = true cloudfront_allowed_paths = ["logos/*"] cors_rules = { "local" = { methods = ["POST", "HEAD", "PUT", "GET"] origins = ["http://localhost:*", "https://*.test.io"] } } } # 可添加更多S3配置条目 "user-assets-service" = { enable_cloudfront = false cors_rules = { "prod" = { methods = ["GET"] origins = ["https://my-app.com"] } } } } } generate "cdn" { path = "cdn.tf" if_exists = "overwrite" contents = <<EOF module "cdn" { source = "git::git@github.com:my-org/terraform-modules.git//s3?ref=v0.0.21" for_each = ${hclencode(local.s3)} # 根据模块需求,此处用each.key作为bucket名称 name = $${each.key} enable_cloudfront = $${each.value.enable_cloudfront} cloudfront_allowed_paths = lookup($${each.value}, "cloudfront_allowed_paths", []) cors_rules = $${each.value.cors_rules} # 其他配置项... } EOF }
说明
hclencode(local.s3)会将Terragrunt的local.s3对象转换为Terraform可识别的HCL对象语法,确保for_each能正确遍历条目。- 使用
$${}转义Terraform的变量引用,避免被Terragrunt提前插值解析。 - 对于可选字段(如
cloudfront_allowed_paths),使用lookup函数处理默认值,避免因部分条目缺少该字段而报错。
内容的提问来源于stack exchange,提问作者Kaleby Cadorin
相关产品推荐
相关产品推荐

