I have several domains and I want to create subdomains with as much DRY as possible. This is the original structure:
variable "domain1" {
type = list(string)
default = ["www", "www2"]
}
variable "domain2" {
type = list(string)
default = ["www3", "www1"]
}
resource "aws_route53_record" "domain1" {
for_each = toset(var.domain1)
type = "A"
name = "${each.key}.domain1.com"
zone_id = ""
}
resource "aws_route53_record" "domain2" {
for_each = toset(var.domain2)
type = "A"
name = "${each.key}.domain2.com"
zone_id = ""
}
that I want to combine to one variable and one resource block:
variable "subdomains" {
type = map(list(string))
default = {
"domain1.com" = ["www", "www2"]
"domain2.com" = ["www3", "www1"]
}
}
resource "aws_route53_record" "domain1" {
for_each = var.subdomains // make magic happen here...
type = "A"
name = "${each.subdomain_part}.${each.domain_part}" // ...and here
zone_id = ""
}
Is there a way to achieve this?
Following up on the comment about a messy state, I would not say messy... but certainly there are some downsides, the index in that answer is numeric, a plan show that the resource ends up:
# aws_route53_record.domain1["0"] will be created
+ resource "aws_route53_record" "domain1" {
# aws_route53_record.domain1["1"] will be created
+ resource "aws_route53_record" "domain1" {
That can create problems when we add or remove subdomains to the list, the order can change and that will cause the resources to be destroyed and recreated, not ideal on route53 records...
Here is another approach that will create a different index in the resource name.
We still use flatten to extract the subdomains but on this case I'm concatenating right away, that local variable is ready for the aws_route53_record
resource to consume it.
provider "aws" {
region = "us-east-2"
}
variable "subdomains" {
type = map(list(string))
default = {
"domain1.com" = ["www", "www2"]
"domain2.com" = ["www3", "www1"]
}
}
locals {
records = flatten([for d, subs in var.subdomains: [for s in subs: "${s}.${d}"]])
}
resource "aws_route53_record" "domain1" {
for_each = toset(local.records)
type = "A"
name = each.value
zone_id = "us-east-1"
}
A terraform plan of that looks like:
Terraform will perform the following actions:
# aws_route53_record.domain1["www.domain1.com"] will be created
+ resource "aws_route53_record" "domain1" {
+ allow_overwrite = (known after apply)
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = "www.domain1.com"
+ type = "A"
+ zone_id = "us-east-1"
}
# aws_route53_record.domain1["www1.domain2.com"] will be created
+ resource "aws_route53_record" "domain1" {
+ allow_overwrite = (known after apply)
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = "www1.domain2.com"
+ type = "A"
+ zone_id = "us-east-1"
}
...