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