github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_route53_zone_test.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"sort"
     7  	"testing"
     8  
     9  	"github.com/hashicorp/terraform/helper/acctest"
    10  	"github.com/hashicorp/terraform/helper/resource"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  	"github.com/hashicorp/terraform/terraform"
    13  
    14  	"github.com/aws/aws-sdk-go/aws"
    15  	"github.com/aws/aws-sdk-go/service/route53"
    16  )
    17  
    18  func TestCleanPrefix(t *testing.T) {
    19  	cases := []struct {
    20  		Input, Prefix, Output string
    21  	}{
    22  		{"/hostedzone/foo", "/hostedzone/", "foo"},
    23  		{"/change/foo", "/change/", "foo"},
    24  		{"/bar", "/test", "/bar"},
    25  	}
    26  
    27  	for _, tc := range cases {
    28  		actual := cleanPrefix(tc.Input, tc.Prefix)
    29  		if actual != tc.Output {
    30  			t.Fatalf("input: %s\noutput: %s", tc.Input, actual)
    31  		}
    32  	}
    33  }
    34  
    35  func TestCleanZoneID(t *testing.T) {
    36  	cases := []struct {
    37  		Input, Output string
    38  	}{
    39  		{"/hostedzone/foo", "foo"},
    40  		{"/change/foo", "/change/foo"},
    41  		{"/bar", "/bar"},
    42  	}
    43  
    44  	for _, tc := range cases {
    45  		actual := cleanZoneID(tc.Input)
    46  		if actual != tc.Output {
    47  			t.Fatalf("input: %s\noutput: %s", tc.Input, actual)
    48  		}
    49  	}
    50  }
    51  
    52  func TestCleanChangeID(t *testing.T) {
    53  	cases := []struct {
    54  		Input, Output string
    55  	}{
    56  		{"/hostedzone/foo", "/hostedzone/foo"},
    57  		{"/change/foo", "foo"},
    58  		{"/bar", "/bar"},
    59  	}
    60  
    61  	for _, tc := range cases {
    62  		actual := cleanChangeID(tc.Input)
    63  		if actual != tc.Output {
    64  			t.Fatalf("input: %s\noutput: %s", tc.Input, actual)
    65  		}
    66  	}
    67  }
    68  
    69  func TestAccAWSRoute53Zone_basic(t *testing.T) {
    70  	var zone route53.GetHostedZoneOutput
    71  	var td route53.ResourceTagSet
    72  
    73  	resource.Test(t, resource.TestCase{
    74  		PreCheck:      func() { testAccPreCheck(t) },
    75  		IDRefreshName: "aws_route53_zone.main",
    76  		Providers:     testAccProviders,
    77  		CheckDestroy:  testAccCheckRoute53ZoneDestroy,
    78  		Steps: []resource.TestStep{
    79  			resource.TestStep{
    80  				Config: testAccRoute53ZoneConfig,
    81  				Check: resource.ComposeTestCheckFunc(
    82  					testAccCheckRoute53ZoneExists("aws_route53_zone.main", &zone),
    83  					testAccLoadTagsR53(&zone, &td),
    84  					testAccCheckTagsR53(&td.Tags, "foo", "bar"),
    85  				),
    86  			},
    87  		},
    88  	})
    89  }
    90  
    91  func TestAccAWSRoute53Zone_forceDestroy(t *testing.T) {
    92  	var zone, zoneWithDot route53.GetHostedZoneOutput
    93  
    94  	// record the initialized providers so that we can use them to
    95  	// check for the instances in each region
    96  	var providers []*schema.Provider
    97  	providerFactories := map[string]terraform.ResourceProviderFactory{
    98  		"aws": func() (terraform.ResourceProvider, error) {
    99  			p := Provider()
   100  			providers = append(providers, p.(*schema.Provider))
   101  			return p, nil
   102  		},
   103  	}
   104  
   105  	resource.Test(t, resource.TestCase{
   106  		PreCheck:          func() { testAccPreCheck(t) },
   107  		IDRefreshName:     "aws_route53_zone.destroyable",
   108  		ProviderFactories: providerFactories,
   109  		CheckDestroy:      testAccCheckRoute53ZoneDestroyWithProviders(&providers),
   110  		Steps: []resource.TestStep{
   111  			resource.TestStep{
   112  				Config: testAccRoute53ZoneConfig_forceDestroy,
   113  				Check: resource.ComposeTestCheckFunc(
   114  					testAccCheckRoute53ZoneExistsWithProviders("aws_route53_zone.destroyable", &zone, &providers),
   115  					// Add >100 records to verify pagination works ok
   116  					testAccCreateRandomRoute53RecordsInZoneIdWithProviders(&providers, &zone, 100),
   117  					testAccCreateRandomRoute53RecordsInZoneIdWithProviders(&providers, &zone, 5),
   118  
   119  					testAccCheckRoute53ZoneExistsWithProviders("aws_route53_zone.with_trailing_dot", &zoneWithDot, &providers),
   120  					// Add >100 records to verify pagination works ok
   121  					testAccCreateRandomRoute53RecordsInZoneIdWithProviders(&providers, &zoneWithDot, 100),
   122  					testAccCreateRandomRoute53RecordsInZoneIdWithProviders(&providers, &zoneWithDot, 5),
   123  				),
   124  			},
   125  		},
   126  	})
   127  }
   128  
   129  func TestAccAWSRoute53Zone_updateComment(t *testing.T) {
   130  	var zone route53.GetHostedZoneOutput
   131  	var td route53.ResourceTagSet
   132  
   133  	resource.Test(t, resource.TestCase{
   134  		PreCheck:      func() { testAccPreCheck(t) },
   135  		IDRefreshName: "aws_route53_zone.main",
   136  		Providers:     testAccProviders,
   137  		CheckDestroy:  testAccCheckRoute53ZoneDestroy,
   138  		Steps: []resource.TestStep{
   139  			resource.TestStep{
   140  				Config: testAccRoute53ZoneConfig,
   141  				Check: resource.ComposeTestCheckFunc(
   142  					testAccCheckRoute53ZoneExists("aws_route53_zone.main", &zone),
   143  					testAccLoadTagsR53(&zone, &td),
   144  					testAccCheckTagsR53(&td.Tags, "foo", "bar"),
   145  					resource.TestCheckResourceAttr(
   146  						"aws_route53_zone.main", "comment", "Custom comment"),
   147  				),
   148  			},
   149  
   150  			resource.TestStep{
   151  				Config: testAccRoute53ZoneConfigUpdateComment,
   152  				Check: resource.ComposeTestCheckFunc(
   153  					testAccCheckRoute53ZoneExists("aws_route53_zone.main", &zone),
   154  					testAccLoadTagsR53(&zone, &td),
   155  					resource.TestCheckResourceAttr(
   156  						"aws_route53_zone.main", "comment", "Change Custom Comment"),
   157  				),
   158  			},
   159  		},
   160  	})
   161  }
   162  
   163  func TestAccAWSRoute53Zone_private_basic(t *testing.T) {
   164  	var zone route53.GetHostedZoneOutput
   165  
   166  	resource.Test(t, resource.TestCase{
   167  		PreCheck:      func() { testAccPreCheck(t) },
   168  		IDRefreshName: "aws_route53_zone.main",
   169  		Providers:     testAccProviders,
   170  		CheckDestroy:  testAccCheckRoute53ZoneDestroy,
   171  		Steps: []resource.TestStep{
   172  			resource.TestStep{
   173  				Config: testAccRoute53PrivateZoneConfig,
   174  				Check: resource.ComposeTestCheckFunc(
   175  					testAccCheckRoute53ZoneExists("aws_route53_zone.main", &zone),
   176  					testAccCheckRoute53ZoneAssociatesWithVpc("aws_vpc.main", &zone),
   177  				),
   178  			},
   179  		},
   180  	})
   181  }
   182  
   183  func TestAccAWSRoute53Zone_private_region(t *testing.T) {
   184  	var zone route53.GetHostedZoneOutput
   185  
   186  	// record the initialized providers so that we can use them to
   187  	// check for the instances in each region
   188  	var providers []*schema.Provider
   189  	providerFactories := map[string]terraform.ResourceProviderFactory{
   190  		"aws": func() (terraform.ResourceProvider, error) {
   191  			p := Provider()
   192  			providers = append(providers, p.(*schema.Provider))
   193  			return p, nil
   194  		},
   195  	}
   196  
   197  	resource.Test(t, resource.TestCase{
   198  		PreCheck:          func() { testAccPreCheck(t) },
   199  		IDRefreshName:     "aws_route53_zone.main",
   200  		ProviderFactories: providerFactories,
   201  		CheckDestroy:      testAccCheckRoute53ZoneDestroyWithProviders(&providers),
   202  		Steps: []resource.TestStep{
   203  			resource.TestStep{
   204  				Config: testAccRoute53PrivateZoneRegionConfig,
   205  				Check: resource.ComposeTestCheckFunc(
   206  					testAccCheckRoute53ZoneExistsWithProviders("aws_route53_zone.main", &zone, &providers),
   207  					testAccCheckRoute53ZoneAssociatesWithVpc("aws_vpc.main", &zone),
   208  				),
   209  			},
   210  		},
   211  	})
   212  }
   213  
   214  func testAccCheckRoute53ZoneDestroy(s *terraform.State) error {
   215  	return testAccCheckRoute53ZoneDestroyWithProvider(s, testAccProvider)
   216  }
   217  
   218  func testAccCheckRoute53ZoneDestroyWithProviders(providers *[]*schema.Provider) resource.TestCheckFunc {
   219  	return func(s *terraform.State) error {
   220  		for _, provider := range *providers {
   221  			if provider.Meta() == nil {
   222  				continue
   223  			}
   224  			if err := testAccCheckRoute53ZoneDestroyWithProvider(s, provider); err != nil {
   225  				return err
   226  			}
   227  		}
   228  		return nil
   229  	}
   230  }
   231  
   232  func testAccCheckRoute53ZoneDestroyWithProvider(s *terraform.State, provider *schema.Provider) error {
   233  	conn := provider.Meta().(*AWSClient).r53conn
   234  	for _, rs := range s.RootModule().Resources {
   235  		if rs.Type != "aws_route53_zone" {
   236  			continue
   237  		}
   238  
   239  		_, err := conn.GetHostedZone(&route53.GetHostedZoneInput{Id: aws.String(rs.Primary.ID)})
   240  		if err == nil {
   241  			return fmt.Errorf("Hosted zone still exists")
   242  		}
   243  	}
   244  	return nil
   245  }
   246  
   247  func testAccCreateRandomRoute53RecordsInZoneIdWithProviders(providers *[]*schema.Provider,
   248  	zone *route53.GetHostedZoneOutput, recordsCount int) resource.TestCheckFunc {
   249  	return func(s *terraform.State) error {
   250  		for _, provider := range *providers {
   251  			if provider.Meta() == nil {
   252  				continue
   253  			}
   254  			if err := testAccCreateRandomRoute53RecordsInZoneId(provider, zone, recordsCount); err != nil {
   255  				return err
   256  			}
   257  		}
   258  		return nil
   259  	}
   260  }
   261  
   262  func testAccCreateRandomRoute53RecordsInZoneId(provider *schema.Provider, zone *route53.GetHostedZoneOutput, recordsCount int) error {
   263  	conn := provider.Meta().(*AWSClient).r53conn
   264  
   265  	var changes []*route53.Change
   266  	if recordsCount > 100 {
   267  		return fmt.Errorf("Route53 API only allows 100 record sets in a single batch")
   268  	}
   269  	for i := 0; i < recordsCount; i++ {
   270  		changes = append(changes, &route53.Change{
   271  			Action: aws.String("UPSERT"),
   272  			ResourceRecordSet: &route53.ResourceRecordSet{
   273  				Name: aws.String(fmt.Sprintf("%d-tf-acc-random.%s", acctest.RandInt(), *zone.HostedZone.Name)),
   274  				Type: aws.String("CNAME"),
   275  				ResourceRecords: []*route53.ResourceRecord{
   276  					&route53.ResourceRecord{Value: aws.String(fmt.Sprintf("random.%s", *zone.HostedZone.Name))},
   277  				},
   278  				TTL: aws.Int64(int64(30)),
   279  			},
   280  		})
   281  	}
   282  
   283  	req := &route53.ChangeResourceRecordSetsInput{
   284  		HostedZoneId: zone.HostedZone.Id,
   285  		ChangeBatch: &route53.ChangeBatch{
   286  			Comment: aws.String("Generated by Terraform"),
   287  			Changes: changes,
   288  		},
   289  	}
   290  	log.Printf("[DEBUG] Change set: %s\n", *req)
   291  	resp, err := changeRoute53RecordSet(conn, req)
   292  	if err != nil {
   293  		return err
   294  	}
   295  	changeInfo := resp.(*route53.ChangeResourceRecordSetsOutput).ChangeInfo
   296  	err = waitForRoute53RecordSetToSync(conn, cleanChangeID(*changeInfo.Id))
   297  	return err
   298  }
   299  
   300  func testAccCheckRoute53ZoneExists(n string, zone *route53.GetHostedZoneOutput) resource.TestCheckFunc {
   301  	return func(s *terraform.State) error {
   302  		return testAccCheckRoute53ZoneExistsWithProvider(s, n, zone, testAccProvider)
   303  	}
   304  }
   305  
   306  func testAccCheckRoute53ZoneExistsWithProviders(n string, zone *route53.GetHostedZoneOutput, providers *[]*schema.Provider) resource.TestCheckFunc {
   307  	return func(s *terraform.State) error {
   308  		for _, provider := range *providers {
   309  			if provider.Meta() == nil {
   310  				continue
   311  			}
   312  			if err := testAccCheckRoute53ZoneExistsWithProvider(s, n, zone, provider); err != nil {
   313  				return err
   314  			}
   315  		}
   316  		return nil
   317  	}
   318  }
   319  
   320  func testAccCheckRoute53ZoneExistsWithProvider(s *terraform.State, n string, zone *route53.GetHostedZoneOutput, provider *schema.Provider) error {
   321  	rs, ok := s.RootModule().Resources[n]
   322  	if !ok {
   323  		return fmt.Errorf("Not found: %s", n)
   324  	}
   325  
   326  	if rs.Primary.ID == "" {
   327  		return fmt.Errorf("No hosted zone ID is set")
   328  	}
   329  
   330  	conn := provider.Meta().(*AWSClient).r53conn
   331  	resp, err := conn.GetHostedZone(&route53.GetHostedZoneInput{Id: aws.String(rs.Primary.ID)})
   332  	if err != nil {
   333  		return fmt.Errorf("Hosted zone err: %v", err)
   334  	}
   335  
   336  	aws_comment := *resp.HostedZone.Config.Comment
   337  	rs_comment := rs.Primary.Attributes["comment"]
   338  	if rs_comment != "" && rs_comment != aws_comment {
   339  		return fmt.Errorf("Hosted zone with comment '%s' found but does not match '%s'", aws_comment, rs_comment)
   340  	}
   341  
   342  	if !*resp.HostedZone.Config.PrivateZone {
   343  		sorted_ns := make([]string, len(resp.DelegationSet.NameServers))
   344  		for i, ns := range resp.DelegationSet.NameServers {
   345  			sorted_ns[i] = *ns
   346  		}
   347  		sort.Strings(sorted_ns)
   348  		for idx, ns := range sorted_ns {
   349  			attribute := fmt.Sprintf("name_servers.%d", idx)
   350  			dsns := rs.Primary.Attributes[attribute]
   351  			if dsns != ns {
   352  				return fmt.Errorf("Got: %v for %v, Expected: %v", dsns, attribute, ns)
   353  			}
   354  		}
   355  	}
   356  
   357  	*zone = *resp
   358  	return nil
   359  }
   360  
   361  func testAccCheckRoute53ZoneAssociatesWithVpc(n string, zone *route53.GetHostedZoneOutput) resource.TestCheckFunc {
   362  	return func(s *terraform.State) error {
   363  		rs, ok := s.RootModule().Resources[n]
   364  		if !ok {
   365  			return fmt.Errorf("Not found: %s", n)
   366  		}
   367  
   368  		if rs.Primary.ID == "" {
   369  			return fmt.Errorf("No VPC ID is set")
   370  		}
   371  
   372  		var associatedVPC *route53.VPC
   373  		for _, vpc := range zone.VPCs {
   374  			if *vpc.VPCId == rs.Primary.ID {
   375  				associatedVPC = vpc
   376  			}
   377  		}
   378  		if associatedVPC == nil {
   379  			return fmt.Errorf("VPC: %v is not associated to Zone: %v", n, cleanZoneID(*zone.HostedZone.Id))
   380  		}
   381  		return nil
   382  	}
   383  }
   384  
   385  func testAccLoadTagsR53(zone *route53.GetHostedZoneOutput, td *route53.ResourceTagSet) resource.TestCheckFunc {
   386  	return func(s *terraform.State) error {
   387  		conn := testAccProvider.Meta().(*AWSClient).r53conn
   388  
   389  		zone := cleanZoneID(*zone.HostedZone.Id)
   390  		req := &route53.ListTagsForResourceInput{
   391  			ResourceId:   aws.String(zone),
   392  			ResourceType: aws.String("hostedzone"),
   393  		}
   394  
   395  		resp, err := conn.ListTagsForResource(req)
   396  		if err != nil {
   397  			return err
   398  		}
   399  
   400  		if resp.ResourceTagSet != nil {
   401  			*td = *resp.ResourceTagSet
   402  		}
   403  
   404  		return nil
   405  	}
   406  }
   407  
   408  const testAccRoute53ZoneConfig = `
   409  resource "aws_route53_zone" "main" {
   410  	name = "hashicorp.com."
   411  	comment = "Custom comment"
   412  
   413  	tags {
   414  		foo = "bar"
   415  		Name = "tf-route53-tag-test"
   416  	}
   417  }
   418  `
   419  
   420  const testAccRoute53ZoneConfig_forceDestroy = `
   421  resource "aws_route53_zone" "destroyable" {
   422  	name = "terraform.io"
   423  	force_destroy = true
   424  }
   425  
   426  resource "aws_route53_zone" "with_trailing_dot" {
   427  	name = "hashicorptest.io."
   428  	force_destroy = true
   429  }
   430  `
   431  
   432  const testAccRoute53ZoneConfigUpdateComment = `
   433  resource "aws_route53_zone" "main" {
   434  	name = "hashicorp.com."
   435  	comment = "Change Custom Comment"
   436  
   437  	tags {
   438  		foo = "bar"
   439  		Name = "tf-route53-tag-test"
   440  	}
   441  }
   442  `
   443  
   444  const testAccRoute53PrivateZoneConfig = `
   445  resource "aws_vpc" "main" {
   446  	cidr_block = "172.29.0.0/24"
   447  	instance_tenancy = "default"
   448  	enable_dns_support = true
   449  	enable_dns_hostnames = true
   450  }
   451  
   452  resource "aws_route53_zone" "main" {
   453  	name = "hashicorp.com."
   454  	vpc_id = "${aws_vpc.main.id}"
   455  }
   456  `
   457  
   458  const testAccRoute53PrivateZoneRegionConfig = `
   459  provider "aws" {
   460  	alias = "west"
   461  	region = "us-west-2"
   462  }
   463  
   464  provider "aws" {
   465  	alias = "east"
   466  	region = "us-east-1"
   467  }
   468  
   469  resource "aws_vpc" "main" {
   470  	provider = "aws.east"
   471  	cidr_block = "172.29.0.0/24"
   472  	instance_tenancy = "default"
   473  	enable_dns_support = true
   474  	enable_dns_hostnames = true
   475  }
   476  
   477  resource "aws_route53_zone" "main" {
   478  	provider = "aws.west"
   479  	name = "hashicorp.com."
   480  	vpc_id = "${aws_vpc.main.id}"
   481  	vpc_region = "us-east-1"
   482  }
   483  `