如何迭代使用for_each声明的Terraform模块实例输出?
for_each模块输出创建AWS Glue爬虫 我需要基于用for_each声明的S3桶模块实例,创建对应的AWS Glue爬虫和数据目录数据库。尝试了几种for_each写法都报错,比如:
写法1:
for_each = {for key, value in setproduct(local.bucket-names, module.crawler_source_buckets.id): key=>value}
报错:
Error: Invalid function argument
on catalog.tf line 11, in resource "aws_glue_crawler" "bucket_crawlers":
11: for_each = {for key, value in setproduct(local.bucket-names, module.crawler_source_buckets.id): key=>value}
├────────────────
│ while calling setproduct(sets...)
│ module.crawler_source_buckets.id is a objectInvalid value for "sets" parameter: a set or a list is required.
写法2:
for_each = {for key, value in setproduct(local.bucket-names, module.crawler_source_buckets.*.id): key=>value}
写法3:
for_each = {for key, value in setproduct(local.bucket-names, module.crawler_source_buckets.[*].id): key=>value}
其中一种报错:
Error: Invalid template interpolation value
on catalog.tf line 14, in resource "aws_glue_crawler" "bucket_crawlers":
14: path = "s3://${each.value[1]}"
├────────────────
│ each.value[1] is object with 2 attributesCannot include the given value in a string template: string required.
错误原因
用for_each实例化的模块,module.crawler_source_buckets本质是一个映射(Map),键是local.bucket-names里的桶名,值是每个模块实例的输出对象。之前的写法错误在于:
- 直接访问
module.crawler_source_buckets.id会返回一个键值对Map,而非setproduct所需的列表/集合 *.id和.[*].id是针对count创建资源的语法,不适用于for_each创建的模块- 用
setproduct会生成桶名和桶ID的笛卡尔积,完全没必要(每个桶名对应唯一桶ID),反而会导致资源重复或类型错误
正确实现方案
因为模块实例的键就是桶名,直接遍历module.crawler_source_buckets即可,无需额外的setproduct或列表转换:
修改后的catalog.tf
resource "aws_glue_catalog_database" "catalog_databases" { for_each = module.crawler_source_buckets name = each.key } resource "aws_glue_crawler" "bucket_crawlers" { for_each = module.crawler_source_buckets database_name = each.key name = "${each.key}-crawler" role = aws_iam_role.glue_crawler_role.arn s3_target { path = "s3://${each.value.id}" } schedule = "cron(*/15 * * * ? *)" }
关键说明
each.key:对应模块实例的键,也就是桶名,直接用来作为数据库名和爬虫名称的前缀each.value.id:对应每个模块实例输出的桶ID(即桶名),直接拼接成S3路径- 这种写法完全对齐模块的实例数量,自动同步桶的增删,无需维护额外的列表
补充:如果需要提取模块输出的列表
如果确实需要把模块的输出转换成列表(比如其他场景),可以用values()函数:
# 获取所有桶ID的列表 locals { bucket_ids = [for bucket in values(module.crawler_source_buckets) : bucket.id] }
内容的提问来源于stack exchange,提问作者AlexLordThorsen

