【问题标题】:Iterate over nested data with for / for_each at resource level在资源级别使用 for / for_each 迭代嵌套数据
【发布时间】:2022-03-29 16:29:40
【问题描述】:

我正在尝试研究如何使用 Terraform 0.12.10 从以下 tfvars 文件中给出的复杂对象中迭代嵌套变量:

example.tfvars

virtual_network_data = {
  1 = {
    product_instance_id              = 1
    location                         = "somewhere"
    address_space                    = ["192.168.0.0/23"]
    dns_servers                      = []
    custom_tags                      = {"test":"test value"}
    subnets                          = [
      {
        purpose = "mgmt"
        newbits = 4
        item = 0
      },
      {
        purpose = "transit"
        newbits = 4
        item = 1
      }
    ]
  }
}

example.tf

variable "virtual_network_data" {} #Data comes from example.tfvars

variable "resource_group_name" {
    default = "my_resource_group"
}

variable "virtual_network_name" {
    default = "my_virtual_network"
}

####

resource "azurerm_subnet" "pool" {
    for_each             = var.virtual_network_data

    name                 = format("%s%s%02d", "subnet_", s.purpose, s.item)
    resource_group_name  = var.resource_group_name
    virtual_network_name = var.virtual_network_name
    address_prefix       = cidrsubnet(each.value["address_space"], s.newbits, s.item)

}

example.tf 中,我可以使用each.value["address_space"] 获取顶级变量,但我不知道如何获取subnets 中的项目(s.purposes.items.newbits )。

我使用了动态块,作为父资源的一部分(如下),它可以工作,但在这种情况下,我需要将子网移动到它自己的资源中。简单地说,如何让第一个 for_each 表现得像动态块中的第二个 for_each

resource "azurerm_virtual_network" "pool" {
  for_each                  = var.virtual_network_data

  name                      = format("%s%02d", local.resource_name, each.key)
  resource_group_name       = var.resource_group_name
  location                  = each.value["location"]
  address_space             = each.value["address_space"]
  dns_servers               = each.value["dns_servers"]
  tags                      = merge(local.tags, each.value["custom_tags"])

  dynamic "subnet" {
    for_each = [for s in each.value["subnets"]: {
      name   = format("%s%s%02d", "subnet_", s.purpose, s.item)
      prefix = cidrsubnet(element(each.value["address_space"],0), s.newbits, s.item)
    }]

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

厚颜无耻的奖金,有没有办法用each.keycount.index之类的东西替换s.item

TIA

【问题讨论】:

  • 我想我在某处读到嵌套迭代器在 Terraform 中还没有工作。

标签: terraform


【解决方案1】:

这种情况下的技术是使用其他 Terraform 语言功能将您的集合转换为适合 for_each 参数的形状:每个资源实例一个元素。

对于嵌套数据结构,您可以将flatten 与两个或多个for 表达式结合使用,以生成每个嵌套对象一个元素的平面数据结构:

locals {
  network_subnets = flatten([
    for network_key, network in var.virtual_network_data : [
      for subnet in network.subnets : {
        network_key       = network_key
        purpose           = subnet.purpose
        parent_cidr_block = network.address_space[0]
        newbits           = subnet.newbits
        item              = subnet.item
      }
    ]
  ])
}

那么你可以使用local.network_subnets作为重复的基础:

resource "azurerm_subnet" "pool" {
    # Each instance must have a unique key, so we'll construct one
    # by combining the network key, the subnet "purpose", and the "item".
    for_each = {
      for ns in local.network_subnets : "${ns.network_key}.${ns.purpose}${ns.item}" => ns
    }

    name                 = format("%s%s%02d", "subnet_", each.value.purpose, each.value.item)
    resource_group_name  = var.resource_group_name
    virtual_network_name = var.virtual_network_name
    address_prefix       = cidrsubnet(each.value.parent_cidr_block, each.value.newbits, each.value.item)
}

the flatten documentation 中有一个类似的例子,作为一些额外的上下文。

【讨论】:

  • 谢谢@Martin。工作一种享受。
【解决方案2】:

作为flatten技巧的替代方法,您可以在嵌套模块中通过第一个参数for_each资源,然后通过第二个参数for_each此模块。

【讨论】:

    猜你喜欢
    • 2021-12-14
    • 2021-10-06
    • 2021-07-21
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 2011-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多