github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_rds_cluster_test.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "regexp" 7 "strings" 8 "testing" 9 10 "github.com/hashicorp/terraform/helper/acctest" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/terraform" 13 14 "github.com/aws/aws-sdk-go/aws" 15 "github.com/aws/aws-sdk-go/aws/awserr" 16 "github.com/aws/aws-sdk-go/service/rds" 17 ) 18 19 func TestAccAWSRDSCluster_basic(t *testing.T) { 20 var v rds.DBCluster 21 22 resource.Test(t, resource.TestCase{ 23 PreCheck: func() { testAccPreCheck(t) }, 24 Providers: testAccProviders, 25 CheckDestroy: testAccCheckAWSClusterDestroy, 26 Steps: []resource.TestStep{ 27 { 28 Config: testAccAWSClusterConfig(acctest.RandInt()), 29 Check: resource.ComposeTestCheckFunc( 30 testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), 31 resource.TestCheckResourceAttr( 32 "aws_rds_cluster.default", "storage_encrypted", "false"), 33 resource.TestCheckResourceAttr( 34 "aws_rds_cluster.default", "db_cluster_parameter_group_name", "default.aurora5.6"), 35 resource.TestCheckResourceAttrSet( 36 "aws_rds_cluster.default", "reader_endpoint"), 37 ), 38 }, 39 }, 40 }) 41 } 42 43 func TestAccAWSRDSCluster_namePrefix(t *testing.T) { 44 var v rds.DBCluster 45 46 resource.Test(t, resource.TestCase{ 47 PreCheck: func() { testAccPreCheck(t) }, 48 Providers: testAccProviders, 49 CheckDestroy: testAccCheckAWSClusterDestroy, 50 Steps: []resource.TestStep{ 51 { 52 Config: testAccAWSClusterConfig_namePrefix(acctest.RandInt()), 53 Check: resource.ComposeTestCheckFunc( 54 testAccCheckAWSClusterExists("aws_rds_cluster.test", &v), 55 resource.TestMatchResourceAttr( 56 "aws_rds_cluster.test", "cluster_identifier", regexp.MustCompile("^tf-test-")), 57 ), 58 }, 59 }, 60 }) 61 } 62 63 func TestAccAWSRDSCluster_generatedName(t *testing.T) { 64 var v rds.DBCluster 65 66 resource.Test(t, resource.TestCase{ 67 PreCheck: func() { testAccPreCheck(t) }, 68 Providers: testAccProviders, 69 CheckDestroy: testAccCheckAWSClusterDestroy, 70 Steps: []resource.TestStep{ 71 { 72 Config: testAccAWSClusterConfig_generatedName(acctest.RandInt()), 73 Check: resource.ComposeTestCheckFunc( 74 testAccCheckAWSClusterExists("aws_rds_cluster.test", &v), 75 resource.TestMatchResourceAttr( 76 "aws_rds_cluster.test", "cluster_identifier", regexp.MustCompile("^tf-")), 77 ), 78 }, 79 }, 80 }) 81 } 82 83 func TestAccAWSRDSCluster_takeFinalSnapshot(t *testing.T) { 84 var v rds.DBCluster 85 rInt := acctest.RandInt() 86 87 resource.Test(t, resource.TestCase{ 88 PreCheck: func() { testAccPreCheck(t) }, 89 Providers: testAccProviders, 90 CheckDestroy: testAccCheckAWSClusterSnapshot(rInt), 91 Steps: []resource.TestStep{ 92 { 93 Config: testAccAWSClusterConfigWithFinalSnapshot(rInt), 94 Check: resource.ComposeTestCheckFunc( 95 testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), 96 ), 97 }, 98 }, 99 }) 100 } 101 102 /// This is a regression test to make sure that we always cover the scenario as hightlighted in 103 /// https://github.com/hashicorp/terraform/issues/11568 104 func TestAccAWSRDSCluster_missingUserNameCausesError(t *testing.T) { 105 resource.Test(t, resource.TestCase{ 106 PreCheck: func() { testAccPreCheck(t) }, 107 Providers: testAccProviders, 108 CheckDestroy: testAccCheckAWSClusterDestroy, 109 Steps: []resource.TestStep{ 110 { 111 Config: testAccAWSClusterConfigWithoutUserNameAndPassword(acctest.RandInt()), 112 ExpectError: regexp.MustCompile(`required field is not set`), 113 }, 114 }, 115 }) 116 } 117 118 func TestAccAWSRDSCluster_updateTags(t *testing.T) { 119 var v rds.DBCluster 120 ri := acctest.RandInt() 121 122 resource.Test(t, resource.TestCase{ 123 PreCheck: func() { testAccPreCheck(t) }, 124 Providers: testAccProviders, 125 CheckDestroy: testAccCheckAWSClusterDestroy, 126 Steps: []resource.TestStep{ 127 { 128 Config: testAccAWSClusterConfig(ri), 129 Check: resource.ComposeTestCheckFunc( 130 testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), 131 resource.TestCheckResourceAttr( 132 "aws_rds_cluster.default", "tags.%", "1"), 133 ), 134 }, 135 { 136 Config: testAccAWSClusterConfigUpdatedTags(ri), 137 Check: resource.ComposeTestCheckFunc( 138 testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), 139 resource.TestCheckResourceAttr( 140 "aws_rds_cluster.default", "tags.%", "2"), 141 ), 142 }, 143 }, 144 }) 145 } 146 147 func TestAccAWSRDSCluster_kmsKey(t *testing.T) { 148 var v rds.DBCluster 149 keyRegex := regexp.MustCompile("^arn:aws:kms:") 150 151 resource.Test(t, resource.TestCase{ 152 PreCheck: func() { testAccPreCheck(t) }, 153 Providers: testAccProviders, 154 CheckDestroy: testAccCheckAWSClusterDestroy, 155 Steps: []resource.TestStep{ 156 { 157 Config: testAccAWSClusterConfig_kmsKey(acctest.RandInt()), 158 Check: resource.ComposeTestCheckFunc( 159 testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), 160 resource.TestMatchResourceAttr( 161 "aws_rds_cluster.default", "kms_key_id", keyRegex), 162 ), 163 }, 164 }, 165 }) 166 } 167 168 func TestAccAWSRDSCluster_encrypted(t *testing.T) { 169 var v rds.DBCluster 170 171 resource.Test(t, resource.TestCase{ 172 PreCheck: func() { testAccPreCheck(t) }, 173 Providers: testAccProviders, 174 CheckDestroy: testAccCheckAWSClusterDestroy, 175 Steps: []resource.TestStep{ 176 { 177 Config: testAccAWSClusterConfig_encrypted(acctest.RandInt()), 178 Check: resource.ComposeTestCheckFunc( 179 testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), 180 resource.TestCheckResourceAttr( 181 "aws_rds_cluster.default", "storage_encrypted", "true"), 182 resource.TestCheckResourceAttr( 183 "aws_rds_cluster.default", "db_cluster_parameter_group_name", "default.aurora5.6"), 184 ), 185 }, 186 }, 187 }) 188 } 189 190 func TestAccAWSRDSCluster_backupsUpdate(t *testing.T) { 191 var v rds.DBCluster 192 193 ri := acctest.RandInt() 194 resource.Test(t, resource.TestCase{ 195 PreCheck: func() { testAccPreCheck(t) }, 196 Providers: testAccProviders, 197 CheckDestroy: testAccCheckAWSClusterDestroy, 198 Steps: []resource.TestStep{ 199 { 200 Config: testAccAWSClusterConfig_backups(ri), 201 Check: resource.ComposeTestCheckFunc( 202 testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), 203 resource.TestCheckResourceAttr( 204 "aws_rds_cluster.default", "preferred_backup_window", "07:00-09:00"), 205 resource.TestCheckResourceAttr( 206 "aws_rds_cluster.default", "backup_retention_period", "5"), 207 resource.TestCheckResourceAttr( 208 "aws_rds_cluster.default", "preferred_maintenance_window", "tue:04:00-tue:04:30"), 209 ), 210 }, 211 212 resource.TestStep{ 213 Config: testAccAWSClusterConfig_backupsUpdate(ri), 214 Check: resource.ComposeTestCheckFunc( 215 testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), 216 resource.TestCheckResourceAttr( 217 "aws_rds_cluster.default", "preferred_backup_window", "03:00-09:00"), 218 resource.TestCheckResourceAttr( 219 "aws_rds_cluster.default", "backup_retention_period", "10"), 220 resource.TestCheckResourceAttr( 221 "aws_rds_cluster.default", "preferred_maintenance_window", "wed:01:00-wed:01:30"), 222 ), 223 }, 224 }, 225 }) 226 } 227 228 func testAccCheckAWSClusterDestroy(s *terraform.State) error { 229 for _, rs := range s.RootModule().Resources { 230 if rs.Type != "aws_rds_cluster" { 231 continue 232 } 233 234 // Try to find the Group 235 conn := testAccProvider.Meta().(*AWSClient).rdsconn 236 var err error 237 resp, err := conn.DescribeDBClusters( 238 &rds.DescribeDBClustersInput{ 239 DBClusterIdentifier: aws.String(rs.Primary.ID), 240 }) 241 242 if err == nil { 243 if len(resp.DBClusters) != 0 && 244 *resp.DBClusters[0].DBClusterIdentifier == rs.Primary.ID { 245 return fmt.Errorf("DB Cluster %s still exists", rs.Primary.ID) 246 } 247 } 248 249 // Return nil if the cluster is already destroyed 250 if awsErr, ok := err.(awserr.Error); ok { 251 if awsErr.Code() == "DBClusterNotFoundFault" { 252 return nil 253 } 254 } 255 256 return err 257 } 258 259 return nil 260 } 261 262 func testAccCheckAWSClusterSnapshot(rInt int) resource.TestCheckFunc { 263 return func(s *terraform.State) error { 264 for _, rs := range s.RootModule().Resources { 265 if rs.Type != "aws_rds_cluster" { 266 continue 267 } 268 269 // Try and delete the snapshot before we check for the cluster not found 270 snapshot_identifier := fmt.Sprintf("tf-acctest-rdscluster-snapshot-%d", rInt) 271 272 awsClient := testAccProvider.Meta().(*AWSClient) 273 conn := awsClient.rdsconn 274 275 arn, arnErr := buildRDSClusterARN(snapshot_identifier, awsClient.partition, awsClient.accountid, awsClient.region) 276 tagsARN := strings.Replace(arn, ":cluster:", ":snapshot:", 1) 277 if arnErr != nil { 278 return fmt.Errorf("Error building ARN for tags check with ARN (%s): %s", tagsARN, arnErr) 279 } 280 281 log.Printf("[INFO] Deleting the Snapshot %s", snapshot_identifier) 282 _, snapDeleteErr := conn.DeleteDBClusterSnapshot( 283 &rds.DeleteDBClusterSnapshotInput{ 284 DBClusterSnapshotIdentifier: aws.String(snapshot_identifier), 285 }) 286 if snapDeleteErr != nil { 287 return snapDeleteErr 288 } 289 290 // Try to find the Group 291 var err error 292 resp, err := conn.DescribeDBClusters( 293 &rds.DescribeDBClustersInput{ 294 DBClusterIdentifier: aws.String(rs.Primary.ID), 295 }) 296 297 if err == nil { 298 if len(resp.DBClusters) != 0 && 299 *resp.DBClusters[0].DBClusterIdentifier == rs.Primary.ID { 300 return fmt.Errorf("DB Cluster %s still exists", rs.Primary.ID) 301 } 302 } 303 304 // Return nil if the cluster is already destroyed 305 if awsErr, ok := err.(awserr.Error); ok { 306 if awsErr.Code() == "DBClusterNotFoundFault" { 307 return nil 308 } 309 } 310 311 return err 312 } 313 314 return nil 315 } 316 } 317 318 func testAccCheckAWSClusterExists(n string, v *rds.DBCluster) resource.TestCheckFunc { 319 return func(s *terraform.State) error { 320 rs, ok := s.RootModule().Resources[n] 321 if !ok { 322 return fmt.Errorf("Not found: %s", n) 323 } 324 325 if rs.Primary.ID == "" { 326 return fmt.Errorf("No DB Instance ID is set") 327 } 328 329 conn := testAccProvider.Meta().(*AWSClient).rdsconn 330 resp, err := conn.DescribeDBClusters(&rds.DescribeDBClustersInput{ 331 DBClusterIdentifier: aws.String(rs.Primary.ID), 332 }) 333 334 if err != nil { 335 return err 336 } 337 338 for _, c := range resp.DBClusters { 339 if *c.DBClusterIdentifier == rs.Primary.ID { 340 *v = *c 341 return nil 342 } 343 } 344 345 return fmt.Errorf("DB Cluster (%s) not found", rs.Primary.ID) 346 } 347 } 348 349 func testAccAWSClusterConfig(n int) string { 350 return fmt.Sprintf(` 351 resource "aws_rds_cluster" "default" { 352 cluster_identifier = "tf-aurora-cluster-%d" 353 availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] 354 database_name = "mydb" 355 master_username = "foo" 356 master_password = "mustbeeightcharaters" 357 db_cluster_parameter_group_name = "default.aurora5.6" 358 skip_final_snapshot = true 359 tags { 360 Environment = "production" 361 } 362 }`, n) 363 } 364 365 func testAccAWSClusterConfig_namePrefix(n int) string { 366 return fmt.Sprintf(` 367 resource "aws_rds_cluster" "test" { 368 cluster_identifier_prefix = "tf-test-" 369 master_username = "root" 370 master_password = "password" 371 db_subnet_group_name = "${aws_db_subnet_group.test.name}" 372 skip_final_snapshot = true 373 } 374 375 resource "aws_vpc" "test" { 376 cidr_block = "10.0.0.0/16" 377 } 378 379 resource "aws_subnet" "a" { 380 vpc_id = "${aws_vpc.test.id}" 381 cidr_block = "10.0.0.0/24" 382 availability_zone = "us-west-2a" 383 } 384 385 resource "aws_subnet" "b" { 386 vpc_id = "${aws_vpc.test.id}" 387 cidr_block = "10.0.1.0/24" 388 availability_zone = "us-west-2b" 389 } 390 391 resource "aws_db_subnet_group" "test" { 392 name = "tf-test-%d" 393 subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"] 394 } 395 `, n) 396 } 397 398 func testAccAWSClusterConfig_generatedName(n int) string { 399 return fmt.Sprintf(` 400 resource "aws_rds_cluster" "test" { 401 master_username = "root" 402 master_password = "password" 403 db_subnet_group_name = "${aws_db_subnet_group.test.name}" 404 skip_final_snapshot = true 405 } 406 407 resource "aws_vpc" "test" { 408 cidr_block = "10.0.0.0/16" 409 } 410 411 resource "aws_subnet" "a" { 412 vpc_id = "${aws_vpc.test.id}" 413 cidr_block = "10.0.0.0/24" 414 availability_zone = "us-west-2a" 415 } 416 417 resource "aws_subnet" "b" { 418 vpc_id = "${aws_vpc.test.id}" 419 cidr_block = "10.0.1.0/24" 420 availability_zone = "us-west-2b" 421 } 422 423 resource "aws_db_subnet_group" "test" { 424 name = "tf-test-%d" 425 subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"] 426 } 427 `, n) 428 } 429 430 func testAccAWSClusterConfigWithFinalSnapshot(n int) string { 431 return fmt.Sprintf(` 432 resource "aws_rds_cluster" "default" { 433 cluster_identifier = "tf-aurora-cluster-%d" 434 availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] 435 database_name = "mydb" 436 master_username = "foo" 437 master_password = "mustbeeightcharaters" 438 db_cluster_parameter_group_name = "default.aurora5.6" 439 final_snapshot_identifier = "tf-acctest-rdscluster-snapshot-%d" 440 tags { 441 Environment = "production" 442 } 443 }`, n, n) 444 } 445 446 func testAccAWSClusterConfigWithoutUserNameAndPassword(n int) string { 447 return fmt.Sprintf(` 448 resource "aws_rds_cluster" "default" { 449 cluster_identifier = "tf-aurora-cluster-%d" 450 availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] 451 database_name = "mydb" 452 skip_final_snapshot = true 453 }`, n) 454 } 455 456 func testAccAWSClusterConfigUpdatedTags(n int) string { 457 return fmt.Sprintf(` 458 resource "aws_rds_cluster" "default" { 459 cluster_identifier = "tf-aurora-cluster-%d" 460 availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] 461 database_name = "mydb" 462 master_username = "foo" 463 master_password = "mustbeeightcharaters" 464 db_cluster_parameter_group_name = "default.aurora5.6" 465 skip_final_snapshot = true 466 tags { 467 Environment = "production" 468 AnotherTag = "test" 469 } 470 }`, n) 471 } 472 473 func testAccAWSClusterConfig_kmsKey(n int) string { 474 return fmt.Sprintf(` 475 476 resource "aws_kms_key" "foo" { 477 description = "Terraform acc test %d" 478 policy = <<POLICY 479 { 480 "Version": "2012-10-17", 481 "Id": "kms-tf-1", 482 "Statement": [ 483 { 484 "Sid": "Enable IAM User Permissions", 485 "Effect": "Allow", 486 "Principal": { 487 "AWS": "*" 488 }, 489 "Action": "kms:*", 490 "Resource": "*" 491 } 492 ] 493 } 494 POLICY 495 } 496 497 resource "aws_rds_cluster" "default" { 498 cluster_identifier = "tf-aurora-cluster-%d" 499 availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] 500 database_name = "mydb" 501 master_username = "foo" 502 master_password = "mustbeeightcharaters" 503 db_cluster_parameter_group_name = "default.aurora5.6" 504 storage_encrypted = true 505 kms_key_id = "${aws_kms_key.foo.arn}" 506 skip_final_snapshot = true 507 }`, n, n) 508 } 509 510 func testAccAWSClusterConfig_encrypted(n int) string { 511 return fmt.Sprintf(` 512 resource "aws_rds_cluster" "default" { 513 cluster_identifier = "tf-aurora-cluster-%d" 514 availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] 515 database_name = "mydb" 516 master_username = "foo" 517 master_password = "mustbeeightcharaters" 518 storage_encrypted = true 519 skip_final_snapshot = true 520 }`, n) 521 } 522 523 func testAccAWSClusterConfig_backups(n int) string { 524 return fmt.Sprintf(` 525 resource "aws_rds_cluster" "default" { 526 cluster_identifier = "tf-aurora-cluster-%d" 527 availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] 528 database_name = "mydb" 529 master_username = "foo" 530 master_password = "mustbeeightcharaters" 531 backup_retention_period = 5 532 preferred_backup_window = "07:00-09:00" 533 preferred_maintenance_window = "tue:04:00-tue:04:30" 534 skip_final_snapshot = true 535 }`, n) 536 } 537 538 func testAccAWSClusterConfig_backupsUpdate(n int) string { 539 return fmt.Sprintf(` 540 resource "aws_rds_cluster" "default" { 541 cluster_identifier = "tf-aurora-cluster-%d" 542 availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] 543 database_name = "mydb" 544 master_username = "foo" 545 master_password = "mustbeeightcharaters" 546 backup_retention_period = 10 547 preferred_backup_window = "03:00-09:00" 548 preferred_maintenance_window = "wed:01:00-wed:01:30" 549 apply_immediately = true 550 skip_final_snapshot = true 551 }`, n) 552 }