github.com/ottenhoff/terraform@v0.7.0-rc1.0.20160607213102-ac2d195cc560/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 Computed: true, 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 Tags: tags, 336 } 337 if attr, ok := d.GetOk("iops"); ok { 338 opts.Iops = aws.Int64(int64(attr.(int))) 339 } 340 341 if attr, ok := d.GetOk("port"); ok { 342 opts.Port = aws.Int64(int64(attr.(int))) 343 } 344 345 if attr, ok := d.GetOk("availability_zone"); ok { 346 opts.AvailabilityZone = aws.String(attr.(string)) 347 } 348 349 if attr, ok := d.GetOk("storage_type"); ok { 350 opts.StorageType = aws.String(attr.(string)) 351 } 352 353 if attr, ok := d.GetOk("publicly_accessible"); ok { 354 opts.PubliclyAccessible = aws.Bool(attr.(bool)) 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 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("publicly_accessible"); ok { 422 opts.PubliclyAccessible = aws.Bool(attr.(bool)) 423 } 424 425 if attr, ok := d.GetOk("tde_credential_arn"); ok { 426 opts.TdeCredentialArn = aws.String(attr.(string)) 427 } 428 429 if attr, ok := d.GetOk("storage_type"); ok { 430 opts.StorageType = aws.String(attr.(string)) 431 } 432 433 log.Printf("[DEBUG] DB Instance restore from snapshot configuration: %s", opts) 434 _, err := conn.RestoreDBInstanceFromDBSnapshot(&opts) 435 if err != nil { 436 return fmt.Errorf("Error creating DB Instance: %s", err) 437 } 438 439 var sgUpdate bool 440 if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { 441 sgUpdate = true 442 } 443 if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { 444 sgUpdate = true 445 } 446 if sgUpdate { 447 log.Printf("[INFO] DB is restoring from snapshot with default security, but custom security should be set, will now update after snapshot is restored!") 448 449 // wait for instance to get up and then modify security 450 d.SetId(d.Get("identifier").(string)) 451 452 log.Printf("[INFO] DB Instance ID: %s", d.Id()) 453 454 log.Println( 455 "[INFO] Waiting for DB Instance to be available") 456 457 stateConf := &resource.StateChangeConf{ 458 Pending: []string{"creating", "backing-up", "modifying", "resetting-master-credentials", 459 "maintenance", "renaming", "rebooting", "upgrading"}, 460 Target: []string{"available"}, 461 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 462 Timeout: 40 * time.Minute, 463 MinTimeout: 10 * time.Second, 464 Delay: 30 * time.Second, // Wait 30 secs before starting 465 } 466 467 // Wait, catching any errors 468 _, err := stateConf.WaitForState() 469 if err != nil { 470 return err 471 } 472 473 err = resourceAwsDbInstanceUpdate(d, meta) 474 if err != nil { 475 return err 476 } 477 478 } 479 } else { 480 if _, ok := d.GetOk("allocated_storage"); !ok { 481 return fmt.Errorf(`provider.aws: aws_db_instance: %s: "allocated_storage": required field is not set`, d.Get("name").(string)) 482 } 483 if _, ok := d.GetOk("engine"); !ok { 484 return fmt.Errorf(`provider.aws: aws_db_instance: %s: "engine": required field is not set`, d.Get("name").(string)) 485 } 486 if _, ok := d.GetOk("password"); !ok { 487 return fmt.Errorf(`provider.aws: aws_db_instance: %s: "password": required field is not set`, d.Get("name").(string)) 488 } 489 if _, ok := d.GetOk("username"); !ok { 490 return fmt.Errorf(`provider.aws: aws_db_instance: %s: "username": required field is not set`, d.Get("name").(string)) 491 } 492 opts := rds.CreateDBInstanceInput{ 493 AllocatedStorage: aws.Int64(int64(d.Get("allocated_storage").(int))), 494 DBName: aws.String(d.Get("name").(string)), 495 DBInstanceClass: aws.String(d.Get("instance_class").(string)), 496 DBInstanceIdentifier: aws.String(d.Get("identifier").(string)), 497 MasterUsername: aws.String(d.Get("username").(string)), 498 MasterUserPassword: aws.String(d.Get("password").(string)), 499 Engine: aws.String(d.Get("engine").(string)), 500 EngineVersion: aws.String(d.Get("engine_version").(string)), 501 StorageEncrypted: aws.Bool(d.Get("storage_encrypted").(bool)), 502 AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)), 503 Tags: tags, 504 CopyTagsToSnapshot: aws.Bool(d.Get("copy_tags_to_snapshot").(bool)), 505 } 506 507 attr := d.Get("backup_retention_period") 508 opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int))) 509 if attr, ok := d.GetOk("multi_az"); ok { 510 opts.MultiAZ = aws.Bool(attr.(bool)) 511 512 } 513 514 if attr, ok := d.GetOk("character_set_name"); ok { 515 opts.CharacterSetName = aws.String(attr.(string)) 516 } 517 518 if attr, ok := d.GetOk("maintenance_window"); ok { 519 opts.PreferredMaintenanceWindow = aws.String(attr.(string)) 520 } 521 522 if attr, ok := d.GetOk("backup_window"); ok { 523 opts.PreferredBackupWindow = aws.String(attr.(string)) 524 } 525 526 if attr, ok := d.GetOk("license_model"); ok { 527 opts.LicenseModel = aws.String(attr.(string)) 528 } 529 if attr, ok := d.GetOk("parameter_group_name"); ok { 530 opts.DBParameterGroupName = aws.String(attr.(string)) 531 } 532 533 if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { 534 var s []*string 535 for _, v := range attr.List() { 536 s = append(s, aws.String(v.(string))) 537 } 538 opts.VpcSecurityGroupIds = s 539 } 540 541 if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { 542 var s []*string 543 for _, v := range attr.List() { 544 s = append(s, aws.String(v.(string))) 545 } 546 opts.DBSecurityGroups = s 547 } 548 if attr, ok := d.GetOk("storage_type"); ok { 549 opts.StorageType = aws.String(attr.(string)) 550 } 551 552 if attr, ok := d.GetOk("db_subnet_group_name"); ok { 553 opts.DBSubnetGroupName = aws.String(attr.(string)) 554 } 555 556 if attr, ok := d.GetOk("iops"); ok { 557 opts.Iops = aws.Int64(int64(attr.(int))) 558 } 559 560 if attr, ok := d.GetOk("port"); ok { 561 opts.Port = aws.Int64(int64(attr.(int))) 562 } 563 564 if attr, ok := d.GetOk("availability_zone"); ok { 565 opts.AvailabilityZone = aws.String(attr.(string)) 566 } 567 568 if attr, ok := d.GetOk("publicly_accessible"); ok { 569 opts.PubliclyAccessible = aws.Bool(attr.(bool)) 570 } 571 572 if attr, ok := d.GetOk("monitoring_role_arn"); ok { 573 opts.MonitoringRoleArn = aws.String(attr.(string)) 574 } 575 576 if attr, ok := d.GetOk("monitoring_interval"); ok { 577 opts.MonitoringInterval = aws.Int64(int64(attr.(int))) 578 } 579 580 if attr, ok := d.GetOk("option_group_name"); ok { 581 opts.OptionGroupName = aws.String(attr.(string)) 582 } 583 584 if attr, ok := d.GetOk("kms_key_id"); ok { 585 opts.KmsKeyId = aws.String(attr.(string)) 586 } 587 588 log.Printf("[DEBUG] DB Instance create configuration: %#v", opts) 589 var err error 590 err = resource.Retry(5*time.Minute, func() *resource.RetryError { 591 _, err = conn.CreateDBInstance(&opts) 592 if err != nil { 593 if awsErr, ok := err.(awserr.Error); ok { 594 if awsErr.Code() == "InvalidParameterValue" && strings.Contains(awsErr.Message(), "ENHANCED_MONITORING") { 595 return resource.RetryableError(awsErr) 596 } 597 } 598 return resource.NonRetryableError(err) 599 } 600 return nil 601 }) 602 if err != nil { 603 return fmt.Errorf("Error creating DB Instance: %s", err) 604 } 605 } 606 607 d.SetId(d.Get("identifier").(string)) 608 609 log.Printf("[INFO] DB Instance ID: %s", d.Id()) 610 611 log.Println( 612 "[INFO] Waiting for DB Instance to be available") 613 614 stateConf := &resource.StateChangeConf{ 615 Pending: []string{"creating", "backing-up", "modifying", "resetting-master-credentials", 616 "maintenance", "renaming", "rebooting", "upgrading"}, 617 Target: []string{"available"}, 618 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 619 Timeout: 40 * time.Minute, 620 MinTimeout: 10 * time.Second, 621 Delay: 30 * time.Second, // Wait 30 secs before starting 622 } 623 624 // Wait, catching any errors 625 _, err := stateConf.WaitForState() 626 if err != nil { 627 return err 628 } 629 630 return resourceAwsDbInstanceRead(d, meta) 631 } 632 633 func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { 634 v, err := resourceAwsDbInstanceRetrieve(d, meta) 635 636 if err != nil { 637 return err 638 } 639 if v == nil { 640 d.SetId("") 641 return nil 642 } 643 644 d.Set("name", v.DBName) 645 d.Set("username", v.MasterUsername) 646 d.Set("engine", v.Engine) 647 d.Set("engine_version", v.EngineVersion) 648 d.Set("allocated_storage", v.AllocatedStorage) 649 d.Set("copy_tags_to_snapshot", v.CopyTagsToSnapshot) 650 d.Set("auto_minor_version_upgrade", v.AutoMinorVersionUpgrade) 651 d.Set("storage_type", v.StorageType) 652 d.Set("instance_class", v.DBInstanceClass) 653 d.Set("availability_zone", v.AvailabilityZone) 654 d.Set("backup_retention_period", v.BackupRetentionPeriod) 655 d.Set("backup_window", v.PreferredBackupWindow) 656 d.Set("license_model", v.LicenseModel) 657 d.Set("maintenance_window", v.PreferredMaintenanceWindow) 658 d.Set("publicly_accessible", v.PubliclyAccessible) 659 d.Set("multi_az", v.MultiAZ) 660 d.Set("kms_key_id", v.KmsKeyId) 661 if v.DBSubnetGroup != nil { 662 d.Set("db_subnet_group_name", v.DBSubnetGroup.DBSubnetGroupName) 663 } 664 665 if v.CharacterSetName != nil { 666 d.Set("character_set_name", v.CharacterSetName) 667 } 668 669 if len(v.DBParameterGroups) > 0 { 670 d.Set("parameter_group_name", v.DBParameterGroups[0].DBParameterGroupName) 671 } 672 673 if v.Endpoint != nil { 674 d.Set("port", v.Endpoint.Port) 675 d.Set("address", v.Endpoint.Address) 676 677 if v.Endpoint.Address != nil && v.Endpoint.Port != nil { 678 d.Set("endpoint", 679 fmt.Sprintf("%s:%d", *v.Endpoint.Address, *v.Endpoint.Port)) 680 } 681 } 682 683 d.Set("status", v.DBInstanceStatus) 684 d.Set("storage_encrypted", v.StorageEncrypted) 685 if v.OptionGroupMemberships != nil { 686 d.Set("option_group_name", v.OptionGroupMemberships[0].OptionGroupName) 687 } 688 689 if v.MonitoringInterval != nil { 690 d.Set("monitoring_interval", v.MonitoringInterval) 691 } 692 693 if v.MonitoringRoleArn != nil { 694 d.Set("monitoring_role_arn", v.MonitoringRoleArn) 695 } 696 697 // list tags for resource 698 // set tags 699 conn := meta.(*AWSClient).rdsconn 700 arn, err := buildRDSARN(d.Id(), meta) 701 if err != nil { 702 name := "<empty>" 703 if v.DBName != nil && *v.DBName != "" { 704 name = *v.DBName 705 } 706 log.Printf("[DEBUG] Error building ARN for DB Instance, not setting Tags for DB %s", name) 707 } else { 708 d.Set("arn", arn) 709 resp, err := conn.ListTagsForResource(&rds.ListTagsForResourceInput{ 710 ResourceName: aws.String(arn), 711 }) 712 713 if err != nil { 714 log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn) 715 } 716 717 var dt []*rds.Tag 718 if len(resp.TagList) > 0 { 719 dt = resp.TagList 720 } 721 d.Set("tags", tagsToMapRDS(dt)) 722 } 723 724 // Create an empty schema.Set to hold all vpc security group ids 725 ids := &schema.Set{ 726 F: schema.HashString, 727 } 728 for _, v := range v.VpcSecurityGroups { 729 ids.Add(*v.VpcSecurityGroupId) 730 } 731 d.Set("vpc_security_group_ids", ids) 732 733 // Create an empty schema.Set to hold all security group names 734 sgn := &schema.Set{ 735 F: schema.HashString, 736 } 737 for _, v := range v.DBSecurityGroups { 738 sgn.Add(*v.DBSecurityGroupName) 739 } 740 d.Set("security_group_names", sgn) 741 742 // replica things 743 744 var replicas []string 745 for _, v := range v.ReadReplicaDBInstanceIdentifiers { 746 replicas = append(replicas, *v) 747 } 748 if err := d.Set("replicas", replicas); err != nil { 749 return fmt.Errorf("[DEBUG] Error setting replicas attribute: %#v, error: %#v", replicas, err) 750 } 751 752 d.Set("replicate_source_db", v.ReadReplicaSourceDBInstanceIdentifier) 753 754 return nil 755 } 756 757 func resourceAwsDbInstanceDelete(d *schema.ResourceData, meta interface{}) error { 758 conn := meta.(*AWSClient).rdsconn 759 760 log.Printf("[DEBUG] DB Instance destroy: %v", d.Id()) 761 762 opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())} 763 764 skipFinalSnapshot := d.Get("skip_final_snapshot").(bool) 765 opts.SkipFinalSnapshot = aws.Bool(skipFinalSnapshot) 766 767 if !skipFinalSnapshot { 768 if name, present := d.GetOk("final_snapshot_identifier"); present { 769 opts.FinalDBSnapshotIdentifier = aws.String(name.(string)) 770 } else { 771 return fmt.Errorf("DB Instance FinalSnapshotIdentifier is required when a final snapshot is required") 772 } 773 } 774 775 log.Printf("[DEBUG] DB Instance destroy configuration: %v", opts) 776 if _, err := conn.DeleteDBInstance(&opts); err != nil { 777 return err 778 } 779 780 log.Println( 781 "[INFO] Waiting for DB Instance to be destroyed") 782 stateConf := &resource.StateChangeConf{ 783 Pending: []string{"creating", "backing-up", 784 "modifying", "deleting", "available"}, 785 Target: []string{}, 786 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 787 Timeout: 40 * time.Minute, 788 MinTimeout: 10 * time.Second, 789 Delay: 30 * time.Second, // Wait 30 secs before starting 790 } 791 if _, err := stateConf.WaitForState(); err != nil { 792 return err 793 } 794 795 return nil 796 } 797 798 func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error { 799 conn := meta.(*AWSClient).rdsconn 800 801 d.Partial(true) 802 803 req := &rds.ModifyDBInstanceInput{ 804 ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), 805 DBInstanceIdentifier: aws.String(d.Id()), 806 } 807 d.SetPartial("apply_immediately") 808 809 requestUpdate := false 810 if d.HasChange("allocated_storage") { 811 d.SetPartial("allocated_storage") 812 req.AllocatedStorage = aws.Int64(int64(d.Get("allocated_storage").(int))) 813 requestUpdate = true 814 } 815 if d.HasChange("allow_major_version_upgrade") { 816 d.SetPartial("allow_major_version_upgrade") 817 req.AllowMajorVersionUpgrade = aws.Bool(d.Get("allow_major_version_upgrade").(bool)) 818 requestUpdate = true 819 } 820 if d.HasChange("backup_retention_period") { 821 d.SetPartial("backup_retention_period") 822 req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_period").(int))) 823 requestUpdate = true 824 } 825 if d.HasChange("copy_tags_to_snapshot") { 826 d.SetPartial("copy_tags_to_snapshot") 827 req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool)) 828 requestUpdate = true 829 } 830 if d.HasChange("instance_class") { 831 d.SetPartial("instance_class") 832 req.DBInstanceClass = aws.String(d.Get("instance_class").(string)) 833 requestUpdate = true 834 } 835 if d.HasChange("parameter_group_name") { 836 d.SetPartial("parameter_group_name") 837 req.DBParameterGroupName = aws.String(d.Get("parameter_group_name").(string)) 838 requestUpdate = true 839 } 840 if d.HasChange("engine_version") { 841 d.SetPartial("engine_version") 842 req.EngineVersion = aws.String(d.Get("engine_version").(string)) 843 requestUpdate = true 844 } 845 if d.HasChange("iops") { 846 d.SetPartial("iops") 847 req.Iops = aws.Int64(int64(d.Get("iops").(int))) 848 requestUpdate = true 849 } 850 if d.HasChange("backup_window") { 851 d.SetPartial("backup_window") 852 req.PreferredBackupWindow = aws.String(d.Get("backup_window").(string)) 853 requestUpdate = true 854 } 855 if d.HasChange("maintenance_window") { 856 d.SetPartial("maintenance_window") 857 req.PreferredMaintenanceWindow = aws.String(d.Get("maintenance_window").(string)) 858 requestUpdate = true 859 } 860 if d.HasChange("password") { 861 d.SetPartial("password") 862 req.MasterUserPassword = aws.String(d.Get("password").(string)) 863 requestUpdate = true 864 } 865 if d.HasChange("multi_az") { 866 d.SetPartial("multi_az") 867 req.MultiAZ = aws.Bool(d.Get("multi_az").(bool)) 868 requestUpdate = true 869 } 870 if d.HasChange("publicly_accessible") { 871 d.SetPartial("publicly_accessible") 872 req.PubliclyAccessible = aws.Bool(d.Get("publicly_accessible").(bool)) 873 requestUpdate = true 874 } 875 if d.HasChange("storage_type") { 876 d.SetPartial("storage_type") 877 req.StorageType = aws.String(d.Get("storage_type").(string)) 878 requestUpdate = true 879 880 if *req.StorageType == "io1" { 881 req.Iops = aws.Int64(int64(d.Get("iops").(int))) 882 } 883 } 884 if d.HasChange("auto_minor_version_upgrade") { 885 d.SetPartial("auto_minor_version_upgrade") 886 req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) 887 requestUpdate = true 888 } 889 890 if d.HasChange("monitoring_role_arn") { 891 d.SetPartial("monitoring_role_arn") 892 req.MonitoringRoleArn = aws.String(d.Get("monitoring_role_arn").(string)) 893 requestUpdate = true 894 } 895 896 if d.HasChange("monitoring_interval") { 897 d.SetPartial("monitoring_interval") 898 req.MonitoringInterval = aws.Int64(int64(d.Get("monitoring_interval").(int))) 899 requestUpdate = true 900 } 901 902 if d.HasChange("vpc_security_group_ids") { 903 if attr := d.Get("vpc_security_group_ids").(*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.VpcSecurityGroupIds = s 909 } 910 requestUpdate = true 911 } 912 913 if d.HasChange("security_group_names") { 914 if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { 915 var s []*string 916 for _, v := range attr.List() { 917 s = append(s, aws.String(v.(string))) 918 } 919 req.DBSecurityGroups = s 920 } 921 requestUpdate = true 922 } 923 924 if d.HasChange("option_group_name") { 925 d.SetPartial("option_group_name") 926 req.OptionGroupName = aws.String(d.Get("option_group_name").(string)) 927 requestUpdate = true 928 } 929 930 log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate) 931 if requestUpdate { 932 log.Printf("[DEBUG] DB Instance Modification request: %#v", 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 939 // separate request to promote a database 940 if d.HasChange("replicate_source_db") { 941 if d.Get("replicate_source_db").(string) == "" { 942 // promote 943 opts := rds.PromoteReadReplicaInput{ 944 DBInstanceIdentifier: aws.String(d.Id()), 945 } 946 attr := d.Get("backup_retention_period") 947 opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int))) 948 if attr, ok := d.GetOk("backup_window"); ok { 949 opts.PreferredBackupWindow = aws.String(attr.(string)) 950 } 951 _, err := conn.PromoteReadReplica(&opts) 952 if err != nil { 953 return fmt.Errorf("Error promoting database: %#v", err) 954 } 955 d.Set("replicate_source_db", "") 956 } else { 957 return fmt.Errorf("cannot elect new source database for replication") 958 } 959 } 960 961 if arn, err := buildRDSARN(d.Id(), meta); err == nil { 962 if err := setTagsRDS(conn, d, arn); err != nil { 963 return err 964 } else { 965 d.SetPartial("tags") 966 } 967 } 968 d.Partial(false) 969 970 return resourceAwsDbInstanceRead(d, meta) 971 } 972 973 // resourceAwsDbInstanceRetrieve fetches DBInstance information from the AWS 974 // API. It returns an error if there is a communication problem or unexpected 975 // error with AWS. When the DBInstance is not found, it returns no error and a 976 // nil pointer. 977 func resourceAwsDbInstanceRetrieve( 978 d *schema.ResourceData, meta interface{}) (*rds.DBInstance, error) { 979 conn := meta.(*AWSClient).rdsconn 980 981 opts := rds.DescribeDBInstancesInput{ 982 DBInstanceIdentifier: aws.String(d.Id()), 983 } 984 985 log.Printf("[DEBUG] DB Instance describe configuration: %#v", opts) 986 987 resp, err := conn.DescribeDBInstances(&opts) 988 if err != nil { 989 dbinstanceerr, ok := err.(awserr.Error) 990 if ok && dbinstanceerr.Code() == "DBInstanceNotFound" { 991 return nil, nil 992 } 993 return nil, fmt.Errorf("Error retrieving DB Instances: %s", err) 994 } 995 996 if len(resp.DBInstances) != 1 || 997 *resp.DBInstances[0].DBInstanceIdentifier != d.Id() { 998 if err != nil { 999 return nil, nil 1000 } 1001 } 1002 1003 return resp.DBInstances[0], nil 1004 } 1005 1006 func resourceAwsDbInstanceStateRefreshFunc( 1007 d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { 1008 return func() (interface{}, string, error) { 1009 v, err := resourceAwsDbInstanceRetrieve(d, meta) 1010 1011 if err != nil { 1012 log.Printf("Error on retrieving DB Instance when waiting: %s", err) 1013 return nil, "", err 1014 } 1015 1016 if v == nil { 1017 return nil, "", nil 1018 } 1019 1020 if v.DBInstanceStatus != nil { 1021 log.Printf("[DEBUG] DB Instance status for instance %s: %s", d.Id(), *v.DBInstanceStatus) 1022 } 1023 1024 return v, *v.DBInstanceStatus, nil 1025 } 1026 } 1027 1028 func buildRDSARN(identifier string, meta interface{}) (string, error) { 1029 iamconn := meta.(*AWSClient).iamconn 1030 region := meta.(*AWSClient).region 1031 // An zero value GetUserInput{} defers to the currently logged in user 1032 resp, err := iamconn.GetUser(&iam.GetUserInput{}) 1033 if err != nil { 1034 return "", err 1035 } 1036 userARN := *resp.User.Arn 1037 accountID := strings.Split(userARN, ":")[4] 1038 arn := fmt.Sprintf("arn:aws:rds:%s:%s:db:%s", region, accountID, identifier) 1039 return arn, nil 1040 }