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