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 `