Terraform - 条件数据源 [英] Terraform - Conditional Data Source

查看:19
本文介绍了Terraform - 条件数据源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 terraform 中,有没有办法有条件地使用数据源?例如:

In terraform, is there any way to conditionally use a data source? For example:

 data "aws_ami" "application" {
     most_recent = true
     filter {
         name = "tag:environment"
         values = ["${var.environment}"]
     }
     owners = ["self"]
}

我希望能够通过命令行传入一个环境变量,并基于此确定是否获取此数据源.

I'm hoping to be able to pass in an environment variable via the command line, and based on that, determine whether or not to fetch this data source.

我知道对于资源,您可以使用 count 属性,但似乎不能将其用于数据源.

I know with resources you can use the count property, but it doesn't seem you can use that with data sources.

我会考虑将此代码隐藏在模块中,但模块也不能使用 count 参数.

I would consider tucking this code away in a module, but modules also can't use the count parameter.

最后,另一种选择是提供默认"数据源的值,如果它返回 null,但我认为这也不可行.

Lastly, another option would be to provide a "Default" value for the data source, if it returned null, but I don't think that's doable either.

是否有其他潜在的解决方案?

Are there any other potential solutions for this?

推荐答案

您可以像使用资源一样对数据源使用条件,也可以在模块上使用 Terraform 0.13+:

You can use a conditional on data sources the same as you can with resources and also from Terraform 0.13+ on modules as well:

variable "lookup_ami" {
  default = true
}

 data "aws_ami" "application" {
   count       = var.lookup_ami ? 1 : 0
   most_recent = true
   filter {
     name   = "tag:environment"
     values = [var.environment]
   }
   owners = ["self"]
}

Terraform 0.12+ 中的一个用例是利用三元语句的惰性求值,如下所示:

One use case for this in Terraform 0.12+ is to utilise the lazy evaluation of ternary statements like with the following:

variable "internal" {
  default = true
}

data "aws_route53_zone" "private_zone" {
  count        = var.internal ? 1 : 0
  name         = var.domain
  vpc_id       = var.vpc_id
  private_zone = var.internal
}

data "aws_route53_zone" "public_zone" {
  count        = var.internal ? 0 : 1
  name         = var.domain
  private_zone = var.internal
}

resource "aws_route53_record" "www" {
   zone_id = var.internal ? data.aws_route53_zone.private_zone.zone_id : data.aws_route53_zone.public_zone.zone_id
   name    = "www.${var.domain}"
   type    = "A"
   alias {
     name                   = aws_elb.lb.dns_name
     zone_id                = aws_elb.lb.zone_id
     evaluate_target_health = false
   }
}

var.internaltrue 时,这将在私有区域中创建记录,而当 var.internalfalse.

This would create a record in the private zone when var.internal is true and instead create a record in the public zone when var.internal is false.

对于这个特定用例,您还可以使用 Terraform 0.12+ 的 null 更简单地重写:

For this specific use case you could also use Terraform 0.12+'s null to rewrite this more simply:

variable "internal" {
  default = true
}

data "aws_route53_zone" "zone" {
  name         = var.domain
  vpc_id       = var.internal ? var.vpc_id : null
  private_zone = var.internal
}

resource "aws_route53_record" "www" {
   zone_id = data.aws_route53_zone.zone.zone_id
   name    = "www.${data.aws_route53_zone.zone.name}"
   type    = "A"
   alias {
     name                   = aws_elb.lb.dns_name
     zone_id                = aws_elb.lb.zone_id
     evaluate_target_health = false
   }
}

如果 var.internal 设置为 true,这只会将 vpc_id 参数传递给 aws_route53_zone 数据源> 因为当 private_zonefalse 时,您无法设置 vpc_id.

This would only pass the vpc_id parameter to the aws_route53_zone data source if var.internal is set to true as you can't set vpc_id when private_zone is false.

实际上,您可以根据数据源的数量使用条件,但在我尝试后,我还没有设法为它找到一个好的用例.

You can in fact use a conditional on the count of data sources but I've yet to manage to work out a good use case for it when I've tried.

举个例子,我成功地完成了这项工作:

As an example I successfully had this working:

data "aws_route53_zone" "private_zone" {
  count        = "${var.internal == "true" ? 1 : 0}"
  name         = "${var.domain}"
  vpc_id       = "${var.vpc_id}"
  private_zone = "true"
}

data "aws_route53_zone" "public_zone" {
  count        = "${var.internal == "true" ? 0 : 1}"
  name         = "${var.domain}"
  private_zone = "false"
}

但是随后在如何选择它的输出方面遇到了问题,因为 Terraform 将在决定使用三元的哪一侧之前评估三元条件中的任何变量(而不是惰性求值).所以这样的事情是行不通的:

But then had issues in how to then select the output of it because Terraform will evaluate any variables in the ternary conditional before deciding which side of the ternary to use (instead of lazy evaluation). So something like this doesn't work:

resource "aws_route53_record" "www" {
   zone_id = "${var.internal ? data.aws_route53_zone.private_zone.zone_id : data.aws_route53_zone.public_zone.zone_id}"
   name = "www.example.com"
   type = "A"
   alias {
     name                   = "${aws_elb.lb.dns_name}"
     zone_id                = "${aws_elb.lb.zone_id }"
     evaluate_target_health = "false"
   }
}

因为如果 internal 为真,那么您将获得 private_zone 数据源而不是 public_zone 数据源,因此三元的后半部分无法评估,因为 data.aws_route53_zone.public_zone.zone_id 未定义,反之亦然.

Because if internal is true then you get the private_zone data source but not the public_zone data source and so the second half of the ternary fails to evaluate because data.aws_route53_zone.public_zone.zone_id isn't defined and equally with the other way around too.

在您的情况下,您可能只想有条件地使用数据源,因此可以执行以下操作:

In your case you probably just want to conditionally use the data source so might be able to do something like this:

variable "dynamic_ami" { default = "true" }
variable "default_ami" { default = "ami-123456" }

data "aws_ami" "application" {
  most_recent = true
  filter {
    name = "tag:environment"
    values = ["${var.environment}"]
  }
  owners = ["self"]
}

resource "aws_instance" "app" {
    ami = "${var.dynamic_ami == "true" ? data.aws_ami.application.id : var.default_ami}"
    instance_type = "t2.micro"
}

这篇关于Terraform - 条件数据源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆