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