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