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