我正在尝试在 terraform 中使用嵌套循环。我有两个列表变量list_of_allowed_accounts
和list_of_images
,并希望迭代列表list_of_images
,然后迭代列表list_of_allowed_accounts
。
这是我的地形代码。
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}"
}
这和我正在尝试做的事情是同一个 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
答案1
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]}"
}
由于我们想要为账户和图片的每种组合创建一个策略模板,因此数据块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"
每个策略实例适用于不同的账户 ID 和图像对,涵盖所有组合。
答案2
这里的答案确实有效(我最初使用它们),但我认为我有一个更好的解决方案,使用 Terraform 的设置产品函数。我在网上没有看到很多使用它的例子,但 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"] }
}
这将创建名为的 SSM 参数:
/outer1/inner1
/outer1/inner2
/outer1/inner3
/outer2/inner1
/outer2/inner2
/outer2/inner3
我那小小的大脑可以比其他答案中的模魔法更容易地解析这一点!
答案3
仅供参考,如果有人从 Google 来到这里,如果您使用的是 terraform 0.12,那么您将需要在进行划分的任何地方使用 floor 函数,否则您将收到有关部分索引的错误。
account_id = var.允许的账户列表[地面(计数索引/长度(var.list_of_images))]
答案4
基本上,问题出在数据“template_file”中,account_id 无法按您认为的方式设置,因为您的情况下的计数只是另一个永远不会增加/更改的变量。只是说说而已,因为我不明白您的问题到底是什么。