Terraform - 使用带计数的嵌套循环

vik*_*027 23 count terraform

我正在尝试在 terraform 中使用嵌套循环。我有两个列表变量list_of_allowed_accountsand list_of_images,并希望遍历 list list_of_images,然后遍历 list list_of_allowed_accounts

这是我的 terraform 代码。

variable "list_of_allowed_accounts" {
  type    = "list"
  default = ["111111111", "2222222"]
}

variable "list_of_images" {
  type    = "list"
  default = ["alpine", "java", "jenkins"]
}

data "template_file" "ecr_policy_allowed_accounts" {
  template = "${file("${path.module}/ecr_policy.tpl")}"

  vars {
    count = "${length(var.list_of_allowed_accounts)}"
    account_id = "${element(var.list_of_allowed_accounts, count.index)}"
  }
}

resource "aws_ecr_repository_policy" "repo_policy_allowed_accounts" {
  count = "${length(var.list_of_images)}"
  repository = "${element(aws_ecr_repository.images.*.id, count.index)}"
  count = "${length(var.list_of_allowed_accounts)}"
  policy = "${data.template_file.ecr_policy_allowed_accounts.rendered}"
}
Run Code Online (Sandbox Code Playgroud)

这相当于我正在尝试做的 bash。

for image in alpine java jenkins
do 
  for account_id in 111111111 2222222
  do 
    // call template here using variable 'account_id' and 'image'
  done
done
Run Code Online (Sandbox Code Playgroud)

Mar*_*ins 41

Terraform 不直接支持这种嵌套迭代,但我们可以用一些算术来伪造它。

variable "list_of_allowed_accounts" {
  type = "list"
  default = ["1111", "2222"]
}

variable "list_of_images" {
  type = "list"
  default = ["alpine", "java", "jenkins"]
}

data "template_file" "ecr_policy_allowed_accounts" {
  count = "${length(var.list_of_allowed_accounts) * length(var.list_of_images)}"

  template = "${file("${path.module}/ecr_policy.tpl")}"

  vars {
    account_id = "${var.list_of_allowed_accounts[count.index / length(var.list_of_images)]}"
    image      = "${var.list_of_images[count.index % length(var.list_of_images)]}"
  }
}

resource "aws_ecr_repository_policy" "repo_policy_allowed_accounts" {
  count = "${data.template_file.ecr_policy_allowed_accounts.count}"

  repository = "${var.list_of_images[count.index % length(var.list_of_images)]}"
  policy = "${data.template_file.ecr_policy_allowed_accounts.*.rendered[count.index]}"
}
Run Code Online (Sandbox Code Playgroud)

由于我们要为帐户和图像的每个组合创建一个策略模板,count因此template_file数据块上的两者相乘。然后,我们可以使用除法和模运算count.index将单独的索引返回到每个列表中。

因为我没有你的策略模板的副本,所以我只使用了一个占位符;因此,此配置给出了以下计划:

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.0
    policy:     "policy allowing 1111 to access alpine"
    repository: "alpine"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.1
    policy:     "policy allowing 1111 to access java"
    repository: "java"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.2
    policy:     "policy allowing 1111 to access jenkins"
    repository: "jenkins"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.3
    policy:     "policy allowing 2222 to access alpine"
    repository: "alpine"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.4
    policy:     "policy allowing 2222 to access java"
    repository: "java"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.5
    policy:     "policy allowing 2222 to access jenkins"
    repository: "jenkins"
Run Code Online (Sandbox Code Playgroud)

每个策略实例适用于不同的帐户 ID 和图像对,涵盖所有组合。

  • @justin-grote 在他的回答中有一个观点:在 terraform 0.12 中,您需要在除法的任何地方使用 floor 函数,否则您将收到有关部分索引的错误。`account_id = var.list_of_allowed_accounts[floor(count.index / length(var.list_of_images))]` (3认同)
  • 如果您想扩展配置(例如添加新帐户或/和图像),这会给您带来麻烦,而不是您的资源将映射到不同的索引,但是如果删除和重新创建它们不是问题,这可以正常工作。 (2认同)

小智 9

这里的答案确实有效(我最初使用它们),但我认为使用 Terraform 的setproduct函数有更好的解决方案。我还没有在互联网上看到很多使用它的例子,但是 setproduct 需要两个集合(或者更重要的是两个列表)并生成一个带有每个输入排列的集合列表。就我而言,我正在创建 SSM 参数:

variable "list1" {
  type    = "list"
  default = ["outer1", "outer2"]
}

variable "list2" {
  type    = "list"
  default = ["inner1", "inner2", "inner3"]
}

locals {
  product = "${setproduct(var.list1, var.list2)}"
}

resource "aws_ssm_parameter" "params" {
  count     = "${length(var.list1) * length(var.list2)}"
  name      = "/${element(local.product, count.index)[0]}/${element(local.product, count.index)[1]}"
  type      = "String"
  value     = "somevalue"
  overwrite = false
  lifecycle { ignore_changes = ["value"] }
}
Run Code Online (Sandbox Code Playgroud)

这将创建名为的 SSM 参数:

/outer1/inner1
/outer1/inner2
/outer1/inner3
/outer2/inner1
/outer2/inner2
/outer2/inner3
Run Code Online (Sandbox Code Playgroud)

我那懦弱的小脑袋比其他答案中的模魔法更容易解析这个!


小智 7

仅供参考,如果有人从 Google 来到这里,如果您使用 terraform 0.12,则需要在进行除法的任何地方使用 floor 函数,否则您将收到有关部分索引的错误。

account_id = var.list_of_allowed_accounts[ floor (count.index / length(var.list_of_images))]