provider/aws: data source for AWS Hosted Zone (#9766)
* provider/aws: data source for AWS Hosted Zone * add caller_reference, resource_record_set_count fields, manage private zone and trailing dot * fix fmt * update documentation, use string function in hostedZoneNamewq * add vpc_id support * add tags support * add documentation for hosted zone data source tags support
This commit is contained in:
parent
b2136beff2
commit
3239138099
|
@ -0,0 +1,176 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/service/route53"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourceAwsRoute53Zone() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Read: dataSourceAwsRoute53ZoneRead,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"zone_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"private_zone": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
},
|
||||||
|
"comment": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"caller_reference": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"vpc_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"tags": tagsSchemaComputed(),
|
||||||
|
"resource_record_set_count": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).r53conn
|
||||||
|
name, nameExists := d.GetOk("name")
|
||||||
|
name = hostedZoneName(name.(string))
|
||||||
|
id, idExists := d.GetOk("zone_id")
|
||||||
|
vpcId, vpcIdExists := d.GetOk("vpc_id")
|
||||||
|
tags := tagsFromMap(d.Get("tags").(map[string]interface{}))
|
||||||
|
if nameExists && idExists {
|
||||||
|
return fmt.Errorf("zone_id and name arguments can't be used together")
|
||||||
|
} else if !nameExists && !idExists {
|
||||||
|
return fmt.Errorf("Either name or zone_id must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextMarker *string
|
||||||
|
|
||||||
|
var hostedZoneFound *route53.HostedZone
|
||||||
|
// We loop through all hostedzone
|
||||||
|
for allHostedZoneListed := false; !allHostedZoneListed; {
|
||||||
|
req := &route53.ListHostedZonesInput{}
|
||||||
|
if nextMarker != nil {
|
||||||
|
req.Marker = nextMarker
|
||||||
|
}
|
||||||
|
resp, err := conn.ListHostedZones(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error finding Route 53 Hosted Zone: %v", err)
|
||||||
|
}
|
||||||
|
for _, hostedZone := range resp.HostedZones {
|
||||||
|
hostedZoneId := cleanZoneID(*hostedZone.Id)
|
||||||
|
if idExists && hostedZoneId == id.(string) {
|
||||||
|
hostedZoneFound = hostedZone
|
||||||
|
break
|
||||||
|
// we check if the name is the same as requested and if private zone field is the same as requested or if there is a vpc_id
|
||||||
|
} else if *hostedZone.Name == name && (*hostedZone.Config.PrivateZone == d.Get("private_zone").(bool) || (*hostedZone.Config.PrivateZone == true && vpcIdExists)) {
|
||||||
|
matchingVPC := false
|
||||||
|
if vpcIdExists {
|
||||||
|
reqHostedZone := &route53.GetHostedZoneInput{}
|
||||||
|
reqHostedZone.Id = aws.String(hostedZoneId)
|
||||||
|
|
||||||
|
respHostedZone, errHostedZone := conn.GetHostedZone(reqHostedZone)
|
||||||
|
if errHostedZone != nil {
|
||||||
|
return fmt.Errorf("Error finding Route 53 Hosted Zone: %v", errHostedZone)
|
||||||
|
}
|
||||||
|
// we go through all VPCs
|
||||||
|
for _, vpc := range respHostedZone.VPCs {
|
||||||
|
if *vpc.VPCId == vpcId.(string) {
|
||||||
|
matchingVPC = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
matchingVPC = true
|
||||||
|
}
|
||||||
|
// we check if tags match
|
||||||
|
matchingTags := true
|
||||||
|
if len(tags) > 0 {
|
||||||
|
reqListTags := &route53.ListTagsForResourceInput{}
|
||||||
|
reqListTags.ResourceId = aws.String(hostedZoneId)
|
||||||
|
reqListTags.ResourceType = aws.String("hostedzone")
|
||||||
|
respListTags, errListTags := conn.ListTagsForResource(reqListTags)
|
||||||
|
|
||||||
|
if errListTags != nil {
|
||||||
|
return fmt.Errorf("Error finding Route 53 Hosted Zone: %v", errListTags)
|
||||||
|
}
|
||||||
|
for _, tag := range tags {
|
||||||
|
found := false
|
||||||
|
for _, tagRequested := range respListTags.ResourceTagSet.Tags {
|
||||||
|
if *tag.Key == *tagRequested.Key && *tag.Value == *tagRequested.Value {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
matchingTags = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if matchingTags && matchingVPC {
|
||||||
|
if hostedZoneFound != nil {
|
||||||
|
return fmt.Errorf("multplie Route53Zone found please use vpc_id option to filter")
|
||||||
|
} else {
|
||||||
|
hostedZoneFound = hostedZone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if *resp.IsTruncated {
|
||||||
|
|
||||||
|
nextMarker = resp.NextMarker
|
||||||
|
} else {
|
||||||
|
allHostedZoneListed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hostedZoneFound == nil {
|
||||||
|
return fmt.Errorf("no matching Route53Zone found")
|
||||||
|
}
|
||||||
|
|
||||||
|
idHostedZone := cleanZoneID(*hostedZoneFound.Id)
|
||||||
|
d.SetId(idHostedZone)
|
||||||
|
d.Set("zone_id", idHostedZone)
|
||||||
|
d.Set("name", hostedZoneFound.Name)
|
||||||
|
d.Set("comment", hostedZoneFound.Config.Comment)
|
||||||
|
d.Set("private_zone", hostedZoneFound.Config.PrivateZone)
|
||||||
|
d.Set("caller_reference", hostedZoneFound.CallerReference)
|
||||||
|
d.Set("resource_record_set_count", hostedZoneFound.ResourceRecordSetCount)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// used to manage trailing .
|
||||||
|
func hostedZoneName(name string) string {
|
||||||
|
if strings.HasSuffix(name, ".") {
|
||||||
|
return name
|
||||||
|
} else {
|
||||||
|
return name + "."
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccDataSourceAwsRoute53Zone(t *testing.T) {
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccDataSourceAwsRoute53ZoneConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccDataSourceAwsRoute53ZoneCheck("data.aws_route53_zone.by_zone_id"),
|
||||||
|
testAccDataSourceAwsRoute53ZoneCheck("data.aws_route53_zone.by_name"),
|
||||||
|
testAccDataSourceAwsRoute53ZoneCheckPrivate("data.aws_route53_zone.by_vpc"),
|
||||||
|
testAccDataSourceAwsRoute53ZoneCheckPrivate("data.aws_route53_zone.by_tag"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccDataSourceAwsRoute53ZoneCheck(name string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[name]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("root module has no resource called %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostedZone, ok := s.RootModule().Resources["aws_route53_zone.test"]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("can't find aws_hosted_zone.test in state")
|
||||||
|
}
|
||||||
|
attr := rs.Primary.Attributes
|
||||||
|
if attr["id"] != hostedZone.Primary.Attributes["id"] {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"id is %s; want %s",
|
||||||
|
attr["id"],
|
||||||
|
hostedZone.Primary.Attributes["id"],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr["name"] != "terraformtestacchz.com." {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Route53 Zone name is %s; want terraformtestacchz.com.",
|
||||||
|
attr["name"],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccDataSourceAwsRoute53ZoneCheckPrivate(name string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[name]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("root module has no resource called %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostedZone, ok := s.RootModule().Resources["aws_route53_zone.test_private"]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("can't find aws_hosted_zone.test in state")
|
||||||
|
}
|
||||||
|
|
||||||
|
attr := rs.Primary.Attributes
|
||||||
|
if attr["id"] != hostedZone.Primary.Attributes["id"] {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"id is %s; want %s",
|
||||||
|
attr["id"],
|
||||||
|
hostedZone.Primary.Attributes["id"],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr["name"] != "test.acc." {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Route53 Zone name is %s; want test.acc.",
|
||||||
|
attr["name"],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccDataSourceAwsRoute53ZoneConfig = `
|
||||||
|
|
||||||
|
provider "aws" {
|
||||||
|
region = "us-east-2"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_vpc" "test" {
|
||||||
|
cidr_block = "172.16.0.0/16"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_zone" "test_private" {
|
||||||
|
name = "test.acc."
|
||||||
|
vpc_id = "${aws_vpc.test.id}"
|
||||||
|
tags {
|
||||||
|
Environment = "dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data "aws_route53_zone" "by_vpc" {
|
||||||
|
name = "${aws_route53_zone.test_private.name}"
|
||||||
|
vpc_id = "${aws_vpc.test.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_route53_zone" "by_tag" {
|
||||||
|
name = "${aws_route53_zone.test_private.name}"
|
||||||
|
private_zone = true
|
||||||
|
tags {
|
||||||
|
Environment = "dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_zone" "test" {
|
||||||
|
name = "terraformtestacchz.com."
|
||||||
|
}
|
||||||
|
data "aws_route53_zone" "by_zone_id" {
|
||||||
|
zone_id = "${aws_route53_zone.test.zone_id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_route53_zone" "by_name" {
|
||||||
|
name = "${data.aws_route53_zone.by_zone_id.name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
`
|
|
@ -157,6 +157,7 @@ func Provider() terraform.ResourceProvider {
|
||||||
"aws_ecs_container_definition": dataSourceAwsEcsContainerDefinition(),
|
"aws_ecs_container_definition": dataSourceAwsEcsContainerDefinition(),
|
||||||
"aws_eip": dataSourceAwsEip(),
|
"aws_eip": dataSourceAwsEip(),
|
||||||
"aws_elb_service_account": dataSourceAwsElbServiceAccount(),
|
"aws_elb_service_account": dataSourceAwsElbServiceAccount(),
|
||||||
|
"aws_route53_zone": dataSourceAwsRoute53Zone(),
|
||||||
"aws_iam_policy_document": dataSourceAwsIamPolicyDocument(),
|
"aws_iam_policy_document": dataSourceAwsIamPolicyDocument(),
|
||||||
"aws_iam_server_certificate": dataSourceAwsIAMServerCertificate(),
|
"aws_iam_server_certificate": dataSourceAwsIAMServerCertificate(),
|
||||||
"aws_ip_ranges": dataSourceAwsIPRanges(),
|
"aws_ip_ranges": dataSourceAwsIPRanges(),
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: aws_hosted_zone"
|
||||||
|
sidebar_current: "docs-aws-datasource-hosted-zone"
|
||||||
|
description: |-
|
||||||
|
Provides details about a specific Hosted Zone
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_hosted\_zone
|
||||||
|
|
||||||
|
`aws_hosted_zone` provides details about a specific Hosted Zone.
|
||||||
|
|
||||||
|
This data source allows to find a Hosted Zone ID given Hosted Zone name and certain search criteria.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
The following example shows how to get a Hosted Zone from it's name and from this data how to create a Record Set.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
data "aws_route53_zone" "selected" {
|
||||||
|
name = "test.com."
|
||||||
|
private_zone = true
|
||||||
|
}
|
||||||
|
|
||||||
|
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"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The arguments of this data source act as filters for querying the available
|
||||||
|
Hosted Zone. You have to use `zone_id` or `name`, not both of them. The given filter must match exactly one
|
||||||
|
Hosted Zone. If you use `name` field for private Hosted Zone, you need to add `private_zone` field to `true`
|
||||||
|
|
||||||
|
* `zone_id` - (Optional) The Hosted Zone id of the desired Hosted Zone.
|
||||||
|
|
||||||
|
* `name` - (Optional) The Hosted Zone name of the desired Hosted Zone.
|
||||||
|
* `private_zone` - (Optional) Used with `name` field to get a private Hosted Zone.
|
||||||
|
* `vpc_id` - (Optional) Used with `name` field to get a private Hosted Zone associated with the vpc_id (in this case, private_zone is not mandatory).
|
||||||
|
* `tags` - (Optional) Used with `name` field. A mapping of tags, each pair of which must exactly match
|
||||||
|
a pair on the desired security group.
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
All of the argument attributes are also exported as
|
||||||
|
result attributes. This data source will complete the data by populating
|
||||||
|
any fields that are not included in the configuration with the data for
|
||||||
|
the selected Hosted Zone.
|
||||||
|
|
||||||
|
The following attribute is additionally exported:
|
||||||
|
|
||||||
|
* `caller_reference` - Caller Reference of the Hosted Zone.
|
||||||
|
* `comment` - The comment field of the Hosted Zone.
|
||||||
|
* `resource_record_set_count` - the number of Record Set in the Hosted Zone
|
|
@ -51,6 +51,9 @@
|
||||||
<li<%= sidebar_current("docs-aws-datasource-elb-service-account") %>>
|
<li<%= sidebar_current("docs-aws-datasource-elb-service-account") %>>
|
||||||
<a href="/docs/providers/aws/d/elb_service_account.html">aws_elb_service_account</a>
|
<a href="/docs/providers/aws/d/elb_service_account.html">aws_elb_service_account</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-aws-datasource-hosted-zone") %>>
|
||||||
|
<a href="/docs/providers/aws/d/hosted_zone.html">aws_hosted_zone</a>
|
||||||
|
</li>
|
||||||
<li<%= sidebar_current("docs-aws-datasource-iam-policy-document") %>>
|
<li<%= sidebar_current("docs-aws-datasource-iam-policy-document") %>>
|
||||||
<a href="/docs/providers/aws/d/iam_policy_document.html">aws_iam_policy_document</a>
|
<a href="/docs/providers/aws/d/iam_policy_document.html">aws_iam_policy_document</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Reference in New Issue