github.com/articulate/terraform@v0.6.13-0.20160303003731-8d31c93862de/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 = conn.CreateDBInstance(&opts) 538 if err != nil { 539 return fmt.Errorf("Error creating DB Instance: %s", err) 540 } 541 } 542 543 d.SetId(d.Get("identifier").(string)) 544 545 log.Printf("[INFO] DB Instance ID: %s", d.Id()) 546 547 log.Println( 548 "[INFO] Waiting for DB Instance to be available") 549 550 stateConf := &resource.StateChangeConf{ 551 Pending: []string{"creating", "backing-up", "modifying", "resetting-master-credentials", 552 "maintenance", "renaming", "rebooting", "upgrading"}, 553 Target: []string{"available"}, 554 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 555 Timeout: 40 * time.Minute, 556 MinTimeout: 10 * time.Second, 557 Delay: 30 * time.Second, // Wait 30 secs before starting 558 } 559 560 // Wait, catching any errors 561 _, err := stateConf.WaitForState() 562 if err != nil { 563 return err 564 } 565 566 return resourceAwsDbInstanceRead(d, meta) 567 } 568 569 func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { 570 v, err := resourceAwsDbInstanceRetrieve(d, meta) 571 572 if err != nil { 573 return err 574 } 575 if v == nil { 576 d.SetId("") 577 return nil 578 } 579 580 d.Set("name", v.DBName) 581 d.Set("username", v.MasterUsername) 582 d.Set("engine", v.Engine) 583 d.Set("engine_version", v.EngineVersion) 584 d.Set("allocated_storage", v.AllocatedStorage) 585 d.Set("copy_tags_to_snapshot", v.CopyTagsToSnapshot) 586 d.Set("auto_minor_version_upgrade", v.AutoMinorVersionUpgrade) 587 d.Set("storage_type", v.StorageType) 588 d.Set("instance_class", v.DBInstanceClass) 589 d.Set("availability_zone", v.AvailabilityZone) 590 d.Set("backup_retention_period", v.BackupRetentionPeriod) 591 d.Set("backup_window", v.PreferredBackupWindow) 592 d.Set("license_model", v.LicenseModel) 593 d.Set("maintenance_window", v.PreferredMaintenanceWindow) 594 d.Set("multi_az", v.MultiAZ) 595 if v.DBSubnetGroup != nil { 596 d.Set("db_subnet_group_name", v.DBSubnetGroup.DBSubnetGroupName) 597 } 598 599 if len(v.DBParameterGroups) > 0 { 600 d.Set("parameter_group_name", v.DBParameterGroups[0].DBParameterGroupName) 601 } 602 603 if v.Endpoint != nil { 604 d.Set("port", v.Endpoint.Port) 605 d.Set("address", v.Endpoint.Address) 606 607 if v.Endpoint.Address != nil && v.Endpoint.Port != nil { 608 d.Set("endpoint", 609 fmt.Sprintf("%s:%d", *v.Endpoint.Address, *v.Endpoint.Port)) 610 } 611 } 612 613 d.Set("status", v.DBInstanceStatus) 614 d.Set("storage_encrypted", v.StorageEncrypted) 615 616 if v.MonitoringInterval != nil { 617 d.Set("monitoring_interval", v.MonitoringInterval) 618 } 619 620 if v.MonitoringRoleArn != nil { 621 d.Set("monitoring_role_arn", v.MonitoringRoleArn) 622 } 623 624 // list tags for resource 625 // set tags 626 conn := meta.(*AWSClient).rdsconn 627 arn, err := buildRDSARN(d.Id(), meta) 628 if err != nil { 629 name := "<empty>" 630 if v.DBName != nil && *v.DBName != "" { 631 name = *v.DBName 632 } 633 log.Printf("[DEBUG] Error building ARN for DB Instance, not setting Tags for DB %s", name) 634 } else { 635 d.Set("arn", arn) 636 resp, err := conn.ListTagsForResource(&rds.ListTagsForResourceInput{ 637 ResourceName: aws.String(arn), 638 }) 639 640 if err != nil { 641 log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn) 642 } 643 644 var dt []*rds.Tag 645 if len(resp.TagList) > 0 { 646 dt = resp.TagList 647 } 648 d.Set("tags", tagsToMapRDS(dt)) 649 } 650 651 // Create an empty schema.Set to hold all vpc security group ids 652 ids := &schema.Set{ 653 F: schema.HashString, 654 } 655 for _, v := range v.VpcSecurityGroups { 656 ids.Add(*v.VpcSecurityGroupId) 657 } 658 d.Set("vpc_security_group_ids", ids) 659 660 // Create an empty schema.Set to hold all security group names 661 sgn := &schema.Set{ 662 F: schema.HashString, 663 } 664 for _, v := range v.DBSecurityGroups { 665 sgn.Add(*v.DBSecurityGroupName) 666 } 667 d.Set("security_group_names", sgn) 668 669 // replica things 670 671 var replicas []string 672 for _, v := range v.ReadReplicaDBInstanceIdentifiers { 673 replicas = append(replicas, *v) 674 } 675 if err := d.Set("replicas", replicas); err != nil { 676 return fmt.Errorf("[DEBUG] Error setting replicas attribute: %#v, error: %#v", replicas, err) 677 } 678 679 d.Set("replicate_source_db", v.ReadReplicaSourceDBInstanceIdentifier) 680 681 return nil 682 } 683 684 func resourceAwsDbInstanceDelete(d *schema.ResourceData, meta interface{}) error { 685 conn := meta.(*AWSClient).rdsconn 686 687 log.Printf("[DEBUG] DB Instance destroy: %v", d.Id()) 688 689 opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())} 690 691 skipFinalSnapshot := d.Get("skip_final_snapshot").(bool) 692 opts.SkipFinalSnapshot = aws.Bool(skipFinalSnapshot) 693 694 if !skipFinalSnapshot { 695 if name, present := d.GetOk("final_snapshot_identifier"); present { 696 opts.FinalDBSnapshotIdentifier = aws.String(name.(string)) 697 } else { 698 return fmt.Errorf("DB Instance FinalSnapshotIdentifier is required when a final snapshot is required") 699 } 700 } 701 702 log.Printf("[DEBUG] DB Instance destroy configuration: %v", opts) 703 if _, err := conn.DeleteDBInstance(&opts); err != nil { 704 return err 705 } 706 707 log.Println( 708 "[INFO] Waiting for DB Instance to be destroyed") 709 stateConf := &resource.StateChangeConf{ 710 Pending: []string{"creating", "backing-up", 711 "modifying", "deleting", "available"}, 712 Target: []string{}, 713 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 714 Timeout: 40 * time.Minute, 715 MinTimeout: 10 * time.Second, 716 Delay: 30 * time.Second, // Wait 30 secs before starting 717 } 718 if _, err := stateConf.WaitForState(); err != nil { 719 return err 720 } 721 722 return nil 723 } 724 725 func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error { 726 conn := meta.(*AWSClient).rdsconn 727 728 d.Partial(true) 729 730 req := &rds.ModifyDBInstanceInput{ 731 ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), 732 DBInstanceIdentifier: aws.String(d.Id()), 733 } 734 d.SetPartial("apply_immediately") 735 736 requestUpdate := false 737 if d.HasChange("allocated_storage") { 738 d.SetPartial("allocated_storage") 739 req.AllocatedStorage = aws.Int64(int64(d.Get("allocated_storage").(int))) 740 requestUpdate = true 741 } 742 if d.HasChange("allow_major_version_upgrade") { 743 d.SetPartial("allow_major_version_upgrade") 744 req.AllowMajorVersionUpgrade = aws.Bool(d.Get("allow_major_version_upgrade").(bool)) 745 requestUpdate = true 746 } 747 if d.HasChange("backup_retention_period") { 748 d.SetPartial("backup_retention_period") 749 req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_period").(int))) 750 requestUpdate = true 751 } 752 if d.HasChange("copy_tags_to_snapshot") { 753 d.SetPartial("copy_tags_to_snapshot") 754 req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool)) 755 requestUpdate = true 756 } 757 if d.HasChange("instance_class") { 758 d.SetPartial("instance_class") 759 req.DBInstanceClass = aws.String(d.Get("instance_class").(string)) 760 requestUpdate = true 761 } 762 if d.HasChange("parameter_group_name") { 763 d.SetPartial("parameter_group_name") 764 req.DBParameterGroupName = aws.String(d.Get("parameter_group_name").(string)) 765 requestUpdate = true 766 } 767 if d.HasChange("engine_version") { 768 d.SetPartial("engine_version") 769 req.EngineVersion = aws.String(d.Get("engine_version").(string)) 770 requestUpdate = true 771 } 772 if d.HasChange("iops") { 773 d.SetPartial("iops") 774 req.Iops = aws.Int64(int64(d.Get("iops").(int))) 775 requestUpdate = true 776 } 777 if d.HasChange("backup_window") { 778 d.SetPartial("backup_window") 779 req.PreferredBackupWindow = aws.String(d.Get("backup_window").(string)) 780 requestUpdate = true 781 } 782 if d.HasChange("maintenance_window") { 783 d.SetPartial("maintenance_window") 784 req.PreferredMaintenanceWindow = aws.String(d.Get("maintenance_window").(string)) 785 requestUpdate = true 786 } 787 if d.HasChange("password") { 788 d.SetPartial("password") 789 req.MasterUserPassword = aws.String(d.Get("password").(string)) 790 requestUpdate = true 791 } 792 if d.HasChange("multi_az") { 793 d.SetPartial("multi_az") 794 req.MultiAZ = aws.Bool(d.Get("multi_az").(bool)) 795 requestUpdate = true 796 } 797 if d.HasChange("publicly_accessible") { 798 d.SetPartial("publicly_accessible") 799 req.PubliclyAccessible = aws.Bool(d.Get("publicly_accessible").(bool)) 800 requestUpdate = true 801 } 802 if d.HasChange("storage_type") { 803 d.SetPartial("storage_type") 804 req.StorageType = aws.String(d.Get("storage_type").(string)) 805 requestUpdate = true 806 } 807 if d.HasChange("auto_minor_version_upgrade") { 808 d.SetPartial("auto_minor_version_upgrade") 809 req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) 810 requestUpdate = true 811 } 812 813 if d.HasChange("monitoring_role_arn") { 814 d.SetPartial("monitoring_role_arn") 815 req.MonitoringRoleArn = aws.String(d.Get("monitoring_role_arn").(string)) 816 requestUpdate = true 817 } 818 819 if d.HasChange("monitoring_interval") { 820 d.SetPartial("monitoring_interval") 821 req.MonitoringInterval = aws.Int64(int64(d.Get("monitoring_interval").(int))) 822 requestUpdate = true 823 } 824 825 if d.HasChange("vpc_security_group_ids") { 826 if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { 827 var s []*string 828 for _, v := range attr.List() { 829 s = append(s, aws.String(v.(string))) 830 } 831 req.VpcSecurityGroupIds = s 832 } 833 requestUpdate = true 834 } 835 836 if d.HasChange("security_group_names") { 837 if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { 838 var s []*string 839 for _, v := range attr.List() { 840 s = append(s, aws.String(v.(string))) 841 } 842 req.DBSecurityGroups = s 843 } 844 requestUpdate = true 845 } 846 847 log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate) 848 if requestUpdate { 849 log.Printf("[DEBUG] DB Instance Modification request: %#v", req) 850 _, err := conn.ModifyDBInstance(req) 851 if err != nil { 852 return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err) 853 } 854 } 855 856 // separate request to promote a database 857 if d.HasChange("replicate_source_db") { 858 if d.Get("replicate_source_db").(string) == "" { 859 // promote 860 opts := rds.PromoteReadReplicaInput{ 861 DBInstanceIdentifier: aws.String(d.Id()), 862 } 863 attr := d.Get("backup_retention_period") 864 opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int))) 865 if attr, ok := d.GetOk("backup_window"); ok { 866 opts.PreferredBackupWindow = aws.String(attr.(string)) 867 } 868 _, err := conn.PromoteReadReplica(&opts) 869 if err != nil { 870 return fmt.Errorf("Error promoting database: %#v", err) 871 } 872 d.Set("replicate_source_db", "") 873 } else { 874 return fmt.Errorf("cannot elect new source database for replication") 875 } 876 } 877 878 if arn, err := buildRDSARN(d.Id(), meta); err == nil { 879 if err := setTagsRDS(conn, d, arn); err != nil { 880 return err 881 } else { 882 d.SetPartial("tags") 883 } 884 } 885 d.Partial(false) 886 887 return resourceAwsDbInstanceRead(d, meta) 888 } 889 890 func resourceAwsDbInstanceRetrieve( 891 d *schema.ResourceData, meta interface{}) (*rds.DBInstance, error) { 892 conn := meta.(*AWSClient).rdsconn 893 894 opts := rds.DescribeDBInstancesInput{ 895 DBInstanceIdentifier: aws.String(d.Id()), 896 } 897 898 log.Printf("[DEBUG] DB Instance describe configuration: %#v", opts) 899 900 resp, err := conn.DescribeDBInstances(&opts) 901 if err != nil { 902 dbinstanceerr, ok := err.(awserr.Error) 903 if ok && dbinstanceerr.Code() == "DBInstanceNotFound" { 904 return nil, nil 905 } 906 return nil, fmt.Errorf("Error retrieving DB Instances: %s", err) 907 } 908 909 if len(resp.DBInstances) != 1 || 910 *resp.DBInstances[0].DBInstanceIdentifier != d.Id() { 911 if err != nil { 912 return nil, nil 913 } 914 } 915 916 return resp.DBInstances[0], nil 917 } 918 919 func resourceAwsDbInstanceStateRefreshFunc( 920 d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { 921 return func() (interface{}, string, error) { 922 v, err := resourceAwsDbInstanceRetrieve(d, meta) 923 924 if err != nil { 925 log.Printf("Error on retrieving DB Instance when waiting: %s", err) 926 return nil, "", err 927 } 928 929 if v == nil { 930 return nil, "", nil 931 } 932 933 if v.DBInstanceStatus != nil { 934 log.Printf("[DEBUG] DB Instance status for instance %s: %s", d.Id(), *v.DBInstanceStatus) 935 } 936 937 return v, *v.DBInstanceStatus, nil 938 } 939 } 940 941 func buildRDSARN(identifier string, meta interface{}) (string, error) { 942 iamconn := meta.(*AWSClient).iamconn 943 region := meta.(*AWSClient).region 944 // An zero value GetUserInput{} defers to the currently logged in user 945 resp, err := iamconn.GetUser(&iam.GetUserInput{}) 946 if err != nil { 947 return "", err 948 } 949 userARN := *resp.User.Arn 950 accountID := strings.Split(userARN, ":")[4] 951 arn := fmt.Sprintf("arn:aws:rds:%s:%s:db:%s", region, accountID, identifier) 952 return arn, nil 953 }