我正在尝试使用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似乎并不支持资源级别的通配符。
我怀疑这与我生成输出列表的方式有关。有没有更好的方法来生成动态列表,因此它只包含创建的资源?
答案 0 :(得分:2)
您很接近,但您需要使用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开始,您不再需要在[
和{{1}中包装列表输出}。我已经更新了我的答案。
2017年6月8日更新:要仅选择一个可能为空的两个列表中的非空列表,请使用]
。 ${element(concat(aws_subnet.subnet-1.*.id, aws_subnet.subnet-2.*.id), 0)}
函数将接受一个空列表,concat()
将始终返回第一个元素,在这种情况下是非空列表。
答案 1 :(得分:0)
我在尝试创建动态列表时发现了这个问题,我必须在其中创建一个列表,其中列表中的元素数量可变。我正在创建一个字符串列表。我通过使用 Terraform's compact
method 解决了这个问题。基本上,这个列表会过滤掉我在列表中生成的空白元素。
例如假设我有以下列表,
myList = ["foo", barExists ? "bar" : ""]
这将创建 ["foo", "bar"]
或 ["foo", ""]
。如果您需要 ["foo", "bar"]
或 ["foo"]
,紧凑函数就是您的朋友。
myList = compact(["foo", barExists ? "bar" : ""])
对于这种情况,上面的代码行会起作用。