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