github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/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 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  			},
   120  		},
   121  	})
   122  }
   123  
   124  func TestAccAWSRoute53Zone_updateComment(t *testing.T) {
   125  	var zone route53.GetHostedZoneOutput
   126  	var td route53.ResourceTagSet
   127  
   128  	resource.Test(t, resource.TestCase{
   129  		PreCheck:      func() { testAccPreCheck(t) },
   130  		IDRefreshName: "aws_route53_zone.main",
   131  		Providers:     testAccProviders,
   132  		CheckDestroy:  testAccCheckRoute53ZoneDestroy,
   133  		Steps: []resource.TestStep{
   134  			resource.TestStep{
   135  				Config: testAccRoute53ZoneConfig,
   136  				Check: resource.ComposeTestCheckFunc(
   137  					testAccCheckRoute53ZoneExists("aws_route53_zone.main", &zone),
   138  					testAccLoadTagsR53(&zone, &td),
   139  					testAccCheckTagsR53(&td.Tags, "foo", "bar"),
   140  					resource.TestCheckResourceAttr(
   141  						"aws_route53_zone.main", "comment", "Custom comment"),
   142  				),
   143  			},
   144  
   145  			resource.TestStep{
   146  				Config: testAccRoute53ZoneConfigUpdateComment,
   147  				Check: resource.ComposeTestCheckFunc(
   148  					testAccCheckRoute53ZoneExists("aws_route53_zone.main", &zone),
   149  					testAccLoadTagsR53(&zone, &td),
   150  					resource.TestCheckResourceAttr(
   151  						"aws_route53_zone.main", "comment", "Change Custom Comment"),
   152  				),
   153  			},
   154  		},
   155  	})
   156  }
   157  
   158  func TestAccAWSRoute53Zone_private_basic(t *testing.T) {
   159  	var zone route53.GetHostedZoneOutput
   160  
   161  	resource.Test(t, resource.TestCase{
   162  		PreCheck:      func() { testAccPreCheck(t) },
   163  		IDRefreshName: "aws_route53_zone.main",
   164  		Providers:     testAccProviders,
   165  		CheckDestroy:  testAccCheckRoute53ZoneDestroy,
   166  		Steps: []resource.TestStep{
   167  			resource.TestStep{
   168  				Config: testAccRoute53PrivateZoneConfig,
   169  				Check: resource.ComposeTestCheckFunc(
   170  					testAccCheckRoute53ZoneExists("aws_route53_zone.main", &zone),
   171  					testAccCheckRoute53ZoneAssociatesWithVpc("aws_vpc.main", &zone),
   172  				),
   173  			},
   174  		},
   175  	})
   176  }
   177  
   178  func TestAccAWSRoute53Zone_private_region(t *testing.T) {
   179  	var zone route53.GetHostedZoneOutput
   180  
   181  	// record the initialized providers so that we can use them to
   182  	// check for the instances in each region
   183  	var providers []*schema.Provider
   184  	providerFactories := map[string]terraform.ResourceProviderFactory{
   185  		"aws": func() (terraform.ResourceProvider, error) {
   186  			p := Provider()
   187  			providers = append(providers, p.(*schema.Provider))
   188  			return p, nil
   189  		},
   190  	}
   191  
   192  	resource.Test(t, resource.TestCase{
   193  		PreCheck:          func() { testAccPreCheck(t) },
   194  		IDRefreshName:     "aws_route53_zone.main",
   195  		ProviderFactories: providerFactories,
   196  		CheckDestroy:      testAccCheckRoute53ZoneDestroyWithProviders(&providers),
   197  		Steps: []resource.TestStep{
   198  			resource.TestStep{
   199  				Config: testAccRoute53PrivateZoneRegionConfig,
   200  				Check: resource.ComposeTestCheckFunc(
   201  					testAccCheckRoute53ZoneExistsWithProviders("aws_route53_zone.main", &zone, &providers),
   202  					testAccCheckRoute53ZoneAssociatesWithVpc("aws_vpc.main", &zone),
   203  				),
   204  			},
   205  		},
   206  	})
   207  }
   208  
   209  func testAccCheckRoute53ZoneDestroy(s *terraform.State) error {
   210  	return testAccCheckRoute53ZoneDestroyWithProvider(s, testAccProvider)
   211  }
   212  
   213  func testAccCheckRoute53ZoneDestroyWithProviders(providers *[]*schema.Provider) resource.TestCheckFunc {
   214  	return func(s *terraform.State) error {
   215  		for _, provider := range *providers {
   216  			if provider.Meta() == nil {
   217  				continue
   218  			}
   219  			if err := testAccCheckRoute53ZoneDestroyWithProvider(s, provider); err != nil {
   220  				return err
   221  			}
   222  		}
   223  		return nil
   224  	}
   225  }
   226  
   227  func testAccCheckRoute53ZoneDestroyWithProvider(s *terraform.State, provider *schema.Provider) error {
   228  	conn := provider.Meta().(*AWSClient).r53conn
   229  	for _, rs := range s.RootModule().Resources {
   230  		if rs.Type != "aws_route53_zone" {
   231  			continue
   232  		}
   233  
   234  		_, err := conn.GetHostedZone(&route53.GetHostedZoneInput{Id: aws.String(rs.Primary.ID)})
   235  		if err == nil {
   236  			return fmt.Errorf("Hosted zone still exists")
   237  		}
   238  	}
   239  	return nil
   240  }
   241  
   242  func testAccCreateRandomRoute53RecordsInZoneIdWithProviders(providers *[]*schema.Provider,
   243  	zone *route53.GetHostedZoneOutput, recordsCount int) resource.TestCheckFunc {
   244  	return func(s *terraform.State) error {
   245  		for _, provider := range *providers {
   246  			if provider.Meta() == nil {
   247  				continue
   248  			}
   249  			if err := testAccCreateRandomRoute53RecordsInZoneId(provider, zone, recordsCount); err != nil {
   250  				return err
   251  			}
   252  		}
   253  		return nil
   254  	}
   255  }
   256  
   257  func testAccCreateRandomRoute53RecordsInZoneId(provider *schema.Provider, zone *route53.GetHostedZoneOutput, recordsCount int) error {
   258  	conn := provider.Meta().(*AWSClient).r53conn
   259  
   260  	var changes []*route53.Change
   261  	if recordsCount > 100 {
   262  		return fmt.Errorf("Route53 API only allows 100 record sets in a single batch")
   263  	}
   264  	for i := 0; i < recordsCount; i++ {
   265  		changes = append(changes, &route53.Change{
   266  			Action: aws.String("UPSERT"),
   267  			ResourceRecordSet: &route53.ResourceRecordSet{
   268  				Name: aws.String(fmt.Sprintf("%d-tf-acc-random.%s", acctest.RandInt(), *zone.HostedZone.Name)),
   269  				Type: aws.String("CNAME"),
   270  				ResourceRecords: []*route53.ResourceRecord{
   271  					&route53.ResourceRecord{Value: aws.String(fmt.Sprintf("random.%s", *zone.HostedZone.Name))},
   272  				},
   273  				TTL: aws.Int64(int64(30)),
   274  			},
   275  		})
   276  	}
   277  
   278  	req := &route53.ChangeResourceRecordSetsInput{
   279  		HostedZoneId: zone.HostedZone.Id,
   280  		ChangeBatch: &route53.ChangeBatch{
   281  			Comment: aws.String("Generated by Terraform"),
   282  			Changes: changes,
   283  		},
   284  	}
   285  	log.Printf("[DEBUG] Change set: %s\n", *req)
   286  	resp, err := changeRoute53RecordSet(conn, req)
   287  	if err != nil {
   288  		return err
   289  	}
   290  	changeInfo := resp.(*route53.ChangeResourceRecordSetsOutput).ChangeInfo
   291  	err = waitForRoute53RecordSetToSync(conn, cleanChangeID(*changeInfo.Id))
   292  	return err
   293  }
   294  
   295  func testAccCheckRoute53ZoneExists(n string, zone *route53.GetHostedZoneOutput) resource.TestCheckFunc {
   296  	return func(s *terraform.State) error {
   297  		return testAccCheckRoute53ZoneExistsWithProvider(s, n, zone, testAccProvider)
   298  	}
   299  }
   300  
   301  func testAccCheckRoute53ZoneExistsWithProviders(n string, zone *route53.GetHostedZoneOutput, providers *[]*schema.Provider) resource.TestCheckFunc {
   302  	return func(s *terraform.State) error {
   303  		for _, provider := range *providers {
   304  			if provider.Meta() == nil {
   305  				continue
   306  			}
   307  			if err := testAccCheckRoute53ZoneExistsWithProvider(s, n, zone, provider); err != nil {
   308  				return err
   309  			}
   310  		}
   311  		return nil
   312  	}
   313  }
   314  
   315  func testAccCheckRoute53ZoneExistsWithProvider(s *terraform.State, n string, zone *route53.GetHostedZoneOutput, provider *schema.Provider) error {
   316  	rs, ok := s.RootModule().Resources[n]
   317  	if !ok {
   318  		return fmt.Errorf("Not found: %s", n)
   319  	}
   320  
   321  	if rs.Primary.ID == "" {
   322  		return fmt.Errorf("No hosted zone ID is set")
   323  	}
   324  
   325  	conn := provider.Meta().(*AWSClient).r53conn
   326  	resp, err := conn.GetHostedZone(&route53.GetHostedZoneInput{Id: aws.String(rs.Primary.ID)})
   327  	if err != nil {
   328  		return fmt.Errorf("Hosted zone err: %v", err)
   329  	}
   330  
   331  	aws_comment := *resp.HostedZone.Config.Comment
   332  	rs_comment := rs.Primary.Attributes["comment"]
   333  	if rs_comment != "" && rs_comment != aws_comment {
   334  		return fmt.Errorf("Hosted zone with comment '%s' found but does not match '%s'", aws_comment, rs_comment)
   335  	}
   336  
   337  	if !*resp.HostedZone.Config.PrivateZone {
   338  		sorted_ns := make([]string, len(resp.DelegationSet.NameServers))
   339  		for i, ns := range resp.DelegationSet.NameServers {
   340  			sorted_ns[i] = *ns
   341  		}
   342  		sort.Strings(sorted_ns)
   343  		for idx, ns := range sorted_ns {
   344  			attribute := fmt.Sprintf("name_servers.%d", idx)
   345  			dsns := rs.Primary.Attributes[attribute]
   346  			if dsns != ns {
   347  				return fmt.Errorf("Got: %v for %v, Expected: %v", dsns, attribute, ns)
   348  			}
   349  		}
   350  	}
   351  
   352  	*zone = *resp
   353  	return nil
   354  }
   355  
   356  func testAccCheckRoute53ZoneAssociatesWithVpc(n string, zone *route53.GetHostedZoneOutput) resource.TestCheckFunc {
   357  	return func(s *terraform.State) error {
   358  		rs, ok := s.RootModule().Resources[n]
   359  		if !ok {
   360  			return fmt.Errorf("Not found: %s", n)
   361  		}
   362  
   363  		if rs.Primary.ID == "" {
   364  			return fmt.Errorf("No VPC ID is set")
   365  		}
   366  
   367  		var associatedVPC *route53.VPC
   368  		for _, vpc := range zone.VPCs {
   369  			if *vpc.VPCId == rs.Primary.ID {
   370  				associatedVPC = vpc
   371  			}
   372  		}
   373  		if associatedVPC == nil {
   374  			return fmt.Errorf("VPC: %v is not associated to Zone: %v", n, cleanZoneID(*zone.HostedZone.Id))
   375  		}
   376  		return nil
   377  	}
   378  }
   379  
   380  func testAccLoadTagsR53(zone *route53.GetHostedZoneOutput, td *route53.ResourceTagSet) resource.TestCheckFunc {
   381  	return func(s *terraform.State) error {
   382  		conn := testAccProvider.Meta().(*AWSClient).r53conn
   383  
   384  		zone := cleanZoneID(*zone.HostedZone.Id)
   385  		req := &route53.ListTagsForResourceInput{
   386  			ResourceId:   aws.String(zone),
   387  			ResourceType: aws.String("hostedzone"),
   388  		}
   389  
   390  		resp, err := conn.ListTagsForResource(req)
   391  		if err != nil {
   392  			return err
   393  		}
   394  
   395  		if resp.ResourceTagSet != nil {
   396  			*td = *resp.ResourceTagSet
   397  		}
   398  
   399  		return nil
   400  	}
   401  }
   402  
   403  const testAccRoute53ZoneConfig = `
   404  resource "aws_route53_zone" "main" {
   405  	name = "hashicorp.com."
   406  	comment = "Custom comment"
   407  
   408  	tags {
   409  		foo = "bar"
   410  		Name = "tf-route53-tag-test"
   411  	}
   412  }
   413  `
   414  
   415  const testAccRoute53ZoneConfig_forceDestroy = `
   416  resource "aws_route53_zone" "destroyable" {
   417  	name = "terraform.io"
   418  	force_destroy = true
   419  }
   420  `
   421  
   422  const testAccRoute53ZoneConfigUpdateComment = `
   423  resource "aws_route53_zone" "main" {
   424  	name = "hashicorp.com."
   425  	comment = "Change Custom Comment"
   426  
   427  	tags {
   428  		foo = "bar"
   429  		Name = "tf-route53-tag-test"
   430  	}
   431  }
   432  `
   433  
   434  const testAccRoute53PrivateZoneConfig = `
   435  resource "aws_vpc" "main" {
   436  	cidr_block = "172.29.0.0/24"
   437  	instance_tenancy = "default"
   438  	enable_dns_support = true
   439  	enable_dns_hostnames = true
   440  }
   441  
   442  resource "aws_route53_zone" "main" {
   443  	name = "hashicorp.com."
   444  	vpc_id = "${aws_vpc.main.id}"
   445  }
   446  `
   447  
   448  const testAccRoute53PrivateZoneRegionConfig = `
   449  provider "aws" {
   450  	alias = "west"
   451  	region = "us-west-2"
   452  }
   453  
   454  provider "aws" {
   455  	alias = "east"
   456  	region = "us-east-1"
   457  }
   458  
   459  resource "aws_vpc" "main" {
   460  	provider = "aws.east"
   461  	cidr_block = "172.29.0.0/24"
   462  	instance_tenancy = "default"
   463  	enable_dns_support = true
   464  	enable_dns_hostnames = true
   465  }
   466  
   467  resource "aws_route53_zone" "main" {
   468  	provider = "aws.west"
   469  	name = "hashicorp.com."
   470  	vpc_id = "${aws_vpc.main.id}"
   471  	vpc_region = "us-east-1"
   472  }
   473  `