Terraform - 条件数据源 [英] Terraform - Conditional Data Source
问题描述
在 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.internal
为 true
时,这将在私有区域中创建记录,而当 var.internal时在公共区域中创建记录code> 是
false
.
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_zone
为 false
时,您无法设置 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屋!