github.com/ottenhoff/terraform@v0.7.0-rc1.0.20160607213102-ac2d195cc560/builtin/providers/aws/resource_aws_db_instance_test.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "regexp" 7 "strings" 8 9 "math/rand" 10 "testing" 11 "time" 12 13 "github.com/hashicorp/terraform/helper/acctest" 14 "github.com/hashicorp/terraform/helper/resource" 15 "github.com/hashicorp/terraform/terraform" 16 17 "github.com/aws/aws-sdk-go/aws" 18 "github.com/aws/aws-sdk-go/aws/awserr" 19 "github.com/aws/aws-sdk-go/service/rds" 20 ) 21 22 func TestAccAWSDBInstance_basic(t *testing.T) { 23 var v rds.DBInstance 24 25 resource.Test(t, resource.TestCase{ 26 PreCheck: func() { testAccPreCheck(t) }, 27 Providers: testAccProviders, 28 CheckDestroy: testAccCheckAWSDBInstanceDestroy, 29 Steps: []resource.TestStep{ 30 resource.TestStep{ 31 Config: testAccAWSDBInstanceConfig, 32 Check: resource.ComposeTestCheckFunc( 33 testAccCheckAWSDBInstanceExists("aws_db_instance.bar", &v), 34 testAccCheckAWSDBInstanceAttributes(&v), 35 resource.TestCheckResourceAttr( 36 "aws_db_instance.bar", "allocated_storage", "10"), 37 resource.TestCheckResourceAttr( 38 "aws_db_instance.bar", "engine", "mysql"), 39 resource.TestCheckResourceAttr( 40 "aws_db_instance.bar", "license_model", "general-public-license"), 41 resource.TestCheckResourceAttr( 42 "aws_db_instance.bar", "instance_class", "db.t1.micro"), 43 resource.TestCheckResourceAttr( 44 "aws_db_instance.bar", "name", "baz"), 45 resource.TestCheckResourceAttr( 46 "aws_db_instance.bar", "username", "foo"), 47 resource.TestCheckResourceAttr( 48 "aws_db_instance.bar", "parameter_group_name", "default.mysql5.6"), 49 ), 50 }, 51 }, 52 }) 53 } 54 55 func TestAccAWSDBInstance_kmsKey(t *testing.T) { 56 var v rds.DBInstance 57 keyRegex := regexp.MustCompile("^arn:aws:kms:") 58 59 ri := rand.New(rand.NewSource(time.Now().UnixNano())).Int() 60 config := fmt.Sprintf(testAccAWSDBInstanceConfigKmsKeyId, ri) 61 62 resource.Test(t, resource.TestCase{ 63 PreCheck: func() { testAccPreCheck(t) }, 64 Providers: testAccProviders, 65 CheckDestroy: testAccCheckAWSDBInstanceDestroy, 66 Steps: []resource.TestStep{ 67 resource.TestStep{ 68 Config: config, 69 Check: resource.ComposeTestCheckFunc( 70 testAccCheckAWSDBInstanceExists("aws_db_instance.bar", &v), 71 testAccCheckAWSDBInstanceAttributes(&v), 72 resource.TestMatchResourceAttr( 73 "aws_db_instance.bar", "kms_key_id", keyRegex), 74 ), 75 }, 76 }, 77 }) 78 } 79 80 func TestAccAWSDBInstance_optionGroup(t *testing.T) { 81 var v rds.DBInstance 82 83 resource.Test(t, resource.TestCase{ 84 PreCheck: func() { testAccPreCheck(t) }, 85 Providers: testAccProviders, 86 CheckDestroy: testAccCheckAWSDBInstanceDestroy, 87 Steps: []resource.TestStep{ 88 resource.TestStep{ 89 Config: testAccAWSDBInstanceConfigWithOptionGroup, 90 Check: resource.ComposeTestCheckFunc( 91 testAccCheckAWSDBInstanceExists("aws_db_instance.bar", &v), 92 testAccCheckAWSDBInstanceAttributes(&v), 93 resource.TestCheckResourceAttr( 94 "aws_db_instance.bar", "option_group_name", "option-group-test-terraform"), 95 ), 96 }, 97 }, 98 }) 99 } 100 101 func TestAccAWSDBInstanceReplica(t *testing.T) { 102 var s, r rds.DBInstance 103 104 resource.Test(t, resource.TestCase{ 105 PreCheck: func() { testAccPreCheck(t) }, 106 Providers: testAccProviders, 107 CheckDestroy: testAccCheckAWSDBInstanceDestroy, 108 Steps: []resource.TestStep{ 109 resource.TestStep{ 110 Config: testAccReplicaInstanceConfig(rand.New(rand.NewSource(time.Now().UnixNano())).Int()), 111 Check: resource.ComposeTestCheckFunc( 112 testAccCheckAWSDBInstanceExists("aws_db_instance.bar", &s), 113 testAccCheckAWSDBInstanceExists("aws_db_instance.replica", &r), 114 testAccCheckAWSDBInstanceReplicaAttributes(&s, &r), 115 ), 116 }, 117 }, 118 }) 119 } 120 121 func TestAccAWSDBInstanceSnapshot(t *testing.T) { 122 var snap rds.DBInstance 123 124 resource.Test(t, resource.TestCase{ 125 PreCheck: func() { testAccPreCheck(t) }, 126 Providers: testAccProviders, 127 // testAccCheckAWSDBInstanceSnapshot verifies a database snapshot is 128 // created, and subequently deletes it 129 CheckDestroy: testAccCheckAWSDBInstanceSnapshot, 130 Steps: []resource.TestStep{ 131 resource.TestStep{ 132 Config: testAccSnapshotInstanceConfig(), 133 Check: resource.ComposeTestCheckFunc( 134 testAccCheckAWSDBInstanceExists("aws_db_instance.snapshot", &snap), 135 ), 136 }, 137 }, 138 }) 139 } 140 141 func TestAccAWSDBInstanceNoSnapshot(t *testing.T) { 142 var nosnap rds.DBInstance 143 144 resource.Test(t, resource.TestCase{ 145 PreCheck: func() { testAccPreCheck(t) }, 146 Providers: testAccProviders, 147 CheckDestroy: testAccCheckAWSDBInstanceNoSnapshot, 148 Steps: []resource.TestStep{ 149 resource.TestStep{ 150 Config: testAccNoSnapshotInstanceConfig(), 151 Check: resource.ComposeTestCheckFunc( 152 testAccCheckAWSDBInstanceExists("aws_db_instance.no_snapshot", &nosnap), 153 ), 154 }, 155 }, 156 }) 157 } 158 159 func TestAccAWSDBInstance_enhancedMonitoring(t *testing.T) { 160 var dbInstance rds.DBInstance 161 162 resource.Test(t, resource.TestCase{ 163 PreCheck: func() { testAccPreCheck(t) }, 164 Providers: testAccProviders, 165 CheckDestroy: testAccCheckAWSDBInstanceNoSnapshot, 166 Steps: []resource.TestStep{ 167 resource.TestStep{ 168 Config: testAccSnapshotInstanceConfig_enhancedMonitoring, 169 Check: resource.ComposeTestCheckFunc( 170 testAccCheckAWSDBInstanceExists("aws_db_instance.enhanced_monitoring", &dbInstance), 171 resource.TestCheckResourceAttr( 172 "aws_db_instance.enhanced_monitoring", "monitoring_interval", "5"), 173 ), 174 }, 175 }, 176 }) 177 } 178 179 func testAccCheckAWSDBInstanceDestroy(s *terraform.State) error { 180 conn := testAccProvider.Meta().(*AWSClient).rdsconn 181 182 for _, rs := range s.RootModule().Resources { 183 if rs.Type != "aws_db_instance" { 184 continue 185 } 186 187 // Try to find the Group 188 var err error 189 resp, err := conn.DescribeDBInstances( 190 &rds.DescribeDBInstancesInput{ 191 DBInstanceIdentifier: aws.String(rs.Primary.ID), 192 }) 193 194 if ae, ok := err.(awserr.Error); ok && ae.Code() == "DBInstanceNotFound" { 195 continue 196 } 197 198 if err == nil { 199 if len(resp.DBInstances) != 0 && 200 *resp.DBInstances[0].DBInstanceIdentifier == rs.Primary.ID { 201 return fmt.Errorf("DB Instance still exists") 202 } 203 } 204 205 // Verify the error 206 newerr, ok := err.(awserr.Error) 207 if !ok { 208 return err 209 } 210 if newerr.Code() != "DBInstanceNotFound" { 211 return err 212 } 213 } 214 215 return nil 216 } 217 218 func testAccCheckAWSDBInstanceAttributes(v *rds.DBInstance) resource.TestCheckFunc { 219 return func(s *terraform.State) error { 220 221 if *v.Engine != "mysql" { 222 return fmt.Errorf("bad engine: %#v", *v.Engine) 223 } 224 225 if *v.EngineVersion == "" { 226 return fmt.Errorf("bad engine_version: %#v", *v.EngineVersion) 227 } 228 229 if *v.BackupRetentionPeriod != 0 { 230 return fmt.Errorf("bad backup_retention_period: %#v", *v.BackupRetentionPeriod) 231 } 232 233 return nil 234 } 235 } 236 237 func testAccCheckAWSDBInstanceReplicaAttributes(source, replica *rds.DBInstance) resource.TestCheckFunc { 238 return func(s *terraform.State) error { 239 240 if replica.ReadReplicaSourceDBInstanceIdentifier != nil && *replica.ReadReplicaSourceDBInstanceIdentifier != *source.DBInstanceIdentifier { 241 return fmt.Errorf("bad source identifier for replica, expected: '%s', got: '%s'", *source.DBInstanceIdentifier, *replica.ReadReplicaSourceDBInstanceIdentifier) 242 } 243 244 return nil 245 } 246 } 247 248 func testAccCheckAWSDBInstanceSnapshot(s *terraform.State) error { 249 conn := testAccProvider.Meta().(*AWSClient).rdsconn 250 251 for _, rs := range s.RootModule().Resources { 252 if rs.Type != "aws_db_instance" { 253 continue 254 } 255 256 var err error 257 resp, err := conn.DescribeDBInstances( 258 &rds.DescribeDBInstancesInput{ 259 DBInstanceIdentifier: aws.String(rs.Primary.ID), 260 }) 261 262 if err != nil { 263 newerr, _ := err.(awserr.Error) 264 if newerr.Code() != "DBInstanceNotFound" { 265 return err 266 } 267 268 } else { 269 if len(resp.DBInstances) != 0 && 270 *resp.DBInstances[0].DBInstanceIdentifier == rs.Primary.ID { 271 return fmt.Errorf("DB Instance still exists") 272 } 273 } 274 275 log.Printf("[INFO] Trying to locate the DBInstance Final Snapshot") 276 snapshot_identifier := "foobarbaz-test-terraform-final-snapshot-1" 277 _, snapErr := conn.DescribeDBSnapshots( 278 &rds.DescribeDBSnapshotsInput{ 279 DBSnapshotIdentifier: aws.String(snapshot_identifier), 280 }) 281 282 if snapErr != nil { 283 newerr, _ := snapErr.(awserr.Error) 284 if newerr.Code() == "DBSnapshotNotFound" { 285 return fmt.Errorf("Snapshot %s not found", snapshot_identifier) 286 } 287 } else { // snapshot was found 288 // verify we have the tags copied to the snapshot 289 instanceARN, err := buildRDSARN(snapshot_identifier, testAccProvider.Meta()) 290 // tags have a different ARN, just swapping :db: for :snapshot: 291 tagsARN := strings.Replace(instanceARN, ":db:", ":snapshot:", 1) 292 if err != nil { 293 return fmt.Errorf("Error building ARN for tags check with ARN (%s): %s", tagsARN, err) 294 } 295 resp, err := conn.ListTagsForResource(&rds.ListTagsForResourceInput{ 296 ResourceName: aws.String(tagsARN), 297 }) 298 if err != nil { 299 return fmt.Errorf("Error retrieving tags for ARN (%s): %s", tagsARN, err) 300 } 301 302 if resp.TagList == nil || len(resp.TagList) == 0 { 303 return fmt.Errorf("Tag list is nil or zero: %s", resp.TagList) 304 } 305 306 var found bool 307 for _, t := range resp.TagList { 308 if *t.Key == "Name" && *t.Value == "tf-tags-db" { 309 found = true 310 } 311 } 312 if !found { 313 return fmt.Errorf("Expected to find tag Name (%s), but wasn't found. Tags: %s", "tf-tags-db", resp.TagList) 314 } 315 // end tag search 316 317 log.Printf("[INFO] Deleting the Snapshot %s", snapshot_identifier) 318 _, snapDeleteErr := conn.DeleteDBSnapshot( 319 &rds.DeleteDBSnapshotInput{ 320 DBSnapshotIdentifier: aws.String(snapshot_identifier), 321 }) 322 if snapDeleteErr != nil { 323 return err 324 } 325 } // end snapshot was found 326 } 327 328 return nil 329 } 330 331 func testAccCheckAWSDBInstanceNoSnapshot(s *terraform.State) error { 332 conn := testAccProvider.Meta().(*AWSClient).rdsconn 333 334 for _, rs := range s.RootModule().Resources { 335 if rs.Type != "aws_db_instance" { 336 continue 337 } 338 339 var err error 340 resp, err := conn.DescribeDBInstances( 341 &rds.DescribeDBInstancesInput{ 342 DBInstanceIdentifier: aws.String(rs.Primary.ID), 343 }) 344 345 if err != nil { 346 newerr, _ := err.(awserr.Error) 347 if newerr.Code() != "DBInstanceNotFound" { 348 return err 349 } 350 351 } else { 352 if len(resp.DBInstances) != 0 && 353 *resp.DBInstances[0].DBInstanceIdentifier == rs.Primary.ID { 354 return fmt.Errorf("DB Instance still exists") 355 } 356 } 357 358 snapshot_identifier := "foobarbaz-test-terraform-final-snapshot-2" 359 _, snapErr := conn.DescribeDBSnapshots( 360 &rds.DescribeDBSnapshotsInput{ 361 DBSnapshotIdentifier: aws.String(snapshot_identifier), 362 }) 363 364 if snapErr != nil { 365 newerr, _ := snapErr.(awserr.Error) 366 if newerr.Code() != "DBSnapshotNotFound" { 367 return fmt.Errorf("Snapshot %s found and it shouldn't have been", snapshot_identifier) 368 } 369 } 370 } 371 372 return nil 373 } 374 375 func testAccCheckAWSDBInstanceExists(n string, v *rds.DBInstance) resource.TestCheckFunc { 376 return func(s *terraform.State) error { 377 rs, ok := s.RootModule().Resources[n] 378 if !ok { 379 return fmt.Errorf("Not found: %s", n) 380 } 381 382 if rs.Primary.ID == "" { 383 return fmt.Errorf("No DB Instance ID is set") 384 } 385 386 conn := testAccProvider.Meta().(*AWSClient).rdsconn 387 388 opts := rds.DescribeDBInstancesInput{ 389 DBInstanceIdentifier: aws.String(rs.Primary.ID), 390 } 391 392 resp, err := conn.DescribeDBInstances(&opts) 393 394 if err != nil { 395 return err 396 } 397 398 if len(resp.DBInstances) != 1 || 399 *resp.DBInstances[0].DBInstanceIdentifier != rs.Primary.ID { 400 return fmt.Errorf("DB Instance not found") 401 } 402 403 *v = *resp.DBInstances[0] 404 405 return nil 406 } 407 } 408 409 // Database names cannot collide, and deletion takes so long, that making the 410 // name a bit random helps so able we can kill a test that's just waiting for a 411 // delete and not be blocked on kicking off another one. 412 var testAccAWSDBInstanceConfig = ` 413 resource "aws_db_instance" "bar" { 414 allocated_storage = 10 415 engine = "MySQL" 416 engine_version = "5.6.21" 417 instance_class = "db.t1.micro" 418 name = "baz" 419 password = "barbarbarbar" 420 username = "foo" 421 422 423 # Maintenance Window is stored in lower case in the API, though not strictly 424 # documented. Terraform will downcase this to match (as opposed to throw a 425 # validation error). 426 maintenance_window = "Fri:09:00-Fri:09:30" 427 428 backup_retention_period = 0 429 430 parameter_group_name = "default.mysql5.6" 431 }` 432 433 var testAccAWSDBInstanceConfigKmsKeyId = ` 434 resource "aws_kms_key" "foo" { 435 description = "Terraform acc test %s" 436 policy = <<POLICY 437 { 438 "Version": "2012-10-17", 439 "Id": "kms-tf-1", 440 "Statement": [ 441 { 442 "Sid": "Enable IAM User Permissions", 443 "Effect": "Allow", 444 "Principal": { 445 "AWS": "*" 446 }, 447 "Action": "kms:*", 448 "Resource": "*" 449 } 450 ] 451 } 452 POLICY 453 } 454 455 resource "aws_db_instance" "bar" { 456 allocated_storage = 10 457 engine = "MySQL" 458 engine_version = "5.6.21" 459 instance_class = "db.m3.medium" 460 name = "baz" 461 password = "barbarbarbar" 462 username = "foo" 463 464 465 # Maintenance Window is stored in lower case in the API, though not strictly 466 # documented. Terraform will downcase this to match (as opposed to throw a 467 # validation error). 468 maintenance_window = "Fri:09:00-Fri:09:30" 469 470 backup_retention_period = 0 471 storage_encrypted = true 472 kms_key_id = "${aws_kms_key.foo.arn}" 473 474 parameter_group_name = "default.mysql5.6" 475 } 476 ` 477 478 var testAccAWSDBInstanceConfigWithOptionGroup = fmt.Sprintf(` 479 480 resource "aws_db_option_group" "bar" { 481 name = "option-group-test-terraform" 482 option_group_description = "Test option group for terraform" 483 engine_name = "mysql" 484 major_engine_version = "5.6" 485 } 486 487 resource "aws_db_instance" "bar" { 488 identifier = "foobarbaz-test-terraform-%d" 489 490 allocated_storage = 10 491 engine = "MySQL" 492 instance_class = "db.m1.small" 493 name = "baz" 494 password = "barbarbarbar" 495 username = "foo" 496 497 backup_retention_period = 0 498 499 parameter_group_name = "default.mysql5.6" 500 option_group_name = "${aws_db_option_group.bar.name}" 501 }`, acctest.RandInt()) 502 503 func testAccReplicaInstanceConfig(val int) string { 504 return fmt.Sprintf(` 505 resource "aws_db_instance" "bar" { 506 identifier = "foobarbaz-test-terraform-%d" 507 508 allocated_storage = 5 509 engine = "mysql" 510 engine_version = "5.6.21" 511 instance_class = "db.t1.micro" 512 name = "baz" 513 password = "barbarbarbar" 514 username = "foo" 515 516 backup_retention_period = 1 517 518 parameter_group_name = "default.mysql5.6" 519 } 520 521 resource "aws_db_instance" "replica" { 522 identifier = "tf-replica-db-%d" 523 backup_retention_period = 0 524 replicate_source_db = "${aws_db_instance.bar.identifier}" 525 allocated_storage = "${aws_db_instance.bar.allocated_storage}" 526 engine = "${aws_db_instance.bar.engine}" 527 engine_version = "${aws_db_instance.bar.engine_version}" 528 instance_class = "${aws_db_instance.bar.instance_class}" 529 password = "${aws_db_instance.bar.password}" 530 username = "${aws_db_instance.bar.username}" 531 tags { 532 Name = "tf-replica-db" 533 } 534 } 535 `, val, val) 536 } 537 538 func testAccSnapshotInstanceConfig() string { 539 return fmt.Sprintf(` 540 provider "aws" { 541 region = "us-east-1" 542 } 543 resource "aws_db_instance" "snapshot" { 544 identifier = "tf-snapshot-%d" 545 546 allocated_storage = 5 547 engine = "mysql" 548 engine_version = "5.6.21" 549 instance_class = "db.t1.micro" 550 name = "baz" 551 password = "barbarbarbar" 552 username = "foo" 553 security_group_names = ["default"] 554 backup_retention_period = 1 555 556 parameter_group_name = "default.mysql5.6" 557 558 skip_final_snapshot = false 559 copy_tags_to_snapshot = true 560 final_snapshot_identifier = "foobarbaz-test-terraform-final-snapshot-1" 561 tags { 562 Name = "tf-tags-db" 563 } 564 }`, acctest.RandInt()) 565 } 566 567 func testAccNoSnapshotInstanceConfig() string { 568 return fmt.Sprintf(` 569 provider "aws" { 570 region = "us-east-1" 571 } 572 resource "aws_db_instance" "no_snapshot" { 573 identifier = "tf-test-%s" 574 575 allocated_storage = 5 576 engine = "mysql" 577 engine_version = "5.6.21" 578 instance_class = "db.t1.micro" 579 name = "baz" 580 password = "barbarbarbar" 581 username = "foo" 582 security_group_names = ["default"] 583 backup_retention_period = 1 584 585 parameter_group_name = "default.mysql5.6" 586 587 skip_final_snapshot = true 588 final_snapshot_identifier = "foobarbaz-test-terraform-final-snapshot-2" 589 } 590 `, acctest.RandString(5)) 591 } 592 593 var testAccSnapshotInstanceConfig_enhancedMonitoring = ` 594 resource "aws_iam_role" "enhanced_policy_role" { 595 name = "enhanced-monitoring-role" 596 assume_role_policy = <<EOF 597 { 598 "Version": "2012-10-17", 599 "Statement": [ 600 { 601 "Sid": "", 602 "Effect": "Allow", 603 "Principal": { 604 "Service": "monitoring.rds.amazonaws.com" 605 }, 606 "Action": "sts:AssumeRole" 607 } 608 ] 609 } 610 EOF 611 612 } 613 614 resource "aws_iam_policy_attachment" "test-attach" { 615 name = "enhanced-monitoring-attachment" 616 roles = [ 617 "${aws_iam_role.enhanced_policy_role.name}", 618 ] 619 620 policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole" 621 } 622 623 resource "aws_db_instance" "enhanced_monitoring" { 624 identifier = "foobarbaz-test-terraform-enhanced-monitoring" 625 depends_on = ["aws_iam_policy_attachment.test-attach"] 626 627 allocated_storage = 5 628 engine = "mysql" 629 engine_version = "5.6.21" 630 instance_class = "db.m3.medium" 631 name = "baz" 632 password = "barbarbarbar" 633 username = "foo" 634 backup_retention_period = 1 635 636 parameter_group_name = "default.mysql5.6" 637 638 monitoring_role_arn = "${aws_iam_role.enhanced_policy_role.arn}" 639 monitoring_interval = "5" 640 641 skip_final_snapshot = true 642 } 643 `