首页 > 解决方案 > Terraform for_each 用于地图内的地图

问题描述

我想知道是否可以使用 for_each/for 的组合来迭代这样的结构

module "network" {
  source    = "../../"
  role                = "test"
  resource_group_name = xyz
  location            = "centralus"
  environment         = "test-1"
  tags = {
    role = "unit-test"
  }
  subnets = {
    subnet-1 = {
      name              = "subnet-a"
      cidr              = "10.0.1.0/24",
      nsg = {
        httpallowinbound = {
          name = "junk"
        }
      }
    }
  }
}

我可以在外部结构上执行 for_each 来获取值并将它们分配给相应的字段,但不能为上面的嵌套结构做。感谢到目前为止的任何反馈。到目前为止我所拥有的:

resource "azurerm_subnet" "this" {
  for_each             = var.subnets
  name                 = lookup(each.value, "name")
  resource_group_name  = var.resource_group_name
  virtual_network_name = azurerm_virtual_network.this.name
  address_prefix       = lookup(each.value, "cidr"
}

对这件作品没有想法

resource "azurerm_network_security_group" "this" {
   Map NSGs to Subnets 
}

----------------------更新-1-------------- --------------------

根据到目前为止的发现,flatten 函数应该提供这种机制,如此处所述

但是,我无法使该示例也正常工作:

主文件

variable "networks" {
  type = map(object({
    cidr_block = string
    subnets = map(object({
      cidr_block = string
    })) # this is missing in the document
  })) # this is missing in the document
}

locals {
  # flatten ensures that this local value is a flat list of objects, rather
  # than a list of lists of objects.
  network_subnets = flatten([
    for network_key, network in var.networks : [
      for subnet_key, subnet in network.subnets : {
        network_key = network_key
        subnet_key  = subnet_key
        #network_id  = aws_vpc.example[network_key].id
        cidr_block  = subnet.cidr_block
      }
    ]
  ])
}

resource "null_resource" "dynamic_self" {
  for_each = {
    for subnet in local.network_subnets : "${subnet.network_key}.${subnet.subnet_key}" => subnet
  }

  provisioner "local-exec" {
    command = "echo ${local.network_subnets}"
  }
}

*.tfvars

networks = {
    network-1 = {
      cidr_block = "10.0.0.0/16"
      subnets = {
        subnet-1 = {
          cidr_block = "10.0.0.0/24"
        }
      }
    }
}

这失败并出现错误:错误:无效的模板插值:无法在字符串模板中包含给定值:需要字符串。

--------------------更新-2--------------- --------------

看起来 flatten 是这个用例的正确功能,我已经在车道上移动得更远了,但最后一个阶段仍然没有工作。我现在拥有的:

值.tfvars

  subnets = {
    inbound-subnet = {
      name              = "subnet-a"
      cidr              = "10.0.1.0/24",
      nsgs = {
        nsg1 = {
            httpallowinbound = {
              name                       = "httpallow"
              priority                   = 100
              direction                  = "Inbound"
              access                     = "Allow"
              protocol                   = "Tcp"
              source_port_range          = "*"
              destination_port_range     = "*"
              source_address_prefix      = "*"
              destination_address_prefix = "*"
            },
            httpdenyinbound = {
              name                       = "httpdeny"
              priority                   = 101
              direction                  = "Inbound"
              access                     = "Deny"
              protocol                   = "Tcp"
              source_port_range          = "*"
              destination_port_range     = "*"
              source_address_prefix      = "*"
              destination_address_prefix = "*"
           },
        },
      }
    }
  }
}

当地人

nsgs = flatten([
    for subnets_name, subnets_values in var.subnets : [
      for nsg_name, nsg_values in subnets_values.nsgs : [
        for rule_name, rule_values in nsg_values: {
          nsg_name                   = nsg_name
          rule                       = rule_name
          name                       = rule_values.name
          priority                   = rule_values.priority
          direction                  = rule_values.direction
          access                     = rule_values.access
          protocol                   = rule_values.protocol
          source_port_range          = rule_values.source_port_range
          destination_port_range     = rule_values.destination_port_range
          source_address_prefix      = rule_values.source_address_prefix
          destination_address_prefix = rule_values.destination_address_prefix
       }
      ]
    ]
  ])
}

主文件

resource "azurerm_subnet" "this" {
  for_each             = var.subnets
  name                 = lookup(each.value, "name")
  resource_group_name  = var.resource_group_name
  virtual_network_name = azurerm_virtual_network.this.name
  address_prefix       = lookup(each.value, "cidr")
}


resource "azurerm_network_security_group" "this" {
  for_each = {
      for sg in local.nsg_name:
        "${sg.nsg_name}" => sg
  }
  name                 = each.value.nsg_name
  location             = var.location
  resource_group_name  = var.resource_group_name
}


resource "azurerm_network_security_rule" "this" {
  for_each = {
      for sg in local.nsgs:
        //"${sg.rule}.${sg.name}" => sg
        sg.nsg_name => sg...
  }
  name                        = each.value.name
  priority                    = each.value.priority
  direction                   = each.value.direction
  access                      = each.value.access
  protocol                    = each.value.protocol
  source_port_range           = each.value.source_port_range
  destination_port_range      = each.value.destination_port_range
  source_address_prefix       = each.value.source_address_prefix
  destination_address_prefix  = each.value.destination_address_prefix
  resource_group_name         = var.resource_group_name
  network_security_group_name = azurerm_network_security_group.this[tostring(each.key)]
}

但我不断收到此错误:

错误:属性值类型不正确

在 ../../vnet.tf 第 55 行,在资源“azurerm_network_security_rule”“this”中:55:network_security_group_name = azurerm_network_security_group.this[tostring(each.value.nsg_name)] |---------- ------

| azurerm_network_security_group.this is object with 1 attribute "nsg1"
| each.value.nsg_name is "nsg1"

属性“network_security_group_name”的值不合适:需要字符串。

Error: Incorrect attribute value type

  on ../../vnet.tf line 55, in resource "azurerm_network_security_rule" "this":
  55:   network_security_group_name = azurerm_network_security_group.this[tostring(each.value.nsg_name)]
    |----------------
    | azurerm_network_security_group.this is object with 1 attribute "nsg1"
    | each.value.nsg_name is "nsg1"

我确信我错过了一些微小的东西,因为它看起来是可行的。任何指针都会有帮助

标签: foreachterraform

解决方案


推荐阅读