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