使用 for_each 创建的资源中带有 for_each 的动态块

Posted

技术标签:

【中文标题】使用 for_each 创建的资源中带有 for_each 的动态块【英文标题】:Dynamic block with for_each inside a resource created with a for_each 【发布时间】:2020-01-13 09:34:04 【问题描述】:

我正在尝试使用 Terraform 0.12+ 及其新的 for_each 在 Azure 中构建多个 vnet,但遇到了一些麻烦。我希望新功能能够让我创建一个接收复杂变量的通用网络模块,但我可能已经达到了它的极限,或者只是没有正确地思考它。 基本上我的变量是像

variable "networks" 
  type = list(object( name = string, newbits = number, netnum = number, subnets = list(object( name = string, newbits = number, netnum = number))))

您可以看到它是一个网络数组,其中包含该网络的子网子数组。这样做可以轻松记录网络,而无需额外的 terraform 资源要求,因此我们的网络团队可以轻松调整/扩展,而无需担心了解 HCL。

我可以使用计数及其索引执行构建多个 vnet 资源的必要功能,但我想使用 for_each,因为它允许索引键而不是可能随时间变化的计数(需要重新部署我们做不到)。

网络对象

networks = [
    
        # x.x.1.0/24
        name        = "DMZ",
        newbits     = "8",
        netnum      = "1",
        subnets      = [
            
                # x.x.1.0/25
                name        = "DMZ"
                newbits     = "9",
                netnum      = "2"
            
        ]
    ,
    
        # x.x.33.0/24
        name        = "Intermediary"
        newbits     = "8",
        netnum      = "33",
        subnets          = [
            
                # x.x.33.0/25
                name        = "subnet1"
                newbits     = "9",
                netnum      = "66"
            ,
            
                # x.x.33.128/25
                name        = "subnet2"
                newbits     = "9",
                netnum      = "67"
            
        ]
    
]

我已经尝试并通过将对象更改为映射然后使用 each.key 和 each.value(为 each.value 执行 cidrsubnet)成功地使用 for_each 构建了 vnet,但问题在于制作子网.

locals 
    vnets = 
        for vnet in var.networks:
        vnet.name => cidrsubnet(var.root_cidr, vnet.newbits, vnet.netnum)
    

由于地图不包括那些子网,我只是把头撞在墙上。 有没有人有什么建议?还是在我不需要的时候,我真的让它变得过于复杂?

有效的资源创建,但没有子网

resource "azurerm_virtual_network" "vnets" 
  for_each            = local.vnets
  name                = each.key
  address_space       = [each.value]
  location            = azurerm_resource_group.network.location
  resource_group_name = azurerm_resource_group.network.name

我希望我可以使用动态块,并可能过滤它以匹配网络资源中的 each.key。之后我也尝试过使用它自己的子网资源,但就是想不通。

这是我希望的全部资源

resource "azurerm_virtual_network" "vnets" 
  for_each            = local.vnets
  name                = "99999-Nucleus-$each.key"
  address_space       = [each.value]
  location            = azurerm_resource_group.network.location
  resource_group_name = azurerm_resource_group.network.name

  dynamic "subnet" 
      for_each = [for vnet in var.networks:
      [for s in vnet.subnets: 
      name   = s.name
      prefix = cidrsubnet(var.root_cidr, s.newbits, s.netnum)
    ] if var.networks.name == each.key]

    content 
      name           = subnet.value.name
      address_prefix = subnet.value.prefix
    
  

【问题讨论】:

【参考方案1】:

在这里构造这个中间local.vnets 映射使这个问题更难解决,因为它丢弃了这些对象中的所有其他信息,因此很难在resource "azurerm_virtual_network" "vnets" 块中使用其他信息。

相反,如果我们对原始var.networks 值使用重复,那么我们可以直接从each.value 内部获得subnets 列表:

resource "azurerm_virtual_network" "vnets" 
  for_each =  for n in var.networks : n.name => n 

  location            = azurerm_resource_group.network.location
  resource_group_name = azurerm_resource_group.network.name

  name = "99999-Nucleus-$each.key"
  address_space = [cidrsubnet(var.root_cidr, each.value.newbits, each.value.netnum)]

  dynamic "subnet" 
    for_each = each.value.subnets
    content 
      name           = subnet.value.name
      address_prefix = cidrsubnet(var.root_cidr, subnet.value.newbits, subnet.value.netnum)
    
  

【讨论】:

太棒了!谢谢你...完全有效,我可以看到我的大脑在哪里无法运作。

以上是关于使用 for_each 创建的资源中带有 for_each 的动态块的主要内容,如果未能解决你的问题,请参考以下文章

如何导入具有由 for_each 创建的特殊字符的资源

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

Terraform : for_each 一个一个

将 aws 资源导入具有 for_each 的 terraform 模块

使用 for_each 创建不同数量的具有唯一 NIC 的 VM

for_each用法