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