Terraform中的条件属性

时间:2018-07-24 10:35:05

标签: terraform terraform-provider-aws

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的{​​{1}}语句。 Terraform是否基于变量的值支持这种属性包含。

5 个答案:

答案 0 :(得分:4)

我不知道这样的功能,但是,如果您的案例不太复杂,则可以对此建模。由于布尔值exec sp_executesql N'SET NOCOUNT ON; INSERT INTO [Items] ([Name]) VALUES (@p0); SELECT [ID], [Code] FROM [Items] WHERE @@ROWCOUNT = 1 AND [ID] = scope_identity(); ',N'@p0 nvarchar(50)',@p0=N'Item1' Code被认为是truefalse,因此您可以在计数内使用它们。所以你可以使用

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) }" } 作为值,因为这似乎可以很好地处理两个值之一的不存在。

感谢ydaetskcortheir answer中指出了变量处理方面的改进。

答案 1 :(得分:3)

Terraform 0.12(尚未发布)还将带来support for HCL2,它使您可以将可空参数用于类似这样的事情:

resource "aws_ebs_volume" "my_volume" {
  availability_zone = "xyz"
  size              = 30
  snapshot_id       = "staging_mode ? a_specific_snapshot_id : null"
}

可空参数包含在this 0.12 preview guide中。

就目前而言,{0.1}之前的Markusanswer可能是您最好的选择,尽管我会更明确地使用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中,情况将不再如此,但是显然,您可以使用可为空的参数来更轻松地解决它。

答案 2 :(得分:2)

现在已发布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

答案 3 :(得分:0)

仅是帮助,一个更复杂的示例:

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}"
  }
}

答案 4 :(得分:0)

Terraform 0.15 有一项新的实验性功能:defaults 可与 optional 配合使用。

<块引用>

defaults 函数是一个专门用于输入变量的函数,输入变量的类型约束是对象类型或包含可选属性的对象类型集合。

来自文档:

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"
    }
  })
}