繁体   English   中英

Terraform - 如何在对象列表上使用 for_each 循环来创建资源

[英]Terraform - how to use for_each loop on a list of objects to create resources

我有一个包含要创建的子网列表的对象。

variable "subnet-map" {
  default = {
    ec2 = [
      {
        cidr_block        = "10.0.1.0/24"
        availability_zone = "eu-west-1a"
      }
    ],
    lambda = [
      {
        cidr_block        = "10.0.5.0/24"
        availability_zone = "eu-west-1a"
      },
      {
        cidr_block        = "10.0.6.0/24"
        availability_zone = "eu-west-1b"
      },
      {
        cidr_block        = "10.0.7.0/24"
        availability_zone = "eu-west-1c"
      }
    ],
    secrets = [
      {
        cidr_block        = "10.0.8.0/24"
        availability_zone = "eu-west-1a"
      },
      {
        cidr_block        = "10.0.9.0/24"
        availability_zone = "eu-west-1b"
      },
      {
        cidr_block        = "10.0.10.0/24"
        availability_zone = "eu-west-1c"
      }
    ],
    rds = [
      {
        cidr_block        = "10.0.11.0/24"
        availability_zone = "eu-west-1a"
      },
      {
        cidr_block        = "10.0.12.0/24"
        availability_zone = "eu-west-1b"
      },
      {
        cidr_block        = "10.0.13.0/24"
        availability_zone = "eu-west-1c"
      }
    ]
  }
}

早些时候我使用了计数循环结构。 所以我曾经把上面的结构扁平化成一个对象列表

locals {
  subnets = flatten([
    for resource in keys(var.subnet-map) : [
      for subnet in var.subnet-map[resource] : {
        resource          = resource
        cidr_block        = subnet.cidr_block
        availability_zone = subnet.availability_zone
      }
    ]
  ])
}

然后我会通过做来创建资源

resource "aws_subnet" "aws-subnets" {
  count             = length(local.subnets)
  vpc_id            = aws_vpc.aws-vpc.id
  cidr_block        = local.subnets[count.index].cidr_block
  availability_zone = local.subnets[count.index].availability_zone

  tags = {
    Name = "subnet-${local.subnets[count.index].resource}-${local.subnets[count.index].availability_zone}"
  }
}

现在我想使用 for_each 循环。 但我不知道该怎么做。 这是我到目前为止所做的。

resource "aws_subnet" "subnets-dev" {
  for_each          = var.subnet-map
  vpc_id            = aws_vpc.vpc-dev.id
  cidr_block        = each.value.cidr_block
  availability_zone = each.value.availability_zone

  tags = {
    Name        = "subnet-dev-${each.value.resource}-${each.value.availability_zone}"
    environment = "dev"
  }
}

但它不断给出一个错误说

Error: Unsupported attribute

  on vpc/main.tf line 93, in resource "aws_subnet" "subnets-dev":
  93:     Name        = "subnet-dev-${each.value.resource}-${each.value.availability_zone}"
    |----------------
    | each.value is tuple with 3 elements

This value does not have any attributes.

我怎么能解决这个问题?

我不确定我是否完全遵循您在此处尝试的所有内容,因为var.subnet-map初始片段显示它是对象列表映射的映射,但是稍后当您使用for_each = var.subnet-map时似乎已将其视为列表映射。 在尝试for_each之前,您是否删除了额外的地图级别(“默认”键)?

使用您对variable "subnet-map"原始定义,您对for_each第一步将类似于您对count所做的:您需要将结构展平,这次是一个对象映射而不是对象列表。 到达那里的最简单方法是从现有的扁平化列表中获取地图:

locals {
  subnets = flatten([
    for resource in keys(var.subnet-map) : [
      for subnet in var.subnet-map[resource] : {
        resource          = resource
        cidr_block        = subnet.cidr_block
        availability_zone = subnet.availability_zone
      }
    ]
  ])

  subnets_map = {
    for s in local.subnets: "${s.resource}:${s.availability_zone}" => s
  }
}

在这里,我假设您的“资源”字符串和可用区一起是一个合适的子网唯一标识符。 如果没有,您可以将"${s.resource}:${s.availability_zone}"部分调整为您想要用于这些的任何唯一键。

现在你可以使用扁平化的地图作为for_each地图:

resource "aws_subnet" "subnets-dev" {
  for_each          = local.subnets_map
  vpc_id            = aws_vpc.vpc-dev.id
  cidr_block        = each.value.cidr_block
  availability_zone = each.value.availability_zone

  tags = {
    Name        = "subnet-dev-${each.value.resource}-${each.value.availability_zone}"
    environment = "dev"
  }
}

这将为您提供地址如aws_subnet.subnets-dev["ec2:eu-west-1a"]实例。


请注意,如果您要从count迁移到您希望保留的现有子网,您还需要执行一次性迁移步骤,以告诉 Terraform 现有状态中的哪些索引对应于新配置中的哪些键。

例如,如果(且仅当)索引0之前是eu-west-1a ec2索引,则该索引的迁移命令将是:

terraform state mv 'aws_subnet.subnets-dev[0]' 'aws_subnet.subnets-dev["ec2:eu-west-1a"]'

如果您不确定它们之间的关系,您可以在添加for_each后运行terraform plan并查看 Terraform 计划销毁的实例。 如果您依次处理其中的每一个,将 Terraform 当前知道的地址与Name标签中显示的资源和可用区名称一起使用,您可以将它们中的每一个迁移到其新地址,以便 Terraform 不再认为您重新要求它销毁编号的实例并用命名的实例替换它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM