【问题标题】:transforming / combining variables (maps) into locals in terraform将变量(地图)转换/组合成 terraform 中的本地变量
【发布时间】:2022-01-25 06:36:09
【问题描述】:

为了简化变量定义,我将子网和属性(如安全组)分组到一个字典列表中......然后有一层字典等......(或地图/对象)

这是一个示例定义 JSON:

"subnets": [
{
  "name": "inside",
  "prefix": "10.248.0.0/28",
  "route_table": true,
  "nsg": true,
  "security_group_rules": [
    {
      "name": "AllowAllInbound",
      "properties": {
        "priority": 100,
        "access": "Allow",
        "direction": "Inbound",
        "protocol": "*",
        "sourcePortRange": "*",
        "destinationPortRange": "*",
        "sourceAddressPrefix": "*",
        "destinationAddressPrefix": "*"
      }
    }
  ]
}

使用这个单个块,我希望能够通过循环运行以构建子网,然后使用不同的资源块构建安全组。我有各种各样的问题能够迭代这个。

我想我应该和当地人一起做点什么,这样我就可以为每个操作提取我需要的东西

在子网侧:

resource "azurerm_subnet" "subnet" {
  for_each = var.subnets
  name                 = each.value.name
  resource_group_name  = azurerm_resource_group.hub_network_rg.name
  virtual_network_name = azurerm_virtual_network.hub_vnet.name
  address_prefixes     = [each.value.prefix] 
}

由于变量类型的问题而无法工作:我将“子网”变量定义为:

variable "subnets" {
  type = list(object({
    name = string
    prefix = string
    route_table = bool
    nsg = bool
    security_group_rules = map(list(string))
  }))
}

我知道 TF 是松散类型的,但它不想遍历对象,因为它遇到了其他东西。

选项: 1.将其分解为单独的元素-我将再次遇到此问题,只是规模较小。 2. 找到一种方法来创建 s local.subnets 映射和一个引用我拥有的 var.subnets 的 local.security_groups 映射。

在 #2 上寻求帮助。

类似:

locals {
  subnets = for k,v in var.subnets: [
    {
      name = var.subnet.name
      prefix = var.subnet.prefix
    }

我离这里很远,但我认为这可以解决问题。我的大脑转向 Python 和列表/字典理解,但我可以弄清楚如何用 TF 做到这一点。我觉得它就在我面前,我只是无法拼凑语法。

【问题讨论】:

    标签: terraform


    【解决方案1】:

    Terraform for_each 仅接受字符串集或字符串映射。传递var 之类的列表根本行不通。我建议这样做:

    # Create a JSON like variable for your subnets. Notice, this variable is a list, the type of it is inferred, we don't need to complicate ourselves here
    variable "subnets" {
      default = [{
        "name" : "inside",
        "prefix" : "10.248.0.0/28",
        "route_table" : true,
        "nsg" : true,
        "security_group_rules" : [
          {
            "name" : "AllowAllInbound",
            "properties" : {
              "priority" : 100,
              "access" : "Allow",
              "direction" : "Inbound",
              "protocol" : "*",
              "sourcePortRange" : "*",
              "destinationPortRange" : "*",
              "sourceAddressPrefix" : "*",
              "destinationAddressPrefix" : "*"
            }
          }
        ]
      }]
    }
    
    # Create a local which maps the name of the the subnet to the subnet itself
    locals {
      subnet_map =  { for s in var.subnets: s.name => s }
    }
    
    # Create the resources
    resource "azurerm_subnet" "subnet" {
      for_each             = toset([
                                 for s in var.subnets: s.name
                             ]) # Note, we create a set from the subnet names. We can use these names to read out properties from the map created above
      name                 = each.value.name
      resource_group_name  = azurerm_resource_group.hub_network_rg.name
      virtual_network_name = azurerm_virtual_network.hub_vnet.name
      address_prefixes     = [local.subnet_map[each.value].prefix] # We use the subnet names here
    }
    
    

    更新:

    我们需要subnet_map的原因是必须有如下映射:

    subnet_map = {
      "inside" = {
        "name" = "inside"
        "nsg" = true
        "prefix" = "10.248.0.0/28"
        ...
      },
      # you have only one subnet as the input, but if you had more than one the map will contain it 
      "other_subnet" = {
      ... 
      }
    }
    

    本质上,我们希望将每个子网的name 映射到子网本身。正如我上面所说,我们需要这个的原因是,for_each 只接受字符串集。这个toset([for s in var.subnets: s.name]) 的值是一组子网名称,所以set("inside"),这意味着for_each 将遍历子网名称并为每个子网名称创建一个azurerm_subnet。显然,我们需要有关子网的更多信息,而不仅仅是它的名称。我们可以从subnet_map 获得我们需要的所有信息。这是因为如果我们提供子网的名称,我们可以从中获取对象。这正是这条语句的作用:local.subnet_map[each.value].prefix

    【讨论】:

    • 欣赏输入。试一试,但子网列表中的每个元素都收到以下错误:“无法访问原始类型值(字符串)的属性”
    • 我明白了。我从 each.value.name 中删除了属性“name”,因为它不需要,因为该集合只包含名称。所以看起来它有效
    • 您能否详细说明 subnet_map = { for s in var.subnets: s.name=> s } ?
    • 用更多信息更新了我的答案。
    • 感谢您的解释!那么这是否也适用于网络安全组?我正在努力将您在此处概述的内容扩展到提取驻留在同一数据集中的规则。
    猜你喜欢
    • 2020-10-13
    • 2021-07-20
    • 2021-05-16
    • 2021-07-17
    • 2021-12-09
    • 2018-10-23
    • 2021-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多