Terraform 获取 for_each 上的列表索引

问题描述 投票:0回答:6

这里是 Terraform 新手。 我想使用

for_each
迭代列表,但看起来键和值是相同的:

provider "aws" {
  profile = "default"
  region  = "us-east-1"
}

variable "vpc_cidrs" {
  default = ["10.0.0.0/16", "10.1.0.0/16"]
}

resource "aws_vpc" "vpc" {
  for_each             = toset(var.vpc_cidrs)
  cidr_block           = each.value
  enable_dns_hostnames = true
  tags                 = { Name = "Company0${each.key}" }
}

我希望标签名称为

"Name" = "Company01"
"Name" = "Company02"
但根据
terraform apply
,我得到:
"Name" = "Company010.0.0.0/16"
"Name" = "Company010.1.0.0/16"
我错过了什么?

terraform
6个回答
52
投票

使用 index 函数找到了一个简单的解决方案:

tags = { Name = "Company0${index(var.vpc_cidrs, each.value) + 1}" }

39
投票

还有另一种方法可以在不使用

index()
的情况下实现想要的结果:

更改以下三行:

for_each   = { for idx, cidr_block in var.vpc_cidrs: cidr_block => idx}
cidr_block = each.key
tags       = { Name = format("Company%02d", each.value + 1) }
  • for_each
    将使用由
    cidr_block
     返回的 
    index
    for
  • 映射的映射
  • 然后
    cidr_block
    就可以使用
    each.key
  • 并且在
    tags
    中还可以在
    format()
    上使用
    each.value
    来获得带有
    index
  • 的前导零的两位数

完整示例为:

provider "aws" {
  profile = "default"
  region  = "us-east-1"
}

variable "vpc_cidrs" {
  default = ["10.0.0.0/16", "10.1.0.0/16"]
}

resource "aws_vpc" "vpc" {
  for_each             = { for idx, cidr_block in var.vpc_cidrs: cidr_block => idx}
  cidr_block           = each.key
  enable_dns_hostnames = true
  tags                 = { Name = format("Company%02d", each.value + 1) }
}

15
投票

for_each
与套装一起使用时,
each.key
each.value
是相同的。

要生成“Company01”、“Company02”等字符串,您需要列表中每个 CIDR 块的索引。一种方法是使用

for
表达式 创建本地地图,例如:

locals {
  vpc_cidrs = {for s in var.vpc_cidrs: index(var.vpc_cidrs, s) => s}
}

resource "aws_vpc" "vpc" {
  for_each             = local.vpc_cidrs
  cidr_block           = each.value
  enable_dns_hostnames = true
  tags                 = { Name = "Company0${each.key}" }
}

作为奖励,您可以使用 format 函数来构建零填充的名称字符串:

resource "aws_vpc" "vpc" {
  ...
  tags                 = { Name = format("Company%02d", each.key) }
}

5
投票

您可以使用

count
函数并使用索引来执行此操作:

provider "aws" {
  profile = "default"
  region  = "us-east-1"
}

variable "vpc_cidrs" {
  type = list(string)
  default = ["10.0.0.0/16", "10.1.0.0/16"]
}

resource "aws_vpc" "vpc" {
  count = length(var.vpc_cidrs)
  cidr_block           = var.vpc_cidrs[count.index]
  enable_dns_hostnames = true
  tags                 = { Name = "Company0${count.index}" }
}

0
投票

foreach 中你可以使用这样的东西:

provider "aws" {
 profile = "default"
 region  = "us-east-1"
}

variable "vpc_cidrs" {
 default = ["10.0.0.0/16", "10.1.0.0/16"]
}

 resource "aws_vpc" "vpc" {
  for_each             = toset(var.vpc_cidrs)
  cidr_block           = each.value
  enable_dns_hostnames = true
  tags                 = { Name = "Company0${index(keys(var.vpc_cidrs), each.key)}" }
}

您可以通过以下方式获得钥匙:

keys(var.vpc_cidrs) 

然后你可以在钥匙中找到钥匙:

index(keys(var.vpc_cidrs), each.key)

-1
投票

其中一条评论询问如何在

动态块
中使用for_each时使用索引来实现此目的。

简短回答

可以参考

<name-of-dynamic-block>.key
key是索引)来完成。


一个例子

使用案例

我将采用一个用例,其中我有一个 S3 存储桶,其中包含多个文件夹,并且每个文件夹都有一个指向它的专用 Cloudfront 发行版。

我想要在 AWS 范围内得到什么

假设我在 s3 存储桶中有 2 个文件夹:name1name2

所以我必须创建一个如下所示的

aws_s3_bucket_policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "AWS": "<arn-of-cloudfront-distribution-1>"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::some-bucket/name1/*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "AWS": "<arn-of-cloudfront-distribution-2>"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::some-bucket/name2/*"
        }
    ]
}

(*) 为了简洁起见,删除了 Cloudfront 发行版的创建。

如何使用 Terraform 实现这一目标

因此,我有一个需要在 s3 存储桶中创建的文件夹列表:

variable "all_s3_folders" {
  type        = list(string)
  default     = []
  description = "All folders inside the bucket"
}

对于每个文件夹,我创建了一个 cloudfront 发行版(为简洁起见,已删除)和 cloudfront 原始访问身份(请参阅 oai)资源。

我们将根据文件夹数量的

count
创建这些资源:

resource "aws_cloudfront_origin_access_identity" "oai" {
  count = length(var.all_s3_folders)
  comment = "some-comment"
}

现在我们需要将每个文件夹(及其相关的 Cloudfront 发行版和 OAI)添加为存储桶策略中的条目。

我想使用其中包含

for_each
的动态块,但不依赖于
count.index

但我仍然需要使用索引迭代

aws_cloudfront_origin_access_identity
资源。

那么,

为了在动态块内使用

for_each
时使用索引,您只需引用
<name-of-dynamic-block>.key
- 这里是
statement.key

data "aws_iam_policy_document" "my-doc" {
  dynamic "statement" {
    for_each = var.folders_array
    content {
      effect = "Allow"

      actions = [
        "s3:GetObject"
      ]

      resources = [
        "${aws_s3_bucket.my_s3_bucket.arn}/${statement.value}/*" # <--Using statement value
      ]

      principals {
        type = "AWS"
        identifiers = [some_cloudfront_resource[statement.key].id] # <--Using statement key
      }
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.