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 `