Terraform: Feature request: function to lookup a DNS name and return an IP address

Created on 6 Jun 2018  ยท  6Comments  ยท  Source: hashicorp/terraform

I would love a new function to lookup a DNS name and return an IP address.

One place I can think of where this would be useful is when using the aws_route53_delegation_set resource and then making your own private label nameservers from the records that are assigned to you:

# Incomplete + invalid config - demonstration only

resource "aws_route53_delegation_set" "main" {
  reference_name = "Main"
}

resource "aws_route53_zone" "foo" {
  name              = "example.com"
  delegation_set_id = "${aws_route53_delegation_set.main.id}"
}

resource "aws_route53_record" "nameservers" {
  count   = 4
  zone_id = "${aws_route53_zone.foo.id}"
  name    = "ns${count.index + 1}"
  type    = "A"
  ttl     = "86400"
  records = ["${nametoip(aws_route53_zone.foo.name_servers[count.index])}"]
}

Most helpful comment

Hi @tdmalone!

If I'm understanding correctly, I think you can get what you want using the dns_a_record_set data source:

resource "aws_route53_zone" "foo" {
  name              = "example.com"
  delegation_set_id = "${aws_route53_delegation_set.main.id}"
}

data "dns_a_record_set" "foo" {
  count = "${length(aws_route53_zone.foo.name_servers)}"
  host  = "${aws_route53_zone.foo.name_servers[count.index]}"
}

resource "aws_route53_record" "nameservers" {
  count = "${length(aws_route53_zone.foo.name_servers)}"

  # ...
  zone_id = "${aws_route53_zone.foo.id}"
  name    = "ns${count.index}.example.com"
  type    = "A"
  ttl     = "300"
  records = "${data.dns_a_record_set.foo.*.addrs}"
}

Unfortunately since aws_route53_zone.foo.name_servers is a value that can't be known until after the zone is created, if you try to apply the above as-is Terraform will complain that the count meta-argument for the data.dns_a_record_set.foo block "can't be computed", because the count must be known at plan time.

To work around this, it'll be necessary to bootstrap by first applying the aws_route53_zone alone using -target, after which the length of that list will be known and Terraform should be able to apply the whole configuration as normal on subsequent runs:

$ terraform apply -target=aws_route53_zone.foo`
...
$ terraform apply
...

DNS lookups are implemented as a data source rather than a function so that they can participate in the dependency graph. Although it's not important here (because the DNS records in question are managed by AWS and long-lived), sometimes it's necessary to read a DNS record that was written in the same configuration, and so it being a data source allows for that possibility.

All 6 comments

I'm currently getting around this by using lookup() and providing my own map:

variable "ns_ips" {
  default = {
    "ns-513.awsdns-00.net"    = "205.251.194.1"
    "ns-1430.awsdns-50.org"   = "205.251.197.150"
    "ns-438.awsdns-54.com"    = "205.251.193.182"
    "ns-1828.awsdns-36.co.uk" = "205.251.199.36"
  }
}

resource "aws_route53_record" "nameservers" {
  ...
  records = ["${lookup(var.ns_ips, aws_route53_zone.foo.name_servers[count.index])}"]
}

But of course this won't be any use for additional delegation sets unless I slowly build this map up :P

Hi @tdmalone!

If I'm understanding correctly, I think you can get what you want using the dns_a_record_set data source:

resource "aws_route53_zone" "foo" {
  name              = "example.com"
  delegation_set_id = "${aws_route53_delegation_set.main.id}"
}

data "dns_a_record_set" "foo" {
  count = "${length(aws_route53_zone.foo.name_servers)}"
  host  = "${aws_route53_zone.foo.name_servers[count.index]}"
}

resource "aws_route53_record" "nameservers" {
  count = "${length(aws_route53_zone.foo.name_servers)}"

  # ...
  zone_id = "${aws_route53_zone.foo.id}"
  name    = "ns${count.index}.example.com"
  type    = "A"
  ttl     = "300"
  records = "${data.dns_a_record_set.foo.*.addrs}"
}

Unfortunately since aws_route53_zone.foo.name_servers is a value that can't be known until after the zone is created, if you try to apply the above as-is Terraform will complain that the count meta-argument for the data.dns_a_record_set.foo block "can't be computed", because the count must be known at plan time.

To work around this, it'll be necessary to bootstrap by first applying the aws_route53_zone alone using -target, after which the length of that list will be known and Terraform should be able to apply the whole configuration as normal on subsequent runs:

$ terraform apply -target=aws_route53_zone.foo`
...
$ terraform apply
...

DNS lookups are implemented as a data source rather than a function so that they can participate in the dependency graph. Although it's not important here (because the DNS records in question are managed by AWS and long-lived), sometimes it's necessary to read a DNS record that was written in the same configuration, and so it being a data source allows for that possibility.

Thanks @apparentlymart, I didn't realise this provider existed! It should do exactly what I'm after.

@apparentlymart I think a lookup function to just perform a host lookup would still be pretty useful, even without the graph. I've got a use case where I want to provide a list of hostnames to a module, but the module actually needs to consume IP addresses. I can't think of a way to just take in hostnames and convert to IPs using a resource or datasource, unless the datasource could take a list to convert?

I could open another issue with the use case laid out if that requirement makes sense to you?

+1 the only other way to do this is with a local or remote provisioner and then it is O.S dependent... could really do with a host_to_ip() function to abstract this... save messing around with data_sources that might not support the general purpose use case... given how much n/w config occurs when using TF having the ability to lookup hostnames to obtain their IP seems like a very valuable utility beyond the specific example use case above

I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pawelsawicz picture pawelsawicz  ยท  3Comments

rnowosielski picture rnowosielski  ยท  3Comments

rjinski picture rjinski  ยท  3Comments

ketzacoatl picture ketzacoatl  ยท  3Comments

ronnix picture ronnix  ยท  3Comments