使用 terraform 在 for_each 嵌套资源中循环

Posted

技术标签:

【中文标题】使用 terraform 在 for_each 嵌套资源中循环【英文标题】:Looping in for_each nested resources with terraform 【发布时间】:2021-10-06 13:19:16 【问题描述】:

我正在尝试使用多个订阅预配多个 Azure 服务总线主题。我可以创建主题,但无法循环订阅变量来创建订阅。

################

locals 
  servicebus = 
    "topic_1" = [
      subscription = ["subscription1", "subscription2", "subscription3"]
    ],
    "topic_2" = [
      subscription = ["subscription4", "subscription5", "subscription6"]
    ],
 "topic_3" = [
      subscription = ["subscription7", "subscription8", "subscription9"]
    ]
  

service_bus = flatten([
    for topicname, topic in local.servicebus : [
      for subname in topic : 
        name                = topicname
        subscription_name  = subname.subscription
      
    ]
  ])

在 servicebus_subscription 资源块中,无法循环订阅名称,但是当我提供 index(each.value.subscription_name[0]) 时,它只创建一个订阅

############  Creating Servicebus Topic ############################### 
module "servicebus_topic" 
  source                = "./servicebus/topic"
 for_each = 
    for sname in local.service_bus : sname.name => sname
    
  name                = each.key
  resource_group_name   = azurerm_resource_group.rg.name
  namespace_name        = module.servicebus_namespace.name
  max_size_in_megabytes = "1024"
  depends_on            = [module.servicebus_namespace.name]


##########  Creating Servicebus Subscription ############################### 
resource "azurerm_servicebus_subscription" "sbs"   
  for_each = 
    for sname in local.service_bus : sname.name => sname
    
  name                = each.value.subscription_name
  topic_name          = module.servicebus_topic[each.value.name].name
  namespace_name      = module.servicebus_namespace.name
  resource_group_name = azurerm_resource_group.rg.name
  max_delivery_count  = "10"

错误:

Error: Incorrect attribute value type
│
│   on servicebus.tf line 77, in resource "azurerm_servicebus_subscription" "sbs":
│   77:   name                = each.value.subscription_name
│     ├────────────────
│     │ each.value.subscription_name is tuple with 3 elements
│
│ Inappropriate value for attribute "name": string required.
╵
╷
│ Error: Incorrect attribute value type
│
│   on servicebus.tf line 77, in resource "azurerm_servicebus_subscription" "sbs":
│   77:   name                = each.value.subscription_name
│     ├────────────────
│     │ each.value.subscription_name is tuple with 3 elements
│
│ Inappropriate value for attribute "name": string required.

使用 Terraform 控制台的局部变量调试输出:

> local.service_bus
[
  
    "name" = "topic_1"
    "subscription_name" = [
      "subscription1",
      "subscription2",
      "subscription3",
    ]
  ,
  
    "name" = "topic_2"
    "subscription_name" = [
      "subscription4",
      "subscription5",
      "subscription16",
    ]
  ,
]

【问题讨论】:

【参考方案1】:

你们很亲密。应该是:

service_bus = merge([
    for topicname, topic in local.servicebus : 
      for subname in topic[0].subscription :
          "$topicname-$subname" => 
            name               = topicname
            subscription_name  =  subname
          
    
  ]...)

然后

resource "azurerm_servicebus_subscription" "sbs"   
  
  for_each = local.service_bus
  
  name                = each.value.subscription_name
  topic_name          = module.servicebus_topic[each.value.name].name
  namespace_name      = module.servicebus_namespace.name
  resource_group_name = azurerm_resource_group.rg.name
  max_delivery_count  = "10"

【讨论】:

导致错误,详细信息如下:Error: Invalid index │ │ on servicebus.tf line 85, in resource "azurerm_servicebus_subscription" "sbs": │ 85: topic_name = module.servicebus_topic[each.value.name].name │ │ │ each.value.name is "topic_1" │ │ module.servicebus_topic is object with 6 attributes │ │ The given key does not identify an element in this collection value. 导致错误 @sreeram 你确定你听懂了我的回答还是你的问题完全代表了你的真实代码?【参考方案2】:

我已经根据 Marcin 的代码创建了一个完整的工作示例:


locals 
  servicebus = 
    "topic1" = [
      subscription = ["sub1", "sub2"]
    ],
    "topic2" = [
      subscription = ["sub1"]
    ]
  

service_bus = merge([
    for topicname, topic in local.servicebus : 
      for subname in topic[0].subscription :
          "$topicname-$subname" => 
            name               = topicname
            subscription_name  =  subname
          
    
   ]...)


resource "azurerm_servicebus_topic" "topic" 
  depends_on = [
    module.servicebus
   ]

for_each = local.service_bus

  name                = each.value.name
  resource_group_name = azurerm_resource_group.shared.name
  namespace_name      = module.servicebus.namespace_name
  enable_partitioning = false
  max_size_in_megabytes = 1024


resource "azurerm_servicebus_subscription" "subscription"   
  for_each = local.service_bus
   
  name                = each.value.subscription_name
  topic_name          = each.value.name
  namespace_name      = module.servicebus.namespace_name
  resource_group_name = azurerm_resource_group.shared.name
  max_delivery_count  = "10"

唯一的小问题是如果没有订阅,它不会创建主题。我有一些主题就是这种情况。

【讨论】:

以上是关于使用 terraform 在 for_each 嵌套资源中循环的主要内容,如果未能解决你的问题,请参考以下文章

如何在 terraform 中正确使用 for_each 中的 each.value?

具有下游依赖项的 Terraform 条件“for_each”

Terraform 因 for_each 参数无效/给定的“for_each”参数值不合适而失败

Terraform For_Each:如何引用创建的资源 ID

Terraform for_each - each.key 在哪里定义?

Terraform 模块输出用作其他模块中的输入,特别是 for_each