【问题标题】:Terraform loops地形循环
【发布时间】:2020-05-25 01:37:26
【问题描述】:

我目前正在编写一些将 Azure 私有 DNS 区域部署到 Azure 中的 Terraform 代码。

我已使用以下代码成功部署了 DNS 区域:

dns_zones = [
"domain1.com",
"domain2.com",
"domain3.com",
]

resource "azurerm_private_dns_zone" "dns_zones" {
  for_each = toset(var.dns_zones)

  name                = each.value
  resource_group_name = var.resource_group
}

我的问题是配置区域和虚拟网络之间的链接。我需要遍历 dns_zones 列表并有一个嵌套循环,然后遍历 vnet_links 列表并配置区域上的 vnet 链接。

以下解决方案有效,但它不是很健壮,因为从任一列表中删除配置都会打乱列表的索引号,导致 Terraform 删除并重新创建配置,这不是一个选项:

vnet_links = [
    {
    "linkName": "name-of-vnet-link1"
    "vnetId": "vnet--resource-id-placeholder1"
    },{
    "linkName": "name-of-vnet-link2"
    "vnetId": "vnet--resource-id-placeholder2"
    }
]

resource "azurerm_private_dns_zone_virtual_network_link" "vnet_link" {
  count              = length(setproduct(var.dns_zones, var.vnet_links))

  name                  = element(setproduct(var.dns_zones, var.vnet_links)[count.index], 1).linkName
  resource_group_name   = var.resource_group
  private_dns_zone_name = element(setproduct(var.dns_zones, var.vnet_links)[count.index], 0)
  virtual_network_id    = element(setproduct(var.dns_zones, var.vnet_links)[count.index], 1).vnetId
}

我发现使用下面的 setproduct() 函数可以创建一个包含我想要使用的数据的新列表,我打算将它与 for_each 一起使用而不是计数,但不可能使用this 与 toset() 函数一起使用,因为它只接受字符串列表。

setproduct(var.dns_zones, var.vnet_links)

现在我有点不知道该去哪里。我可以在 vnet_links 列表中包含区域信息,但这需要我想避免的大量重复。理想情况下,我希望能够找到一个不需要对 dns_zones 列表进行任何更改的解决方案,并保留一个包含 vnet 链接的单独列表。

谢谢!

编辑:

感谢 Charles 提供了一种格式化数据的方法。除了 Charles 响应之外,我还需要在 for_each 循环中创建一个动态映射来使用数据。最终解决方案如下:

dns_zones = [
"domain1.com",
"domain2.com",
"domain3.com",
]

vnet_links = [
    {
    "linkName": "name-of-vnet-link1"
    "vnetId": "vnet--resource-id-placeholder1"
    },{
    "linkName": "name-of-vnet-link2"
    "vnetId": "vnet--resource-id-placeholder2"
    }
]

locals {
  association = flatten([
    for dns_zone in var.dns_zones: [
      for link in var.vnet_links: {
        zone = dns_zone
        vnet_link = link
      }
    ]
  ])
}

resource "azurerm_private_dns_zone_virtual_network_link" "vnet_link" {
  for_each              = { for row in local.association:
    "${row.zone}_${row.vnet_link.linkName}" => {
      zone = row.zone
      linkName = row.vnet_link.linkName
      vnetId = row.vnet_link.vnetId
    }
  }

  name                  = each.value.linkName
  resource_group_name   = var.resource_group
  private_dns_zone_name = each.value.zone
  virtual_network_id    = each.value.vnetId
}

【问题讨论】:

    标签: azure loops terraform


    【解决方案1】:

    根据您的要求,我认为 for 循环适合您,我假设您希望将区域信息和 Vnet 链接关联成这种格式:

      {
        "vnet_link" = {
        "linkName": "name-of-vnet-link1"
        "vnetId": "vnet--resource-id-placeholder1"
        }
        "zone" = "domain1.com"
      }
    

    然后您可以使用 for 循环将所有可能的关联放入如下列表中:

    variable "dns_zones" {
      default = [
        "domain1.com",
        "domain2.com",
        "domain3.com",
      ]
    }
    
    variable "vnet_links" {
      default = [
        {
        "linkName": "name-of-vnet-link1"
        "vnetId": "vnet--resource-id-placeholder1"
        },
        {
        "linkName": "name-of-vnet-link2"
        "vnetId": "vnet--resource-id-placeholder2"
        }
      ]
    }
    
    locals {
      association = flatten([
        for dns_zone in var.dns_zones: [
          for link in var.vnet_links: {
            zone = dns_zone
            vnet_link = link
          }
        ]
      ])
    }
    
    output "association" {
      value = local.association
    }
    

    最后,输出会是这样的:

    如果还有其他问题,请告诉我。希望这是您想要的解决方案。

    【讨论】:

    • 谢谢查尔斯,这很有帮助。我已经编辑了我的初始帖子以包含最终解决方案。
    • @Gaz 太好了!
    猜你喜欢
    • 2020-09-27
    • 2022-01-19
    • 2020-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-15
    相关资源
    最近更新 更多