Terraform: условное создание ресурса на основе переменной в .tfvars
У меня есть ресурсы, определенные в .tf
файлы, общие для нескольких приложений. Я заполняю многие поля через.tfvars
файл. Мне нужно исключить некоторые ресурсы, полностью основанные на переменных в.tfvars
.
Например, если у меня есть ресурс вроде:
resource "cloudflare_record" "record" {
zone_id = "${data.cloudflare_zones.domain.zones[0].id}"
name = "${var.subdomain}"
value = "${var.origin_server}"
type = "CNAME"
ttl = 1
proxied = true
}
Но тогда я заявляю что-то вроде cloudflare = false
в моем .tfvars
файл, я бы хотел сделать что-то вроде этого:
if var.cloudflare {
resource "cloudflare_record" "record" {
zone_id = "${data.cloudflare_zones.domain.zones[0].id}"
name = "${var.subdomain}"
value = "${var.origin_server}"
type = "CNAME"
ttl = 1
proxied = true
}
}
Я посмотрел на динамические блоки, но похоже, что вы можете использовать их только для редактирования полей и блоков внутри ресурса. Мне нужно иметь возможность игнорировать весь ресурс.
5 ответов
На самом деле это очень просто. Добавитьcount
параметр с тернарным условным выражением с использованием переменной, объявленной в .tfvars
нравится:
resource "cloudflare_record" "record" {
count = var.cloudflare ? 1 : 0
zone_id = "${data.cloudflare_zones.domain.zones[0].id}"
name = "${var.subdomain}"
value = "${var.origin_server}"
type = "CNAME"
ttl = 1
proxied = true
}
В этом примере var.cloudflare
является логическим значением, объявленным в .tfvars
файл. Если это правда, счет 1record
будет создан. Если это ложь, подсчет 0record
будет создан.
Расширение ответа @Joel Guerra после использованияcount
чтобы определить, следует ли развертывать ресурс или нет, вы можете использоватьone()
для обращения к ресурсу без индекса (т.е. без использования ).
Например, после определения ресурса, как показано ниже
resource "cloudflare_record" "record" {
count = var.cloudflare ? 1 : 0
}
Определите локальную переменную, как показано ниже.
locals {
cloudflare_record_somefield = one(cloudflare_record.record[*].some_field)
}
Теперь вместоcloudflare_record.record[0].some_field
, вы можете использовать
local.cloudflare_record_somefield
Если счетчик равен 0 (например,var.cloudflare
являетсяfalse
и ресурс не был создан) тогдаlocal.cloudflare_record_somefield
вернетсяnull
(вместо того, чтобы возвращать ошибку при индексировании с помощью[0]
).
Ссылка: https://developer.hashicorp.com/terraform/language/functions/one
Проблема, с которой я сталкиваюсь, заключается в том, что если ресурс, который вы пытаетесь создать, уже использует for_each, то вы не можете использовать в ресурсе как count, так и for_each. Я все еще пытаюсь найти ответ на этот вопрос, если я найду что-то лучше, он будет обновлен.
Пример сценария. Возможно, вы захотите создать или не создавать (переключить/использовать флаг/создать по условию) виртуальную машину. Но наряду с виртуальной машиной вам также может потребоваться создать или не создавать ее балансировщик нагрузки, целевую группу, группу безопасности и т. д.
Проблема с другими ответами в Интернете заключается в том, что когда вы используете тернарный оператор для ресурса и пытаетесь сослаться на него на каком-либо другом ресурсе, вы всегда получаете ошибку ссылки, ошибку индекса или ошибку пустого кортежа.
Чтобы решить эту проблему при указании на условный ресурс, вы можете использовать
resource "aws_vpc" "main" {
count = var.test_flag ? 1 : 0
cidr_block = var.vpc_cidr
instance_tenancy = var.vpc_instance_tenancy
tags = {
Name = "${var.cluster_name}-vpc"
}
}
resource "aws_internet_gateway" "gw" {
count = try(var.test_flag ? 1 : 0, 0) // try block is important here because it has a dependency, here the VPC, but VPC might not need a try block because it is the parent.
vpc_id = aws_vpc.main[0].id
tags = {
Name = "${var.cluster_name}-IG"
}
}
Я столкнулся с аналогичной проблемой создания ресурсов AWS на основе переменной.
Запрос:
- для производственной среды используйте импортированный сертификат;
- для среды разработки запросите сертификат ACM и проверьте его через DNS, создав записи Route53.
Я пробую код, как показано ниже. В производственной среде он жалуется, что выданный AWS файл aws_acm_certificate.alb[] пуст. Я надеялся, что тернарный оператор «?:» ярлык.
Любое предложение о том, как решить мою проблему?
Спасибо,
Тигр
# alb Cert
data "aws_acm_certificate" "vault-alb-imported" {
counti = var.vault-cert-arn == "" ? 0 : 1
domain = "vault-alb.${var.domain}"
types = ["IMPORTED"]
}
resource "aws_acm_certificate" "alb" {
count = var.cert-arn == "" ? 1 : 0
domain_name = "alb.${var.domain}"
validation_method = "DNS"
lifecycle {
create_before_destroy = true
}
tags = merge(var.default-tags, tomap({
Name = "alb"
}))
}
resource "aws_route53_record" "alb-cert" {
for_each = var.cert-arn == "" ? {} : {
for dvo in aws_acm_certificate.alb[0].domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
allow_overwrite = true
name = each.value.name
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = var.public-hosted-zone-id
}