github.com/subuk/terraform@v0.6.14-0.20160317140351-de1567c2e732/builtin/providers/aws/resource_aws_db_instance.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "regexp" 7 "strings" 8 "time" 9 10 "github.com/aws/aws-sdk-go/aws" 11 "github.com/aws/aws-sdk-go/aws/awserr" 12 "github.com/aws/aws-sdk-go/service/iam" 13 "github.com/aws/aws-sdk-go/service/rds" 14 15 "github.com/hashicorp/terraform/helper/resource" 16 "github.com/hashicorp/terraform/helper/schema" 17 ) 18 19 func resourceAwsDbInstance() *schema.Resource { 20 return &schema.Resource{ 21 Create: resourceAwsDbInstanceCreate, 22 Read: resourceAwsDbInstanceRead, 23 Update: resourceAwsDbInstanceUpdate, 24 Delete: resourceAwsDbInstanceDelete, 25 26 Schema: map[string]*schema.Schema{ 27 "name": &schema.Schema{ 28 Type: schema.TypeString, 29 Optional: true, 30 Computed: true, 31 ForceNew: true, 32 }, 33 34 "arn": &schema.Schema{ 35 Type: schema.TypeString, 36 Computed: true, 37 }, 38 39 "username": &schema.Schema{ 40 Type: schema.TypeString, 41 Optional: true, 42 Computed: true, 43 ForceNew: true, 44 }, 45 46 "password": &schema.Schema{ 47 Type: schema.TypeString, 48 Optional: true, 49 }, 50 51 "engine": &schema.Schema{ 52 Type: schema.TypeString, 53 Optional: true, 54 Computed: true, 55 ForceNew: true, 56 StateFunc: func(v interface{}) string { 57 value := v.(string) 58 return strings.ToLower(value) 59 }, 60 }, 61 62 "engine_version": &schema.Schema{ 63 Type: schema.TypeString, 64 Optional: true, 65 Computed: true, 66 }, 67 68 "storage_encrypted": &schema.Schema{ 69 Type: schema.TypeBool, 70 Optional: true, 71 ForceNew: true, 72 }, 73 74 "allocated_storage": &schema.Schema{ 75 Type: schema.TypeInt, 76 Optional: true, 77 Computed: true, 78 }, 79 80 "storage_type": &schema.Schema{ 81 Type: schema.TypeString, 82 Optional: true, 83 Computed: true, 84 }, 85 86 "identifier": &schema.Schema{ 87 Type: schema.TypeString, 88 Required: true, 89 ForceNew: true, 90 ValidateFunc: validateRdsId, 91 }, 92 93 "instance_class": &schema.Schema{ 94 Type: schema.TypeString, 95 Required: true, 96 }, 97 98 "availability_zone": &schema.Schema{ 99 Type: schema.TypeString, 100 Optional: true, 101 Computed: true, 102 ForceNew: true, 103 }, 104 105 "backup_retention_period": &schema.Schema{ 106 Type: schema.TypeInt, 107 Optional: true, 108 Computed: true, 109 }, 110 111 "backup_window": &schema.Schema{ 112 Type: schema.TypeString, 113 Optional: true, 114 Computed: true, 115 }, 116 117 "iops": &schema.Schema{ 118 Type: schema.TypeInt, 119 Optional: true, 120 }, 121 122 "license_model": &schema.Schema{ 123 Type: schema.TypeString, 124 Optional: true, 125 Computed: true, 126 }, 127 128 "maintenance_window": &schema.Schema{ 129 Type: schema.TypeString, 130 Optional: true, 131 Computed: true, 132 StateFunc: func(v interface{}) string { 133 if v != nil { 134 value := v.(string) 135 return strings.ToLower(value) 136 } 137 return "" 138 }, 139 }, 140 141 "multi_az": &schema.Schema{ 142 Type: schema.TypeBool, 143 Optional: true, 144 Computed: true, 145 }, 146 147 "port": &schema.Schema{ 148 Type: schema.TypeInt, 149 Optional: true, 150 Computed: true, 151 ForceNew: true, 152 }, 153 154 "publicly_accessible": &schema.Schema{ 155 Type: schema.TypeBool, 156 Optional: true, 157 Computed: true, 158 }, 159 160 "vpc_security_group_ids": &schema.Schema{ 161 Type: schema.TypeSet, 162 Optional: true, 163 Computed: true, 164 Elem: &schema.Schema{Type: schema.TypeString}, 165 Set: schema.HashString, 166 }, 167 168 "security_group_names": &schema.Schema{ 169 Type: schema.TypeSet, 170 Optional: true, 171 Elem: &schema.Schema{Type: schema.TypeString}, 172 Set: schema.HashString, 173 }, 174 175 "final_snapshot_identifier": &schema.Schema{ 176 Type: schema.TypeString, 177 Optional: true, 178 ValidateFunc: func(v interface{}, k string) (ws []string, es []error) { 179 value := v.(string) 180 if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) { 181 es = append(es, fmt.Errorf( 182 "only alphanumeric characters and hyphens allowed in %q", k)) 183 } 184 if regexp.MustCompile(`--`).MatchString(value) { 185 es = append(es, fmt.Errorf("%q cannot contain two consecutive hyphens", k)) 186 } 187 if regexp.MustCompile(`-$`).MatchString(value) { 188 es = append(es, fmt.Errorf("%q cannot end in a hyphen", k)) 189 } 190 return 191 }, 192 }, 193 194 "skip_final_snapshot": &schema.Schema{ 195 Type: schema.TypeBool, 196 Optional: true, 197 Default: true, 198 }, 199 200 "copy_tags_to_snapshot": &schema.Schema{ 201 Type: schema.TypeBool, 202 Optional: true, 203 Default: false, 204 }, 205 206 "db_subnet_group_name": &schema.Schema{ 207 Type: schema.TypeString, 208 Optional: true, 209 ForceNew: true, 210 Computed: true, 211 }, 212 213 "parameter_group_name": &schema.Schema{ 214 Type: schema.TypeString, 215 Optional: true, 216 Computed: true, 217 }, 218 219 "address": &schema.Schema{ 220 Type: schema.TypeString, 221 Computed: true, 222 }, 223 224 "endpoint": &schema.Schema{ 225 Type: schema.TypeString, 226 Computed: true, 227 }, 228 229 "status": &schema.Schema{ 230 Type: schema.TypeString, 231 Computed: true, 232 }, 233 234 // apply_immediately is used to determine when the update modifications 235 // take place. 236 // See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html 237 "apply_immediately": &schema.Schema{ 238 Type: schema.TypeBool, 239 Optional: true, 240 Computed: true, 241 }, 242 243 "replicate_source_db": &schema.Schema{ 244 Type: schema.TypeString, 245 Optional: true, 246 }, 247 248 "replicas": &schema.Schema{ 249 Type: schema.TypeList, 250 Computed: true, 251 Elem: &schema.Schema{Type: schema.TypeString}, 252 }, 253 254 "snapshot_identifier": &schema.Schema{ 255 Type: schema.TypeString, 256 Computed: false, 257 Optional: true, 258 Elem: &schema.Schema{Type: schema.TypeString}, 259 }, 260 261 "auto_minor_version_upgrade": &schema.Schema{ 262 Type: schema.TypeBool, 263 Optional: true, 264 Default: true, 265 }, 266 267 "allow_major_version_upgrade": &schema.Schema{ 268 Type: schema.TypeBool, 269 Computed: false, 270 Optional: true, 271 }, 272 273 "monitoring_role_arn": &schema.Schema{ 274 Type: schema.TypeString, 275 Optional: true, 276 Computed: true, 277 }, 278 279 "monitoring_interval": &schema.Schema{ 280 Type: schema.TypeInt, 281 Optional: true, 282 Default: 0, 283 }, 284 285 "tags": tagsSchema(), 286 }, 287 } 288 } 289 290 func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error { 291 conn := meta.(*AWSClient).rdsconn 292 tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) 293 294 if v, ok := d.GetOk("replicate_source_db"); ok { 295 opts := rds.CreateDBInstanceReadReplicaInput{ 296 SourceDBInstanceIdentifier: aws.String(v.(string)), 297 CopyTagsToSnapshot: aws.Bool(d.Get("copy_tags_to_snapshot").(bool)), 298 DBInstanceClass: aws.String(d.Get("instance_class").(string)), 299 DBInstanceIdentifier: aws.String(d.Get("identifier").(string)), 300 Tags: tags, 301 } 302 if attr, ok := d.GetOk("iops"); ok { 303 opts.Iops = aws.Int64(int64(attr.(int))) 304 } 305 306 if attr, ok := d.GetOk("port"); ok { 307 opts.Port = aws.Int64(int64(attr.(int))) 308 } 309 310 if attr, ok := d.GetOk("availability_zone"); ok { 311 opts.AvailabilityZone = aws.String(attr.(string)) 312 } 313 314 if attr, ok := d.GetOk("storage_type"); ok { 315 opts.StorageType = aws.String(attr.(string)) 316 } 317 318 if attr, ok := d.GetOk("publicly_accessible"); ok { 319 opts.PubliclyAccessible = aws.Bool(attr.(bool)) 320 } 321 322 if attr, ok := d.GetOk("db_subnet_group_name"); ok { 323 opts.DBSubnetGroupName = aws.String(attr.(string)) 324 } 325 326 if attr, ok := d.GetOk("monitoring_role_arn"); ok { 327 opts.MonitoringRoleArn = aws.String(attr.(string)) 328 } 329 330 if attr, ok := d.GetOk("monitoring_interval"); ok { 331 opts.MonitoringInterval = aws.Int64(int64(attr.(int))) 332 } 333 334 log.Printf("[DEBUG] DB Instance Replica create configuration: %#v", opts) 335 _, err := conn.CreateDBInstanceReadReplica(&opts) 336 if err != nil { 337 return fmt.Errorf("Error creating DB Instance: %s", err) 338 } 339 } else if _, ok := d.GetOk("snapshot_identifier"); ok { 340 opts := rds.RestoreDBInstanceFromDBSnapshotInput{ 341 DBInstanceClass: aws.String(d.Get("instance_class").(string)), 342 DBInstanceIdentifier: aws.String(d.Get("identifier").(string)), 343 DBSnapshotIdentifier: aws.String(d.Get("snapshot_identifier").(string)), 344 AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)), 345 Tags: tags, 346 CopyTagsToSnapshot: aws.Bool(d.Get("copy_tags_to_snapshot").(bool)), 347 } 348 349 if attr, ok := d.GetOk("availability_zone"); ok { 350 opts.AvailabilityZone = aws.String(attr.(string)) 351 } 352 353 if attr, ok := d.GetOk("db_subnet_group_name"); ok { 354 opts.DBSubnetGroupName = aws.String(attr.(string)) 355 } 356 357 if attr, ok := d.GetOk("engine"); ok { 358 opts.Engine = aws.String(attr.(string)) 359 } 360 361 if attr, ok := d.GetOk("iops"); ok { 362 opts.Iops = aws.Int64(int64(attr.(int))) 363 } 364 365 if attr, ok := d.GetOk("license_model"); ok { 366 opts.LicenseModel = aws.String(attr.(string)) 367 } 368 369 if attr, ok := d.GetOk("multi_az"); ok { 370 opts.MultiAZ = aws.Bool(attr.(bool)) 371 } 372 373 if attr, ok := d.GetOk("option_group_name"); ok { 374 opts.OptionGroupName = aws.String(attr.(string)) 375 } 376 377 if attr, ok := d.GetOk("port"); ok { 378 opts.Port = aws.Int64(int64(attr.(int))) 379 } 380 381 if attr, ok := d.GetOk("publicly_accessible"); ok { 382 opts.PubliclyAccessible = aws.Bool(attr.(bool)) 383 } 384 385 if attr, ok := d.GetOk("tde_credential_arn"); ok { 386 opts.TdeCredentialArn = aws.String(attr.(string)) 387 } 388 389 if attr, ok := d.GetOk("storage_type"); ok { 390 opts.StorageType = aws.String(attr.(string)) 391 } 392 393 log.Printf("[DEBUG] DB Instance restore from snapshot configuration: %s", opts) 394 _, err := conn.RestoreDBInstanceFromDBSnapshot(&opts) 395 if err != nil { 396 return fmt.Errorf("Error creating DB Instance: %s", err) 397 } 398 399 var sgUpdate bool 400 if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { 401 sgUpdate = true 402 } 403 if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { 404 sgUpdate = true 405 } 406 if sgUpdate { 407 log.Printf("[INFO] DB is restoring from snapshot with default security, but custom security should be set, will now update after snapshot is restored!") 408 409 // wait for instance to get up and then modify security 410 d.SetId(d.Get("identifier").(string)) 411 412 log.Printf("[INFO] DB Instance ID: %s", d.Id()) 413 414 log.Println( 415 "[INFO] Waiting for DB Instance to be available") 416 417 stateConf := &resource.StateChangeConf{ 418 Pending: []string{"creating", "backing-up", "modifying", "resetting-master-credentials", 419 "maintenance", "renaming", "rebooting", "upgrading"}, 420 Target: []string{"available"}, 421 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 422 Timeout: 40 * time.Minute, 423 MinTimeout: 10 * time.Second, 424 Delay: 30 * time.Second, // Wait 30 secs before starting 425 } 426 427 // Wait, catching any errors 428 _, err := stateConf.WaitForState() 429 if err != nil { 430 return err 431 } 432 433 err = resourceAwsDbInstanceUpdate(d, meta) 434 if err != nil { 435 return err 436 } 437 438 } 439 } else { 440 if _, ok := d.GetOk("allocated_storage"); !ok { 441 return fmt.Errorf(`provider.aws: aws_db_instance: %s: "allocated_storage": required field is not set`, d.Get("name").(string)) 442 } 443 if _, ok := d.GetOk("engine"); !ok { 444 return fmt.Errorf(`provider.aws: aws_db_instance: %s: "engine": required field is not set`, d.Get("name").(string)) 445 } 446 if _, ok := d.GetOk("password"); !ok { 447 return fmt.Errorf(`provider.aws: aws_db_instance: %s: "password": required field is not set`, d.Get("name").(string)) 448 } 449 if _, ok := d.GetOk("username"); !ok { 450 return fmt.Errorf(`provider.aws: aws_db_instance: %s: "username": required field is not set`, d.Get("name").(string)) 451 } 452 opts := rds.CreateDBInstanceInput{ 453 AllocatedStorage: aws.Int64(int64(d.Get("allocated_storage").(int))), 454 DBName: aws.String(d.Get("name").(string)), 455 DBInstanceClass: aws.String(d.Get("instance_class").(string)), 456 DBInstanceIdentifier: aws.String(d.Get("identifier").(string)), 457 MasterUsername: aws.String(d.Get("username").(string)), 458 MasterUserPassword: aws.String(d.Get("password").(string)), 459 Engine: aws.String(d.Get("engine").(string)), 460 EngineVersion: aws.String(d.Get("engine_version").(string)), 461 StorageEncrypted: aws.Bool(d.Get("storage_encrypted").(bool)), 462 AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)), 463 Tags: tags, 464 CopyTagsToSnapshot: aws.Bool(d.Get("copy_tags_to_snapshot").(bool)), 465 } 466 467 attr := d.Get("backup_retention_period") 468 opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int))) 469 if attr, ok := d.GetOk("multi_az"); ok { 470 opts.MultiAZ = aws.Bool(attr.(bool)) 471 } 472 473 if attr, ok := d.GetOk("maintenance_window"); ok { 474 opts.PreferredMaintenanceWindow = aws.String(attr.(string)) 475 } 476 477 if attr, ok := d.GetOk("backup_window"); ok { 478 opts.PreferredBackupWindow = aws.String(attr.(string)) 479 } 480 481 if attr, ok := d.GetOk("license_model"); ok { 482 opts.LicenseModel = aws.String(attr.(string)) 483 } 484 if attr, ok := d.GetOk("parameter_group_name"); ok { 485 opts.DBParameterGroupName = aws.String(attr.(string)) 486 } 487 488 if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { 489 var s []*string 490 for _, v := range attr.List() { 491 s = append(s, aws.String(v.(string))) 492 } 493 opts.VpcSecurityGroupIds = s 494 } 495 496 if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { 497 var s []*string 498 for _, v := range attr.List() { 499 s = append(s, aws.String(v.(string))) 500 } 501 opts.DBSecurityGroups = s 502 } 503 if attr, ok := d.GetOk("storage_type"); ok { 504 opts.StorageType = aws.String(attr.(string)) 505 } 506 507 if attr, ok := d.GetOk("db_subnet_group_name"); ok { 508 opts.DBSubnetGroupName = aws.String(attr.(string)) 509 } 510 511 if attr, ok := d.GetOk("iops"); ok { 512 opts.Iops = aws.Int64(int64(attr.(int))) 513 } 514 515 if attr, ok := d.GetOk("port"); ok { 516 opts.Port = aws.Int64(int64(attr.(int))) 517 } 518 519 if attr, ok := d.GetOk("availability_zone"); ok { 520 opts.AvailabilityZone = aws.String(attr.(string)) 521 } 522 523 if attr, ok := d.GetOk("publicly_accessible"); ok { 524 opts.PubliclyAccessible = aws.Bool(attr.(bool)) 525 } 526 527 if attr, ok := d.GetOk("monitoring_role_arn"); ok { 528 opts.MonitoringRoleArn = aws.String(attr.(string)) 529 } 530 531 if attr, ok := d.GetOk("monitoring_interval"); ok { 532 opts.MonitoringInterval = aws.Int64(int64(attr.(int))) 533 } 534 535 log.Printf("[DEBUG] DB Instance create configuration: %#v", opts) 536 var err error 537 err = resource.Retry(5*time.Minute, func() *resource.RetryError { 538 _, err = conn.CreateDBInstance(&opts) 539 if err != nil { 540 if awsErr, ok := err.(awserr.Error); ok { 541 if awsErr.Code() == "InvalidParameterValue" && strings.Contains(awsErr.Message(), "ENHANCED_MONITORING") { 542 return resource.RetryableError(awsErr) 543 } 544 } 545 return resource.NonRetryableError(err) 546 } 547 return nil 548 }) 549 if err != nil { 550 return fmt.Errorf("Error creating DB Instance: %s", err) 551 } 552 } 553 554 d.SetId(d.Get("identifier").(string)) 555 556 log.Printf("[INFO] DB Instance ID: %s", d.Id()) 557 558 log.Println( 559 "[INFO] Waiting for DB Instance to be available") 560 561 stateConf := &resource.StateChangeConf{ 562 Pending: []string{"creating", "backing-up", "modifying", "resetting-master-credentials", 563 "maintenance", "renaming", "rebooting", "upgrading"}, 564 Target: []string{"available"}, 565 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 566 Timeout: 40 * time.Minute, 567 MinTimeout: 10 * time.Second, 568 Delay: 30 * time.Second, // Wait 30 secs before starting 569 } 570 571 // Wait, catching any errors 572 _, err := stateConf.WaitForState() 573 if err != nil { 574 return err 575 } 576 577 return resourceAwsDbInstanceRead(d, meta) 578 } 579 580 func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { 581 v, err := resourceAwsDbInstanceRetrieve(d, meta) 582 583 if err != nil { 584 return err 585 } 586 if v == nil { 587 d.SetId("") 588 return nil 589 } 590 591 d.Set("name", v.DBName) 592 d.Set("username", v.MasterUsername) 593 d.Set("engine", v.Engine) 594 d.Set("engine_version", v.EngineVersion) 595 d.Set("allocated_storage", v.AllocatedStorage) 596 d.Set("copy_tags_to_snapshot", v.CopyTagsToSnapshot) 597 d.Set("auto_minor_version_upgrade", v.AutoMinorVersionUpgrade) 598 d.Set("storage_type", v.StorageType) 599 d.Set("instance_class", v.DBInstanceClass) 600 d.Set("availability_zone", v.AvailabilityZone) 601 d.Set("backup_retention_period", v.BackupRetentionPeriod) 602 d.Set("backup_window", v.PreferredBackupWindow) 603 d.Set("license_model", v.LicenseModel) 604 d.Set("maintenance_window", v.PreferredMaintenanceWindow) 605 d.Set("publicly_accessible", v.PubliclyAccessible) 606 d.Set("multi_az", v.MultiAZ) 607 if v.DBSubnetGroup != nil { 608 d.Set("db_subnet_group_name", v.DBSubnetGroup.DBSubnetGroupName) 609 } 610 611 if len(v.DBParameterGroups) > 0 { 612 d.Set("parameter_group_name", v.DBParameterGroups[0].DBParameterGroupName) 613 } 614 615 if v.Endpoint != nil { 616 d.Set("port", v.Endpoint.Port) 617 d.Set("address", v.Endpoint.Address) 618 619 if v.Endpoint.Address != nil && v.Endpoint.Port != nil { 620 d.Set("endpoint", 621 fmt.Sprintf("%s:%d", *v.Endpoint.Address, *v.Endpoint.Port)) 622 } 623 } 624 625 d.Set("status", v.DBInstanceStatus) 626 d.Set("storage_encrypted", v.StorageEncrypted) 627 628 if v.MonitoringInterval != nil { 629 d.Set("monitoring_interval", v.MonitoringInterval) 630 } 631 632 if v.MonitoringRoleArn != nil { 633 d.Set("monitoring_role_arn", v.MonitoringRoleArn) 634 } 635 636 // list tags for resource 637 // set tags 638 conn := meta.(*AWSClient).rdsconn 639 arn, err := buildRDSARN(d.Id(), meta) 640 if err != nil { 641 name := "<empty>" 642 if v.DBName != nil && *v.DBName != "" { 643 name = *v.DBName 644 } 645 log.Printf("[DEBUG] Error building ARN for DB Instance, not setting Tags for DB %s", name) 646 } else { 647 d.Set("arn", arn) 648 resp, err := conn.ListTagsForResource(&rds.ListTagsForResourceInput{ 649 ResourceName: aws.String(arn), 650 }) 651 652 if err != nil { 653 log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn) 654 } 655 656 var dt []*rds.Tag 657 if len(resp.TagList) > 0 { 658 dt = resp.TagList 659 } 660 d.Set("tags", tagsToMapRDS(dt)) 661 } 662 663 // Create an empty schema.Set to hold all vpc security group ids 664 ids := &schema.Set{ 665 F: schema.HashString, 666 } 667 for _, v := range v.VpcSecurityGroups { 668 ids.Add(*v.VpcSecurityGroupId) 669 } 670 d.Set("vpc_security_group_ids", ids) 671 672 // Create an empty schema.Set to hold all security group names 673 sgn := &schema.Set{ 674 F: schema.HashString, 675 } 676 for _, v := range v.DBSecurityGroups { 677 sgn.Add(*v.DBSecurityGroupName) 678 } 679 d.Set("security_group_names", sgn) 680 681 // replica things 682 683 var replicas []string 684 for _, v := range v.ReadReplicaDBInstanceIdentifiers { 685 replicas = append(replicas, *v) 686 } 687 if err := d.Set("replicas", replicas); err != nil { 688 return fmt.Errorf("[DEBUG] Error setting replicas attribute: %#v, error: %#v", replicas, err) 689 } 690 691 d.Set("replicate_source_db", v.ReadReplicaSourceDBInstanceIdentifier) 692 693 return nil 694 } 695 696 func resourceAwsDbInstanceDelete(d *schema.ResourceData, meta interface{}) error { 697 conn := meta.(*AWSClient).rdsconn 698 699 log.Printf("[DEBUG] DB Instance destroy: %v", d.Id()) 700 701 opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())} 702 703 skipFinalSnapshot := d.Get("skip_final_snapshot").(bool) 704 opts.SkipFinalSnapshot = aws.Bool(skipFinalSnapshot) 705 706 if !skipFinalSnapshot { 707 if name, present := d.GetOk("final_snapshot_identifier"); present { 708 opts.FinalDBSnapshotIdentifier = aws.String(name.(string)) 709 } else { 710 return fmt.Errorf("DB Instance FinalSnapshotIdentifier is required when a final snapshot is required") 711 } 712 } 713 714 log.Printf("[DEBUG] DB Instance destroy configuration: %v", opts) 715 if _, err := conn.DeleteDBInstance(&opts); err != nil { 716 return err 717 } 718 719 log.Println( 720 "[INFO] Waiting for DB Instance to be destroyed") 721 stateConf := &resource.StateChangeConf{ 722 Pending: []string{"creating", "backing-up", 723 "modifying", "deleting", "available"}, 724 Target: []string{}, 725 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 726 Timeout: 40 * time.Minute, 727 MinTimeout: 10 * time.Second, 728 Delay: 30 * time.Second, // Wait 30 secs before starting 729 } 730 if _, err := stateConf.WaitForState(); err != nil { 731 return err 732 } 733 734 return nil 735 } 736 737 func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error { 738 conn := meta.(*AWSClient).rdsconn 739 740 d.Partial(true) 741 742 req := &rds.ModifyDBInstanceInput{ 743 ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), 744 DBInstanceIdentifier: aws.String(d.Id()), 745 } 746 d.SetPartial("apply_immediately") 747 748 requestUpdate := false 749 if d.HasChange("allocated_storage") { 750 d.SetPartial("allocated_storage") 751 req.AllocatedStorage = aws.Int64(int64(d.Get("allocated_storage").(int))) 752 requestUpdate = true 753 } 754 if d.HasChange("allow_major_version_upgrade") { 755 d.SetPartial("allow_major_version_upgrade") 756 req.AllowMajorVersionUpgrade = aws.Bool(d.Get("allow_major_version_upgrade").(bool)) 757 requestUpdate = true 758 } 759 if d.HasChange("backup_retention_period") { 760 d.SetPartial("backup_retention_period") 761 req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_period").(int))) 762 requestUpdate = true 763 } 764 if d.HasChange("copy_tags_to_snapshot") { 765 d.SetPartial("copy_tags_to_snapshot") 766 req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool)) 767 requestUpdate = true 768 } 769 if d.HasChange("instance_class") { 770 d.SetPartial("instance_class") 771 req.DBInstanceClass = aws.String(d.Get("instance_class").(string)) 772 requestUpdate = true 773 } 774 if d.HasChange("parameter_group_name") { 775 d.SetPartial("parameter_group_name") 776 req.DBParameterGroupName = aws.String(d.Get("parameter_group_name").(string)) 777 requestUpdate = true 778 } 779 if d.HasChange("engine_version") { 780 d.SetPartial("engine_version") 781 req.EngineVersion = aws.String(d.Get("engine_version").(string)) 782 requestUpdate = true 783 } 784 if d.HasChange("iops") { 785 d.SetPartial("iops") 786 req.Iops = aws.Int64(int64(d.Get("iops").(int))) 787 requestUpdate = true 788 } 789 if d.HasChange("backup_window") { 790 d.SetPartial("backup_window") 791 req.PreferredBackupWindow = aws.String(d.Get("backup_window").(string)) 792 requestUpdate = true 793 } 794 if d.HasChange("maintenance_window") { 795 d.SetPartial("maintenance_window") 796 req.PreferredMaintenanceWindow = aws.String(d.Get("maintenance_window").(string)) 797 requestUpdate = true 798 } 799 if d.HasChange("password") { 800 d.SetPartial("password") 801 req.MasterUserPassword = aws.String(d.Get("password").(string)) 802 requestUpdate = true 803 } 804 if d.HasChange("multi_az") { 805 d.SetPartial("multi_az") 806 req.MultiAZ = aws.Bool(d.Get("multi_az").(bool)) 807 requestUpdate = true 808 } 809 if d.HasChange("publicly_accessible") { 810 d.SetPartial("publicly_accessible") 811 req.PubliclyAccessible = aws.Bool(d.Get("publicly_accessible").(bool)) 812 requestUpdate = true 813 } 814 if d.HasChange("storage_type") { 815 d.SetPartial("storage_type") 816 req.StorageType = aws.String(d.Get("storage_type").(string)) 817 requestUpdate = true 818 } 819 if d.HasChange("auto_minor_version_upgrade") { 820 d.SetPartial("auto_minor_version_upgrade") 821 req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) 822 requestUpdate = true 823 } 824 825 if d.HasChange("monitoring_role_arn") { 826 d.SetPartial("monitoring_role_arn") 827 req.MonitoringRoleArn = aws.String(d.Get("monitoring_role_arn").(string)) 828 requestUpdate = true 829 } 830 831 if d.HasChange("monitoring_interval") { 832 d.SetPartial("monitoring_interval") 833 req.MonitoringInterval = aws.Int64(int64(d.Get("monitoring_interval").(int))) 834 requestUpdate = true 835 } 836 837 if d.HasChange("vpc_security_group_ids") { 838 if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { 839 var s []*string 840 for _, v := range attr.List() { 841 s = append(s, aws.String(v.(string))) 842 } 843 req.VpcSecurityGroupIds = s 844 } 845 requestUpdate = true 846 } 847 848 if d.HasChange("security_group_names") { 849 if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { 850 var s []*string 851 for _, v := range attr.List() { 852 s = append(s, aws.String(v.(string))) 853 } 854 req.DBSecurityGroups = s 855 } 856 requestUpdate = true 857 } 858 859 log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate) 860 if requestUpdate { 861 log.Printf("[DEBUG] DB Instance Modification request: %#v", req) 862 _, err := conn.ModifyDBInstance(req) 863 if err != nil { 864 return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err) 865 } 866 } 867 868 // separate request to promote a database 869 if d.HasChange("replicate_source_db") { 870 if d.Get("replicate_source_db").(string) == "" { 871 // promote 872 opts := rds.PromoteReadReplicaInput{ 873 DBInstanceIdentifier: aws.String(d.Id()), 874 } 875 attr := d.Get("backup_retention_period") 876 opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int))) 877 if attr, ok := d.GetOk("backup_window"); ok { 878 opts.PreferredBackupWindow = aws.String(attr.(string)) 879 } 880 _, err := conn.PromoteReadReplica(&opts) 881 if err != nil { 882 return fmt.Errorf("Error promoting database: %#v", err) 883 } 884 d.Set("replicate_source_db", "") 885 } else { 886 return fmt.Errorf("cannot elect new source database for replication") 887 } 888 } 889 890 if arn, err := buildRDSARN(d.Id(), meta); err == nil { 891 if err := setTagsRDS(conn, d, arn); err != nil { 892 return err 893 } else { 894 d.SetPartial("tags") 895 } 896 } 897 d.Partial(false) 898 899 return resourceAwsDbInstanceRead(d, meta) 900 } 901 902 func resourceAwsDbInstanceRetrieve( 903 d *schema.ResourceData, meta interface{}) (*rds.DBInstance, error) { 904 conn := meta.(*AWSClient).rdsconn 905 906 opts := rds.DescribeDBInstancesInput{ 907 DBInstanceIdentifier: aws.String(d.Id()), 908 } 909 910 log.Printf("[DEBUG] DB Instance describe configuration: %#v", opts) 911 912 resp, err := conn.DescribeDBInstances(&opts) 913 if err != nil { 914 dbinstanceerr, ok := err.(awserr.Error) 915 if ok && dbinstanceerr.Code() == "DBInstanceNotFound" { 916 return nil, nil 917 } 918 return nil, fmt.Errorf("Error retrieving DB Instances: %s", err) 919 } 920 921 if len(resp.DBInstances) != 1 || 922 *resp.DBInstances[0].DBInstanceIdentifier != d.Id() { 923 if err != nil { 924 return nil, nil 925 } 926 } 927 928 return resp.DBInstances[0], nil 929 } 930 931 func resourceAwsDbInstanceStateRefreshFunc( 932 d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { 933 return func() (interface{}, string, error) { 934 v, err := resourceAwsDbInstanceRetrieve(d, meta) 935 936 if err != nil { 937 log.Printf("Error on retrieving DB Instance when waiting: %s", err) 938 return nil, "", err 939 } 940 941 if v == nil { 942 return nil, "", nil 943 } 944 945 if v.DBInstanceStatus != nil { 946 log.Printf("[DEBUG] DB Instance status for instance %s: %s", d.Id(), *v.DBInstanceStatus) 947 } 948 949 return v, *v.DBInstanceStatus, nil 950 } 951 } 952 953 func buildRDSARN(identifier string, meta interface{}) (string, error) { 954 iamconn := meta.(*AWSClient).iamconn 955 region := meta.(*AWSClient).region 956 // An zero value GetUserInput{} defers to the currently logged in user 957 resp, err := iamconn.GetUser(&iam.GetUserInput{}) 958 if err != nil { 959 return "", err 960 } 961 userARN := *resp.User.Arn 962 accountID := strings.Split(userARN, ":")[4] 963 arn := fmt.Sprintf("arn:aws:rds:%s:%s:db:%s", region, accountID, identifier) 964 return arn, nil 965 }