How to reference datasources using a dynamic string?

Hello,

I am trying to generate a string with the same name as a datasource resource and am hoping you can suggest me a way to make the string reference the datasource.

This is what I have in code.

variable "env_subdomains" {
  description = "different region specific envs for hosted zones"
  type        = list(string)
  default = [
    "dev",
    "qa",
    "uat"
  ]
}

variable "region_subdomains" {
  description = "different region values for hosted zones"
  type        = list(string)
  default = [
    "au",  #australia
    "sg",  #singapore
    "my" #malaysia
  ]
}

variable "app_subdomains" {
  description = "different apps for subdomains within region"
  type        = list(string)
  default = [
    "kamailo",
   "nginx"
  ]
}

data "aws_route53_zone" "uat_au_region_hosted_zone" {
  name = "uat.au.${var.TLD}"
}

locals {
  all_subdomains     = distinct(setproduct(var.app_subdomains, var.env_subdomains, var.region_subdomains))
}

module "nonprod_acm_certs" {
  count       = length(local.all_subdomains)
  source      = "terraform-aws-modules/acm/aws"
  version     = "~> v2.0"
  domain_name = "*.${local.all_subdomains[count.index].0}.${local.all_subdomains[count.index].1}.${local.all_subdomains[count.index].2}.${var.TLD}"
  zone_id     = "$${data.aws_route53_zone.${local.all_subdomains[count.index].1}_${local.all_subdomains[count.index].2}_region_hosted_zone.zone_id}"
  subject_alternative_names = [
    "${local.all_subdomains[count.index].0}.${local.all_subdomains[count.index].1}.${local.all_subdomains[count.index].2}.${var.TLD}",
  ]
  certificate_transparency_logging_preference = true
  wait_for_validation                         = true
  tags = merge(
    local.common_tags,
    {
      Name = "${local.all_subdomains[count.index].0}.${local.all_subdomains[count.index].1}.${local.all_subdomains[count.index].2}.${var.TLD}"
    }
  )
}

What I trying to achieve is:

  • The zoneID mentioned below in one of it’s iteration would be the same name as the datasource - uat_au_region_hosted_zone. So, I am trying to set the interpolation in such a way that the resultant string would automatically refer the datasource.
 zone_id     = "$${data.aws_route53_zone.${local.all_subdomains[count.index].1}_${local.all_subdomains[count.index].2}_region_hosted_zone.zone_id}"

But when I run TFPlan, it shows like in the image below. Not sure, if in the apply stage, it will automatically resolve to the datasource value.

Can anyone please help me with this ?

You can’t dynamically set the name of any sort of resource/module/data source reference.

Instead you should look at using for_each or count, and then you can do things like data.datasource_name["some_value"].attribute with some_value being calculated (using things like each.value, etc.)

Another possibility is to gather the separate data resource results up into a mapping yourself in a local value, and then you can look up elements of that mapping dynamically by key:

locals {
  route53_zones = {
    uat_au = data.aws_route53_zone.uat_au_region_hosted_zone
    # (and any others you want to use)
  }
}

You can then use local.route53_zones["uat_au"] to access that specific element, or you can put an arbitrary expression inside those brackets to generate a lookup key dynamically based on values from elsewhere.

When you use for_each in a resource or data block Terraform will construct a similar map for you automatically, but if you need something more custom than that there’s no reason you can’t construct the map directly yourself.

1 Like

Thanks for the idea @apparentlymart . This solves my problem.