Terraform 中的条件属性
Conditional attributes in Terraform
Terraform 是否支持条件属性?我只想根据变量的值使用属性。
示例:
resource "aws_ebs_volume" "my_volume" {
availability_zone = "xyz"
size = 30
if ${var.staging_mode} == true:
snapshot_id = "a_specific_snapshot_id"
endif
}
上面 if
包含属性 snapshot_id
的语句正是我要查找的内容。 Terraform 是否支持基于变量值的此类属性包含。
我不知道有这样的功能,但是,如果您的情况不太复杂,您可以围绕此进行建模。由于布尔值 true
和 false
被认为是 1
和 0
,因此您可以在计数中使用它们。所以你可以使用
provider "null" {}
resource "null_resource" "test1" {
count= ${var.condition ? 1 : 0}
}
resource "null_resource" "test2" {
count = ${var.condition ? 0 : 1}
}
output "out" {
value = "${var.condition ? join(",",null_resource.test1.*.id) : join(",",null_resource.test2.*.id) }"
}
由于 count
属性,两个资源中只创建了一个。
您必须使用 join
作为值,因为这似乎可以优雅地处理两个值之一不存在的情况。
感谢ydaetskcor for pointing out in 变量处理的改进。
Terraform 0.12(尚未发布)也会带来 support for HCL2 which allows you to use nullable arguments 类似这样的东西:
resource "aws_ebs_volume" "my_volume" {
availability_zone = "xyz"
size = 30
snapshot_id = var.staging_mode ? local.a_specific_snapshot_id : null
}
中涵盖了可空参数
对于 0.12 之前的 Terraform 版本,Markus's 可能是您最好的选择,尽管我会更明确地使用 count
类似这样的内容:
resource "aws_ebs_volume" "staging_volume" {
count = "${var.staging_mode ? 1 : 0}"
availability_zone = "xyz"
size = 30
snapshot_id = "a_specific_snapshot_id"
}
resource "aws_ebs_volume" "non_staging_volume" {
count = "${var.staging_mode ? 0 : 1}"
availability_zone = "xyz"
size = 30
}
请注意,资源名称必须是唯一的,否则 Terraform 会报错。如果您需要引用 EBS 卷,例如在 pre 0.12 the ternary expression is not lazy 中使用 aws_volume_attachment
,这就会导致问题,所以这样的事情不起作用:
resource "aws_volume_attachment" "ebs_att" {
device_name = "/dev/sdh"
volume_id = "${var.staging_mode ? aws_ebs_volume.staging_volume.id : aws_ebs_volume.non_staging_volume.id}"
instance_id = "${aws_instance.web.id}"
}
因为它将尝试评估三元组的两边,其中在任何时候只有一个有效。在 Terraform 0.12 中,情况将不再如此,但显然您可以使用可为 null 的参数更轻松地解决它。
现在 Terraform v0.12 和相应的 HCL2 已经发布,您只需将默认变量值设置为 "null" 即可实现此目的。从 Terraform 网站看这个例子:
variable "override_private_ip" {
type = string
default = null
}
resource "aws_instance" "example" {
# ... (other aws_instance arguments) ...
private_ip = var.override_private_ip
}
更多信息在这里:
https://www.hashicorp.com/blog/terraform-0-12-conditional-operator-improvements
只是为了帮助,一个更复杂的例子:
data "aws_subnet" "private_subnet" {
count = var.sk_count
vpc_id = data.aws_vpc.vpc.id
availability_zone = element(sort(data.aws_availability_zones.available.names), count.index)
tags = {
Name = var.old_cluster_fqdn != "" ? "${var.old_cluster_fqdn}-prv-subnet-${count.index}" : "${var.cluster_fqdn}-prv-subnet-${count.index}"
}
}
Terraform 0.15 有一个新的实验性功能:defaults
与 optional
一起使用。
The defaults function is a specialized function intended for use with input variables whose type constraints are object types or collections of object types that include optional attributes.
来自文档:
terraform {
# Optional attributes and the defaults function are
# both experimental, so we must opt in to the experiment.
experiments = [module_variable_optional_attrs]
}
variable "storage" {
type = object({
name = string
enabled = optional(bool)
website = object({
index_document = optional(string)
error_document = optional(string)
})
documents = map(
object({
source_file = string
content_type = optional(string)
})
)
})
}
locals {
storage = defaults(var.storage, {
# If "enabled" isn't set then it will default
# to true.
enabled = true
# The "website" attribute is required, but
# it's here to provide defaults for the
# optional attributes inside.
website = {
index_document = "index.html"
error_document = "error.html"
}
# The "documents" attribute has a map type,
# so the default value represents defaults
# to be applied to all of the elements in
# the map, not for the map itself. Therefore
# it's a single object matching the map
# element type, not a map itself.
documents = {
# If _any_ of the map elements omit
# content_type then this default will be
# used instead.
content_type = "application/octet-stream"
}
})
}
Terraform 是否支持条件属性?我只想根据变量的值使用属性。
示例:
resource "aws_ebs_volume" "my_volume" {
availability_zone = "xyz"
size = 30
if ${var.staging_mode} == true:
snapshot_id = "a_specific_snapshot_id"
endif
}
上面 if
包含属性 snapshot_id
的语句正是我要查找的内容。 Terraform 是否支持基于变量值的此类属性包含。
我不知道有这样的功能,但是,如果您的情况不太复杂,您可以围绕此进行建模。由于布尔值 true
和 false
被认为是 1
和 0
,因此您可以在计数中使用它们。所以你可以使用
provider "null" {}
resource "null_resource" "test1" {
count= ${var.condition ? 1 : 0}
}
resource "null_resource" "test2" {
count = ${var.condition ? 0 : 1}
}
output "out" {
value = "${var.condition ? join(",",null_resource.test1.*.id) : join(",",null_resource.test2.*.id) }"
}
由于 count
属性,两个资源中只创建了一个。
您必须使用 join
作为值,因为这似乎可以优雅地处理两个值之一不存在的情况。
感谢ydaetskcor for pointing out in
Terraform 0.12(尚未发布)也会带来 support for HCL2 which allows you to use nullable arguments 类似这样的东西:
resource "aws_ebs_volume" "my_volume" {
availability_zone = "xyz"
size = 30
snapshot_id = var.staging_mode ? local.a_specific_snapshot_id : null
}
中涵盖了可空参数
对于 0.12 之前的 Terraform 版本,Markus's count
类似这样的内容:
resource "aws_ebs_volume" "staging_volume" {
count = "${var.staging_mode ? 1 : 0}"
availability_zone = "xyz"
size = 30
snapshot_id = "a_specific_snapshot_id"
}
resource "aws_ebs_volume" "non_staging_volume" {
count = "${var.staging_mode ? 0 : 1}"
availability_zone = "xyz"
size = 30
}
请注意,资源名称必须是唯一的,否则 Terraform 会报错。如果您需要引用 EBS 卷,例如在 pre 0.12 the ternary expression is not lazy 中使用 aws_volume_attachment
,这就会导致问题,所以这样的事情不起作用:
resource "aws_volume_attachment" "ebs_att" {
device_name = "/dev/sdh"
volume_id = "${var.staging_mode ? aws_ebs_volume.staging_volume.id : aws_ebs_volume.non_staging_volume.id}"
instance_id = "${aws_instance.web.id}"
}
因为它将尝试评估三元组的两边,其中在任何时候只有一个有效。在 Terraform 0.12 中,情况将不再如此,但显然您可以使用可为 null 的参数更轻松地解决它。
现在 Terraform v0.12 和相应的 HCL2 已经发布,您只需将默认变量值设置为 "null" 即可实现此目的。从 Terraform 网站看这个例子:
variable "override_private_ip" {
type = string
default = null
}
resource "aws_instance" "example" {
# ... (other aws_instance arguments) ...
private_ip = var.override_private_ip
}
更多信息在这里:
https://www.hashicorp.com/blog/terraform-0-12-conditional-operator-improvements
只是为了帮助,一个更复杂的例子:
data "aws_subnet" "private_subnet" {
count = var.sk_count
vpc_id = data.aws_vpc.vpc.id
availability_zone = element(sort(data.aws_availability_zones.available.names), count.index)
tags = {
Name = var.old_cluster_fqdn != "" ? "${var.old_cluster_fqdn}-prv-subnet-${count.index}" : "${var.cluster_fqdn}-prv-subnet-${count.index}"
}
}
Terraform 0.15 有一个新的实验性功能:defaults
与 optional
一起使用。
The defaults function is a specialized function intended for use with input variables whose type constraints are object types or collections of object types that include optional attributes.
来自文档:
terraform {
# Optional attributes and the defaults function are
# both experimental, so we must opt in to the experiment.
experiments = [module_variable_optional_attrs]
}
variable "storage" {
type = object({
name = string
enabled = optional(bool)
website = object({
index_document = optional(string)
error_document = optional(string)
})
documents = map(
object({
source_file = string
content_type = optional(string)
})
)
})
}
locals {
storage = defaults(var.storage, {
# If "enabled" isn't set then it will default
# to true.
enabled = true
# The "website" attribute is required, but
# it's here to provide defaults for the
# optional attributes inside.
website = {
index_document = "index.html"
error_document = "error.html"
}
# The "documents" attribute has a map type,
# so the default value represents defaults
# to be applied to all of the elements in
# the map, not for the map itself. Therefore
# it's a single object matching the map
# element type, not a map itself.
documents = {
# If _any_ of the map elements omit
# content_type then this default will be
# used instead.
content_type = "application/octet-stream"
}
})
}