github.com/memsql/terraform@v0.7.0-rc2.0.20160706152241-21e2173e0a32/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("iops", v.Iops) 641 d.Set("copy_tags_to_snapshot", v.CopyTagsToSnapshot) 642 d.Set("auto_minor_version_upgrade", v.AutoMinorVersionUpgrade) 643 d.Set("storage_type", v.StorageType) 644 d.Set("instance_class", v.DBInstanceClass) 645 d.Set("availability_zone", v.AvailabilityZone) 646 d.Set("backup_retention_period", v.BackupRetentionPeriod) 647 d.Set("backup_window", v.PreferredBackupWindow) 648 d.Set("license_model", v.LicenseModel) 649 d.Set("maintenance_window", v.PreferredMaintenanceWindow) 650 d.Set("publicly_accessible", v.PubliclyAccessible) 651 d.Set("multi_az", v.MultiAZ) 652 d.Set("kms_key_id", v.KmsKeyId) 653 if v.DBSubnetGroup != nil { 654 d.Set("db_subnet_group_name", v.DBSubnetGroup.DBSubnetGroupName) 655 } 656 657 if v.CharacterSetName != nil { 658 d.Set("character_set_name", v.CharacterSetName) 659 } 660 661 if len(v.DBParameterGroups) > 0 { 662 d.Set("parameter_group_name", v.DBParameterGroups[0].DBParameterGroupName) 663 } 664 665 if v.Endpoint != nil { 666 d.Set("port", v.Endpoint.Port) 667 d.Set("address", v.Endpoint.Address) 668 669 if v.Endpoint.Address != nil && v.Endpoint.Port != nil { 670 d.Set("endpoint", 671 fmt.Sprintf("%s:%d", *v.Endpoint.Address, *v.Endpoint.Port)) 672 } 673 } 674 675 d.Set("status", v.DBInstanceStatus) 676 d.Set("storage_encrypted", v.StorageEncrypted) 677 if v.OptionGroupMemberships != nil { 678 d.Set("option_group_name", v.OptionGroupMemberships[0].OptionGroupName) 679 } 680 681 if v.MonitoringInterval != nil { 682 d.Set("monitoring_interval", v.MonitoringInterval) 683 } 684 685 if v.MonitoringRoleArn != nil { 686 d.Set("monitoring_role_arn", v.MonitoringRoleArn) 687 } 688 689 // list tags for resource 690 // set tags 691 conn := meta.(*AWSClient).rdsconn 692 arn, err := buildRDSARN(d.Id(), meta) 693 if err != nil { 694 name := "<empty>" 695 if v.DBName != nil && *v.DBName != "" { 696 name = *v.DBName 697 } 698 log.Printf("[DEBUG] Error building ARN for DB Instance, not setting Tags for DB %s", name) 699 } else { 700 d.Set("arn", arn) 701 resp, err := conn.ListTagsForResource(&rds.ListTagsForResourceInput{ 702 ResourceName: aws.String(arn), 703 }) 704 705 if err != nil { 706 log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn) 707 } 708 709 var dt []*rds.Tag 710 if len(resp.TagList) > 0 { 711 dt = resp.TagList 712 } 713 d.Set("tags", tagsToMapRDS(dt)) 714 } 715 716 // Create an empty schema.Set to hold all vpc security group ids 717 ids := &schema.Set{ 718 F: schema.HashString, 719 } 720 for _, v := range v.VpcSecurityGroups { 721 ids.Add(*v.VpcSecurityGroupId) 722 } 723 d.Set("vpc_security_group_ids", ids) 724 725 // Create an empty schema.Set to hold all security group names 726 sgn := &schema.Set{ 727 F: schema.HashString, 728 } 729 for _, v := range v.DBSecurityGroups { 730 sgn.Add(*v.DBSecurityGroupName) 731 } 732 d.Set("security_group_names", sgn) 733 734 // replica things 735 736 var replicas []string 737 for _, v := range v.ReadReplicaDBInstanceIdentifiers { 738 replicas = append(replicas, *v) 739 } 740 if err := d.Set("replicas", replicas); err != nil { 741 return fmt.Errorf("[DEBUG] Error setting replicas attribute: %#v, error: %#v", replicas, err) 742 } 743 744 d.Set("replicate_source_db", v.ReadReplicaSourceDBInstanceIdentifier) 745 746 return nil 747 } 748 749 func resourceAwsDbInstanceDelete(d *schema.ResourceData, meta interface{}) error { 750 conn := meta.(*AWSClient).rdsconn 751 752 log.Printf("[DEBUG] DB Instance destroy: %v", d.Id()) 753 754 opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())} 755 756 skipFinalSnapshot := d.Get("skip_final_snapshot").(bool) 757 opts.SkipFinalSnapshot = aws.Bool(skipFinalSnapshot) 758 759 if !skipFinalSnapshot { 760 if name, present := d.GetOk("final_snapshot_identifier"); present { 761 opts.FinalDBSnapshotIdentifier = aws.String(name.(string)) 762 } else { 763 return fmt.Errorf("DB Instance FinalSnapshotIdentifier is required when a final snapshot is required") 764 } 765 } 766 767 log.Printf("[DEBUG] DB Instance destroy configuration: %v", opts) 768 if _, err := conn.DeleteDBInstance(&opts); err != nil { 769 return err 770 } 771 772 log.Println( 773 "[INFO] Waiting for DB Instance to be destroyed") 774 stateConf := &resource.StateChangeConf{ 775 Pending: []string{"creating", "backing-up", 776 "modifying", "deleting", "available"}, 777 Target: []string{}, 778 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 779 Timeout: 40 * time.Minute, 780 MinTimeout: 10 * time.Second, 781 Delay: 30 * time.Second, // Wait 30 secs before starting 782 } 783 if _, err := stateConf.WaitForState(); err != nil { 784 return err 785 } 786 787 return nil 788 } 789 790 func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error { 791 conn := meta.(*AWSClient).rdsconn 792 793 d.Partial(true) 794 795 req := &rds.ModifyDBInstanceInput{ 796 ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), 797 DBInstanceIdentifier: aws.String(d.Id()), 798 } 799 d.SetPartial("apply_immediately") 800 801 requestUpdate := false 802 if d.HasChange("allocated_storage") || d.HasChange("iops") { 803 d.SetPartial("allocated_storage") 804 d.SetPartial("iops") 805 req.Iops = aws.Int64(int64(d.Get("iops").(int))) 806 req.AllocatedStorage = aws.Int64(int64(d.Get("allocated_storage").(int))) 807 requestUpdate = true 808 } 809 if d.HasChange("allow_major_version_upgrade") { 810 d.SetPartial("allow_major_version_upgrade") 811 req.AllowMajorVersionUpgrade = aws.Bool(d.Get("allow_major_version_upgrade").(bool)) 812 requestUpdate = true 813 } 814 if d.HasChange("backup_retention_period") { 815 d.SetPartial("backup_retention_period") 816 req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_period").(int))) 817 requestUpdate = true 818 } 819 if d.HasChange("copy_tags_to_snapshot") { 820 d.SetPartial("copy_tags_to_snapshot") 821 req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool)) 822 requestUpdate = true 823 } 824 if d.HasChange("instance_class") { 825 d.SetPartial("instance_class") 826 req.DBInstanceClass = aws.String(d.Get("instance_class").(string)) 827 requestUpdate = true 828 } 829 if d.HasChange("parameter_group_name") { 830 d.SetPartial("parameter_group_name") 831 req.DBParameterGroupName = aws.String(d.Get("parameter_group_name").(string)) 832 requestUpdate = true 833 } 834 if d.HasChange("engine_version") { 835 d.SetPartial("engine_version") 836 req.EngineVersion = aws.String(d.Get("engine_version").(string)) 837 requestUpdate = true 838 } 839 if d.HasChange("backup_window") { 840 d.SetPartial("backup_window") 841 req.PreferredBackupWindow = aws.String(d.Get("backup_window").(string)) 842 requestUpdate = true 843 } 844 if d.HasChange("maintenance_window") { 845 d.SetPartial("maintenance_window") 846 req.PreferredMaintenanceWindow = aws.String(d.Get("maintenance_window").(string)) 847 requestUpdate = true 848 } 849 if d.HasChange("password") { 850 d.SetPartial("password") 851 req.MasterUserPassword = aws.String(d.Get("password").(string)) 852 requestUpdate = true 853 } 854 if d.HasChange("multi_az") { 855 d.SetPartial("multi_az") 856 req.MultiAZ = aws.Bool(d.Get("multi_az").(bool)) 857 requestUpdate = true 858 } 859 if d.HasChange("publicly_accessible") { 860 d.SetPartial("publicly_accessible") 861 req.PubliclyAccessible = aws.Bool(d.Get("publicly_accessible").(bool)) 862 requestUpdate = true 863 } 864 if d.HasChange("storage_type") { 865 d.SetPartial("storage_type") 866 req.StorageType = aws.String(d.Get("storage_type").(string)) 867 requestUpdate = true 868 869 if *req.StorageType == "io1" { 870 req.Iops = aws.Int64(int64(d.Get("iops").(int))) 871 } 872 } 873 if d.HasChange("auto_minor_version_upgrade") { 874 d.SetPartial("auto_minor_version_upgrade") 875 req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) 876 requestUpdate = true 877 } 878 879 if d.HasChange("monitoring_role_arn") { 880 d.SetPartial("monitoring_role_arn") 881 req.MonitoringRoleArn = aws.String(d.Get("monitoring_role_arn").(string)) 882 requestUpdate = true 883 } 884 885 if d.HasChange("monitoring_interval") { 886 d.SetPartial("monitoring_interval") 887 req.MonitoringInterval = aws.Int64(int64(d.Get("monitoring_interval").(int))) 888 requestUpdate = true 889 } 890 891 if d.HasChange("vpc_security_group_ids") { 892 if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { 893 var s []*string 894 for _, v := range attr.List() { 895 s = append(s, aws.String(v.(string))) 896 } 897 req.VpcSecurityGroupIds = s 898 } 899 requestUpdate = true 900 } 901 902 if d.HasChange("security_group_names") { 903 if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { 904 var s []*string 905 for _, v := range attr.List() { 906 s = append(s, aws.String(v.(string))) 907 } 908 req.DBSecurityGroups = s 909 } 910 requestUpdate = true 911 } 912 913 if d.HasChange("option_group_name") { 914 d.SetPartial("option_group_name") 915 req.OptionGroupName = aws.String(d.Get("option_group_name").(string)) 916 requestUpdate = true 917 } 918 919 log.Printf("[DEBUG] Send DB Instance Modification request: %t", requestUpdate) 920 if requestUpdate { 921 log.Printf("[DEBUG] DB Instance Modification request: %s", req) 922 _, err := conn.ModifyDBInstance(req) 923 if err != nil { 924 return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err) 925 } 926 } 927 928 // separate request to promote a database 929 if d.HasChange("replicate_source_db") { 930 if d.Get("replicate_source_db").(string) == "" { 931 // promote 932 opts := rds.PromoteReadReplicaInput{ 933 DBInstanceIdentifier: aws.String(d.Id()), 934 } 935 attr := d.Get("backup_retention_period") 936 opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int))) 937 if attr, ok := d.GetOk("backup_window"); ok { 938 opts.PreferredBackupWindow = aws.String(attr.(string)) 939 } 940 _, err := conn.PromoteReadReplica(&opts) 941 if err != nil { 942 return fmt.Errorf("Error promoting database: %#v", err) 943 } 944 d.Set("replicate_source_db", "") 945 } else { 946 return fmt.Errorf("cannot elect new source database for replication") 947 } 948 } 949 950 if arn, err := buildRDSARN(d.Id(), meta); err == nil { 951 if err := setTagsRDS(conn, d, arn); err != nil { 952 return err 953 } else { 954 d.SetPartial("tags") 955 } 956 } 957 d.Partial(false) 958 959 return resourceAwsDbInstanceRead(d, meta) 960 } 961 962 // resourceAwsDbInstanceRetrieve fetches DBInstance information from the AWS 963 // API. It returns an error if there is a communication problem or unexpected 964 // error with AWS. When the DBInstance is not found, it returns no error and a 965 // nil pointer. 966 func resourceAwsDbInstanceRetrieve( 967 d *schema.ResourceData, meta interface{}) (*rds.DBInstance, error) { 968 conn := meta.(*AWSClient).rdsconn 969 970 opts := rds.DescribeDBInstancesInput{ 971 DBInstanceIdentifier: aws.String(d.Id()), 972 } 973 974 log.Printf("[DEBUG] DB Instance describe configuration: %#v", opts) 975 976 resp, err := conn.DescribeDBInstances(&opts) 977 if err != nil { 978 dbinstanceerr, ok := err.(awserr.Error) 979 if ok && dbinstanceerr.Code() == "DBInstanceNotFound" { 980 return nil, nil 981 } 982 return nil, fmt.Errorf("Error retrieving DB Instances: %s", err) 983 } 984 985 if len(resp.DBInstances) != 1 || 986 *resp.DBInstances[0].DBInstanceIdentifier != d.Id() { 987 if err != nil { 988 return nil, nil 989 } 990 } 991 992 return resp.DBInstances[0], nil 993 } 994 995 func resourceAwsDbInstanceStateRefreshFunc( 996 d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { 997 return func() (interface{}, string, error) { 998 v, err := resourceAwsDbInstanceRetrieve(d, meta) 999 1000 if err != nil { 1001 log.Printf("Error on retrieving DB Instance when waiting: %s", err) 1002 return nil, "", err 1003 } 1004 1005 if v == nil { 1006 return nil, "", nil 1007 } 1008 1009 if v.DBInstanceStatus != nil { 1010 log.Printf("[DEBUG] DB Instance status for instance %s: %s", d.Id(), *v.DBInstanceStatus) 1011 } 1012 1013 return v, *v.DBInstanceStatus, nil 1014 } 1015 } 1016 1017 func buildRDSARN(identifier string, meta interface{}) (string, error) { 1018 iamconn := meta.(*AWSClient).iamconn 1019 region := meta.(*AWSClient).region 1020 // An zero value GetUserInput{} defers to the currently logged in user 1021 resp, err := iamconn.GetUser(&iam.GetUserInput{}) 1022 if err != nil { 1023 return "", err 1024 } 1025 userARN := *resp.User.Arn 1026 accountID := strings.Split(userARN, ":")[4] 1027 arn := fmt.Sprintf("arn:aws:rds:%s:%s:db:%s", region, accountID, identifier) 1028 return arn, nil 1029 }