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