1
votes

I want to be able to create multiple R53 records, using the following format defined in TF Vars:

custom_zone_records = {
  "demo.a.com" = [
    {"*.b" = {type: "CNAME", records: ["d.com"]}},
    {"*.c" = {type: "CNAME", records: ["d.com"]}}
  ]
}

Using the record as an example, it should create the R53 record of:

Name: *.b.demo.a.com
Type: CNAME
Records: ["d.com"]

The input variable is defined as:

variable "custom_zone_records" {
  description = "A map of maps for custom zone records"
  type = map(list(map(object({
    type = string
    records: list(string)
  }))))
}

I've tried mutating the array within the resource creation using a for_each and I've tried formatting using a locals file, with no success.

Is there a better way to format or handle this, other than having the array more explicit?

Thanks.

Edit:

If I were to not use the variable, I would have to write the following code (as an example of what I am trying to achieve)

resource "aws_route53_record" "demo_a" {
  zone_id = "ZONE_ID"
  name    = "*.b.demo.a.com"
  type    = "CNAME"
  records = ["d.com"]
  ttl     = 60
}

resource "aws_route53_record" "demo_a" {
  zone_id = "ZONE_ID"
  name    = "*.c.demo.a.com"
  type    = "CNAME"
  records = ["d.com"]
  ttl     = 60
}
1
So far so good, what you tried in terms of passing the variable into aws_route53_record s? Where exactly are you stuck? - luk2302
Got as far as adding the for_each (which loop through the top level zone e.g. demo.a.com) then tried adding a look up, to loop through the values. Kind of stuck at that that point - how do we (if possible) loop through loops in resources, the question is realistically. - James Elliott
What would the N resource(s) look like if you were to manually create them without the variable? How many would there be for the given example? If you need to loop twice (once for the different domains and once for the different records) you can create a local that loops over the data, creates multiple nested arrays and then wrap everything in a flatten call so that you can then for_each over the unrolled local. - luk2302
I've edited the question to show the manual creation of the records I want to create. I don't suppose you'd be able to give me a little bit of code, as an example please? I think I'm barking at the wrong tree in the direction I've gone - James Elliott

1 Answers

2
votes

One way to do this (assuming I correctly understand the issue), would be to create an a helper local variable which would "unwind" the custom_zone_records into more for_each-friendly list.

In the following example, it is called helper_list:

locals {
  custom_zone_records = {
    "demo.a.com" = [
      {"*.b" = {type: "CNAME", records: ["d.com"]}},
      {"*.c" = {type: "CNAME", records: ["d.com"]}}
    ],
    "demo1.a.com" = [
      {"*.b1" = {type: "CNAME", records: ["d1.com"]}},
      {"*.c1" = {type: "CNAME", records: ["d1.com"]}}
    ]    
  }
  
  helper_list = flatten([for k, v in local.custom_zone_records: 
            [for v1 in v: 
              merge({name = join("", [keys(v1)[0], ".", k])}, values(v1)[0])
           ]
      ])
  
}

The helper_list would have the form:

helper_list = [                     
  {                          
    "name" = "*.b.demo.a.com"
    "records" = [   
      "d.com",               
    ]               
    "type" = "CNAME"         
  },             
  {                          
    "name" = "*.c.demo.a.com"
    "records" = [   
      "d.com",
    ]               
    "type" = "CNAME"
  },
  {
    "name" = "*.b1.demo1.a.com"
    "records" = [
      "d1.com",
    ]
    "type" = "CNAME"
  },
  {
    "name" = "*.c1.demo1.a.com"
    "records" = [
      "d1.com",
    ]
    "type" = "CNAME"
  },
]

This way, the for_each usage would be simpler, and could be (I haven't verified the following, so treat it as a pseudo-code):

resource "aws_route53_record" "demo" {

  for_each = toset(local.helper_list)

  zone_id = "ZONE_ID"

  name    = each.value.name
  type    = each.value.type
  records = each.value.records

  ttl     = 60
}