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