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