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