在 Terraform 中构建动态列表?
Build dynamic list in Terraform?
我正在尝试使用 count 在 terraform 中动态创建一些 aws 资源,然后构建一个包含所有已创建资源 ID 列表的输出变量
resource "aws_subnet" "subnet-1" {
// If subnet_id value is supplied then we set count to 1 to create otherwise skip
count = "${replace(replace(var.primary_subnet_cidr, "/^.+/", "1"), "/^$/", "0")}"
tags = {
Name = "subnet-1"
}
cidr_block = "${var.primary_subnet_cidr}"
vpc_id = "${var.vpc_id}"
availability_zone = "${var.aws_region}a"
}
resource "aws_subnet" "subnet-2" {
// If subnet_id value is supplied then we set count to 1 to create otherwise skip
count = "${replace(replace(var.secondary_subnet_cidr, "/^.+/", "1"),"/^$/", "0")}"
tags = {
Name = "subnet-2"
}
cidr_block = "${var.secondary_subnet_cidr}"
vpc_id = "${var.vpc_id}"
availability_zone = "${var.aws_region}b"
}
output "ids" {
value = ["${aws_subnet.subnet-1.id}","${aws_subnet.subnet-2.id}"]
}
想法是通过提供其变量(primary_subnet_cidr 或 secondary_subnet_cidr)来仅创建您想要的子网。
动态创建它们工作正常,但我的问题是动态列表。
当试图在类似 aws_db_subnet_group.subnet_ids
的东西中使用这个列表时,它只在两个子网都已创建时才有效,否则它会抛出以下错误
InvalidSubnet: Subnet IDs are required.
这个我也试过了
output "ids" {
value = ["${aws_subnet.*.id}"]
}
但是 terraform 似乎不支持资源级别的通配符。
我怀疑这与我生成输出列表的方式有关。有没有更好的方法来生成该动态列表,使其仅包含创建的资源?
您很接近,但您需要使用 RESOURCE-TYPE.RESOURCE-NAME.PROPERTY_NAME
或 RESOURCE-TYPE.RESOURCE-NAME.*.PROPERTY_NAME
的正确 Terraform 资源语法。因此,在您的示例中,您将输出:
output "ids" {
value = "${aws_subnet.subnet-1.*.id}"
}
当然,您可能希望使用 concat interpolation function:
加入两个列表
output "ids" {
value = "${concat(aws_subnet.subnet-1.*.id, aws_subnet.subnet-2.*.id)}"
}
但是如果您的 count
属性 在任一资源上设置为 0,这可能会引发错误。为了解决这个问题,您可以使用其他插值函数的某种组合(例如 coalescelist()
),但恐怕我记不起确切的组合了。
最后,对于您的 count
属性,这些 var 定义读起来有点棘手。这里有一些其他的想法可以尝试:
// Count = 1 if var.secondary_subnet_cidr is non-empty
resource "aws_subnet" "subnet-1" {
count = "${signum(length(var.secondary_subnet_cidr))}"
...
}
// Define a separate var altogether. Ideally, you could infer this, but sometimes it's the best you can do.
resource "aws_subnet" "subnet-1" {
count = "${var.should_create_secondary_subnet)}"
...
}
2017 年 6 月 6 日更新:感谢@MartinAtkins 指出从 Terraform 0 开始。9.x,您不再需要将列表输出包装在 [
和 ]
。我已经更新了我的答案。
2017 年 6 月 8 日更新: 要 select 只有两个列表中的一个可能为空的非空列表,请使用 ${element(concat(aws_subnet.subnet-1.*.id, aws_subnet.subnet-2.*.id), 0)}
。 concat()
函数将接受一个空列表,而 element(..., 0)
将始终 returns 第一个元素,在本例中是非空列表。
我在尝试创建动态列表时发现了这个问题,我必须在其中创建一个列表中元素数量可变的列表。我正在创建一个字符串列表。我使用 Terraform's compact
method 解决了这个问题。基本上,这个列表会过滤掉我在列表中生成的空白元素。
例如假设我有以下列表,
myList = ["foo", barExists ? "bar" : ""]
这将创建 ["foo", "bar"]
或 ["foo", ""]
。如果您需要 ["foo", "bar"]
或 ["foo"]
,紧凑型函数就是您的朋友。
myList = compact(["foo", barExists ? "bar" : ""])
对于这种情况,上述行将起作用。
我正在尝试使用 count 在 terraform 中动态创建一些 aws 资源,然后构建一个包含所有已创建资源 ID 列表的输出变量
resource "aws_subnet" "subnet-1" {
// If subnet_id value is supplied then we set count to 1 to create otherwise skip
count = "${replace(replace(var.primary_subnet_cidr, "/^.+/", "1"), "/^$/", "0")}"
tags = {
Name = "subnet-1"
}
cidr_block = "${var.primary_subnet_cidr}"
vpc_id = "${var.vpc_id}"
availability_zone = "${var.aws_region}a"
}
resource "aws_subnet" "subnet-2" {
// If subnet_id value is supplied then we set count to 1 to create otherwise skip
count = "${replace(replace(var.secondary_subnet_cidr, "/^.+/", "1"),"/^$/", "0")}"
tags = {
Name = "subnet-2"
}
cidr_block = "${var.secondary_subnet_cidr}"
vpc_id = "${var.vpc_id}"
availability_zone = "${var.aws_region}b"
}
output "ids" {
value = ["${aws_subnet.subnet-1.id}","${aws_subnet.subnet-2.id}"]
}
想法是通过提供其变量(primary_subnet_cidr 或 secondary_subnet_cidr)来仅创建您想要的子网。
动态创建它们工作正常,但我的问题是动态列表。
当试图在类似 aws_db_subnet_group.subnet_ids
的东西中使用这个列表时,它只在两个子网都已创建时才有效,否则它会抛出以下错误
InvalidSubnet: Subnet IDs are required.
这个我也试过了
output "ids" {
value = ["${aws_subnet.*.id}"]
}
但是 terraform 似乎不支持资源级别的通配符。
我怀疑这与我生成输出列表的方式有关。有没有更好的方法来生成该动态列表,使其仅包含创建的资源?
您很接近,但您需要使用 RESOURCE-TYPE.RESOURCE-NAME.PROPERTY_NAME
或 RESOURCE-TYPE.RESOURCE-NAME.*.PROPERTY_NAME
的正确 Terraform 资源语法。因此,在您的示例中,您将输出:
output "ids" {
value = "${aws_subnet.subnet-1.*.id}"
}
当然,您可能希望使用 concat interpolation function:
加入两个列表output "ids" {
value = "${concat(aws_subnet.subnet-1.*.id, aws_subnet.subnet-2.*.id)}"
}
但是如果您的 count
属性 在任一资源上设置为 0,这可能会引发错误。为了解决这个问题,您可以使用其他插值函数的某种组合(例如 coalescelist()
),但恐怕我记不起确切的组合了。
最后,对于您的 count
属性,这些 var 定义读起来有点棘手。这里有一些其他的想法可以尝试:
// Count = 1 if var.secondary_subnet_cidr is non-empty
resource "aws_subnet" "subnet-1" {
count = "${signum(length(var.secondary_subnet_cidr))}"
...
}
// Define a separate var altogether. Ideally, you could infer this, but sometimes it's the best you can do.
resource "aws_subnet" "subnet-1" {
count = "${var.should_create_secondary_subnet)}"
...
}
2017 年 6 月 6 日更新:感谢@MartinAtkins 指出从 Terraform 0 开始。9.x,您不再需要将列表输出包装在 [
和 ]
。我已经更新了我的答案。
2017 年 6 月 8 日更新: 要 select 只有两个列表中的一个可能为空的非空列表,请使用 ${element(concat(aws_subnet.subnet-1.*.id, aws_subnet.subnet-2.*.id), 0)}
。 concat()
函数将接受一个空列表,而 element(..., 0)
将始终 returns 第一个元素,在本例中是非空列表。
我在尝试创建动态列表时发现了这个问题,我必须在其中创建一个列表中元素数量可变的列表。我正在创建一个字符串列表。我使用 Terraform's compact
method 解决了这个问题。基本上,这个列表会过滤掉我在列表中生成的空白元素。
例如假设我有以下列表,
myList = ["foo", barExists ? "bar" : ""]
这将创建 ["foo", "bar"]
或 ["foo", ""]
。如果您需要 ["foo", "bar"]
或 ["foo"]
,紧凑型函数就是您的朋友。
myList = compact(["foo", barExists ? "bar" : ""])
对于这种情况,上述行将起作用。