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