Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provider/aws: data source for AWS Hosted Zone #9766

Merged
merged 7 commits into from
Dec 13, 2016

Conversation

mathieuherbert
Copy link
Contributor

To add Hosted Zone data source for AWS provider.

data "aws_route53_zone" "selected" {
  name = "test.com."
}

For example we can do that with this data source

resource "aws_route53_record" "www" {
  zone_id = "${data.aws_route53_zone.selected.zone_id}"
  name = "www.${data.aws_route53_zone.selected.name}"
  type = "A"
  ttl = "300"
  records = ["10.0.0.1"]
}

The acceptance test

TF_ACC=true go test -v github.com/hashicorp/terraform/builtin/providers/aws -run ^TestAccDataSourceAwsRoute53Zone$
=== RUN   TestAccDataSourceAwsRoute53Zone
--- PASS: TestAccDataSourceAwsRoute53Zone (48.92s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	48.932s

Copy link
Contributor

@jen20 jen20 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @mathieuherbert! This looks like a great addition! I've left a few comments on the code inline, but there is one missing feature I think we need to add - zone name is not sufficient to narrow down the search to one zone, since you may have the same name in a private and public zone. I think we need to add a private_zone boolean field, defaulting to false, to control which of these we find in this case. Thanks for the PR! If you are able to make the changes noted we'll get this merged soon, if not one of us can pick it up and take it through to completion!

package aws

import (
"fmt"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have goimports run on it for correct formatting.

package aws

import (
"fmt"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have goimports run on it for correct formatting.

d.Set("name", hostedZone.Name)
d.Set("comment", hostedZone.Config.Comment)
} else {
return fmt.Errorf("name or zone_id have to be setted")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should read either name or zone_id must be set, I think.

resp, err := conn.GetHostedZone(req)

if err != nil {
return err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should wrap this in errwrap.Wrapf("Error finding Route 53 Hosted Zone: {{err}}", err).

d.SetId(id)
d.Set("zone_id", id)
d.Set("name", hostedZone.Name)
d.Set("comment", hostedZone.Config.Comment)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail - since there is no comment field defined in the schema. This should be declared as Computed since it is set here.

@kwilczynski
Copy link
Contributor

@mathieuherbert hi there! Thank you for this! This is a highly desirable new data source.

I mean to send a Pull Request which adds such data source, but since you did it already, I will focus on helping you make yours amazing!

The output we would be aiming at is something along the lines of the following:

data.aws_route53_hosted_zone.example:
  id = hostedzone-475ac21f
  caller_reference = 2016-10-18T11:43:41.139220387+01:00
  comment = Managed by Terraform
  private_zone = true
  resource_record_set_count = 2
  zone_id = Z24ZQHYYGFIKHW
  zone_name = example.com
  vpc_id = vpc-47ba0223

Above shows a Hosted Zone which was found based on zone name and VPC ID, as per:

data "aws_route53_hosted_zone" "example" {
  zone_name = "example.com"
  vpc_id = "${aws_vpc.example.id}"
}

In other words, for this resource to be very useful, it should support:

  • Ability to pass either Hosted Zone ID or name
  • Ability to pass VPC ID, to allow for searches involving private zones
  • Ability to specify whether we are looking for a Private Zone by setting private_zone
    attribute accordingly (implied by specifying VPC ID)
  • Handle name with and without the trailing dot (e.g. example.com.)
  • Refresh data should attributes have changed
  • Handle the case where the list of Hosted Zones is truncated (and request needs to continue)
  • Return meaningful errors to the user

I will be more than happy to help you to get there.

@kwilczynski
Copy link
Contributor

Related to #9590.

}

// used to manage trailing .
func HostedZoneName(name string) string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea to have a helper, but few things to consider:

Have a look at the https://golang.org/pkg/strings/ package which is part of the Go's standard library, it should have the tools you need to add and/or remove a trailing dot.

Also, if you are not planning on making this method accessible outside of this package, it should by a convention (and also language mechanics) start with a lower-case letter, so that the symbol is not going to be exported. Albeit, the aws package (namespace) is large at the moment, nevertheless we should follow some common idioms.


`aws_hosted_zone` provides details about a specific Hosted Zone.

This resource can be useful when a module accepts a Hosted Zone name as
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably say "data source".

`aws_hosted_zone` provides details about a specific Hosted Zone.

This resource can be useful when a module accepts a Hosted Zone name as
an input variable and needs to, for example, add a Record Set in Route 53
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would mention that it allows to find Hosted Zone ID, which is often needed, given a Hosted Zone name and certain search criteria.

}
// We test that the first HZ is private or not, if it's not match the field private_zone, we test the second one
index := -1
if *resp.HostedZones[0].Config.PrivateZone == d.Get("private_zone") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might need to do d.Get("private_zone").(bool) in this case, as Get() and GetOk() both return interface{} when they return the value.

@mathieuherbert
Copy link
Contributor Author

Hi,
Thank you for you help, I really appreciate that.
I take your comments and I will put an other commit soon.
I just have an issue with the VPC ID. A private Hosted zone can be associate with multiple VPCs. So do we accept a list in input of the data source and a list also in the output? So the request will match if every VPCs are in hosted zone.
Thank you!

@kwilczynski
Copy link
Contributor

@mathieuherbert hi there! You are welcome!

I had a look at the changes and it looks good. I would have few suggestions to consider which might help with the VPC ID logic implementation - especially, since the ListHostedZones and ListHostedZonesByName do not carry the VPC details in the response data.

The search criteria are either:

  • Find Hosted Zone by name or by ID; and
  • Filter by whether it is private or not; and
  • Filter if associated with a particular VPC.

Also, only a Private Zone can have an association with a VPC, and it can only be associated once with a Hosted Zone that has unique name (domain name, if you wish). It can be associated with multiple Hosted Zones, but they need to have different name (which implies different Hosted Zone altogether; different ID).

Given the above, you could search for:

  1. A Public Hosted Zone based on a name or ID; or
  2. A Public Hosted Zone based on a name or ID with private_zone attribute set; or
  3. A Private Hosted Zone based on a name or ID; or
  4. A Private Hosted Zone based on a name or ID with private_zone attribute set; or
  5. A Private Hosted Zone based on a name or ID which is attached to a particular VPC.

Where the (2) and (3) probably makes little sense (especially (2) would yield empty results), rest of them are useful, especially concerning a scenario when people have multiple Private Hosted Zones that have the same name. One could also add region there as the filter to be able to only consider VPCs from current or given regions when looking them up.

This allows for removal of duplication around nameExists and idExists since a lot of the logic would result in getting a list of the Hosted Zones and then performing search on it to reduce the list to a single zone (the one we want to find).

Note, that you need only to fetch details about each and every zone only when match against a given VPC has to be performed.

I hope this helps! Let me know if you anything else - I am here to help.

@kwilczynski
Copy link
Contributor

Adding an example of what happens when you try to associate VPC with a different private hosted zone that has the same name as the one that already has VPC associated with it (since you can have multiple zones having the same name):

screen shot 2016-11-02 at 10 10 23

Thus, for a private zone, its name together with a VPC ID would be enough to identify it.

@radeksimko
Copy link
Member

Good work so far @mathieuherbert

I agree with @kwilczynski about the ambiguity of the zone - it may look like a 🐰 hole by now, but we do need to support VPC ID as a field. private_zone isn't sufficient.

Also I think we should not just simply take the 1st matching zone - as it may not be what the user wants. We should probably error out if we get >1 zones from the API and suggest the user to narrow down the search (e.g. by specifying VPC ID or other attributes).

A private Hosted zone can be associate with multiple VPCs. So do we accept a list in input of the data source and a list also in the output?

As @kwilczynski mentioned above you can have multiple private zones w/ the same name, but each zone would have 1-1 mapping between zone name - VPC ID - so there is hopefully no need to accept/output a list.

@kwilczynski
Copy link
Contributor

@mathieuherbert @radeksimko just to add, support for searching tags would also be nice (and might help resolve some of the issues around multiple zone with the same name).

@mathieuherbert
Copy link
Contributor Author

Thank you for the help.
I added the support of vpc_id. I don't have the time to add tags support today, but I hope to do that tomorrow.
I have a question, do you know why my tests are red (I think it's really simple but I don't understand) ?

Unchecked errors found in the following places:
builtin/providers/aws/data_source_aws_route53_zone.go:81:17:    errwrap.Wrapf("Error finding Route 53 Hosted Zone: {{err}}", err)

Thank you!

@mathieuherbert
Copy link
Contributor Author

In my last commit I added the support of tags

@mathieuherbert
Copy link
Contributor Author

Hi,
Any comments on my PR ?
Thank you :)

@devinsba
Copy link

Would be nice to output the NS records for the zone. We would use this for delegating zones from other zones and dns providers

@stack72
Copy link
Contributor

stack72 commented Dec 13, 2016

Hi @mathieuherbert

Thanks for all the work here - this LGTM! now :)

% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccDataSourceAwsRoute53Zone'
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2016/12/13 16:17:50 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccDataSourceAwsRoute53Zone -timeout 120m
=== RUN   TestAccDataSourceAwsRoute53Zone
--- PASS: TestAccDataSourceAwsRoute53Zone (78.35s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	78.374s

Paul

@stack72 stack72 merged commit 3239138 into hashicorp:master Dec 13, 2016
@ghost
Copy link

ghost commented Apr 18, 2020

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.

@ghost ghost locked and limited conversation to collaborators Apr 18, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants