diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 6e9505c2e..4448f6de7 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -147,6 +147,7 @@ func Provider() terraform.ResourceProvider { "aws_customer_gateway": resourceAwsCustomerGateway(), "aws_db_event_subscription": resourceAwsDbEventSubscription(), "aws_db_instance": resourceAwsDbInstance(), + "aws_db_option_group": resourceAwsDbOptionGroup(), "aws_db_parameter_group": resourceAwsDbParameterGroup(), "aws_db_security_group": resourceAwsDbSecurityGroup(), "aws_db_subnet_group": resourceAwsDbSubnetGroup(), @@ -255,7 +256,6 @@ func Provider() terraform.ResourceProvider { "aws_vpn_connection_route": resourceAwsVpnConnectionRoute(), "aws_vpn_gateway": resourceAwsVpnGateway(), }, - ConfigureFunc: providerConfigure, } } diff --git a/builtin/providers/aws/resource_aws_db_instance.go b/builtin/providers/aws/resource_aws_db_instance.go index f5d664c55..bc8cec612 100644 --- a/builtin/providers/aws/resource_aws_db_instance.go +++ b/builtin/providers/aws/resource_aws_db_instance.go @@ -283,6 +283,12 @@ func resourceAwsDbInstance() *schema.Resource { Default: 0, }, + "option_group_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "tags": tagsSchema(), }, } @@ -345,6 +351,10 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error opts.MonitoringInterval = aws.Int64(int64(attr.(int))) } + if attr, ok := d.GetOk("option_group_name"); ok { + opts.OptionGroupName = aws.String(attr.(string)) + } + log.Printf("[DEBUG] DB Instance Replica create configuration: %#v", opts) _, err := conn.CreateDBInstanceReadReplica(&opts) if err != nil { @@ -546,6 +556,10 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error opts.MonitoringInterval = aws.Int64(int64(attr.(int))) } + if attr, ok := d.GetOk("option_group_name"); ok { + opts.OptionGroupName = aws.String(attr.(string)) + } + log.Printf("[DEBUG] DB Instance create configuration: %#v", opts) var err error err = resource.Retry(5*time.Minute, func() *resource.RetryError { @@ -638,6 +652,9 @@ func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { d.Set("status", v.DBInstanceStatus) d.Set("storage_encrypted", v.StorageEncrypted) + if v.OptionGroupMemberships != nil { + d.Set("option_group_name", v.OptionGroupMemberships[0].OptionGroupName) + } if v.MonitoringInterval != nil { d.Set("monitoring_interval", v.MonitoringInterval) @@ -874,6 +891,12 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error requestUpdate = true } + if d.HasChange("option_group_name") { + d.SetPartial("option_group_name") + req.OptionGroupName = aws.String(d.Get("option_group_name").(string)) + requestUpdate = true + } + log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate) if requestUpdate { log.Printf("[DEBUG] DB Instance Modification request: %#v", req) diff --git a/builtin/providers/aws/resource_aws_db_instance_test.go b/builtin/providers/aws/resource_aws_db_instance_test.go index fcff06f65..7421c8701 100644 --- a/builtin/providers/aws/resource_aws_db_instance_test.go +++ b/builtin/providers/aws/resource_aws_db_instance_test.go @@ -51,6 +51,27 @@ func TestAccAWSDBInstance_basic(t *testing.T) { }) } +func TestAccAWSDBInstance_optionGroup(t *testing.T) { + var v rds.DBInstance + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBInstanceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSDBInstanceConfigWithOptionGroup, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists("aws_db_instance.bar", &v), + testAccCheckAWSDBInstanceAttributes(&v), + resource.TestCheckResourceAttr( + "aws_db_instance.bar", "option_group_name", "option-group-test-terraform"), + ), + }, + }, + }) +} + func TestAccAWSDBInstanceReplica(t *testing.T) { var s, r rds.DBInstance @@ -160,7 +181,7 @@ func testAccCheckAWSDBInstanceDestroy(s *terraform.State) error { if !ok { return err } - if newerr.Code() != "InvalidDBInstance.NotFound" { + if newerr.Code() != "DBInstanceNotFound" { return err } } @@ -383,6 +404,31 @@ resource "aws_db_instance" "bar" { parameter_group_name = "default.mysql5.6" }` +var testAccAWSDBInstanceConfigWithOptionGroup = fmt.Sprintf(` + +resource "aws_db_option_group" "bar" { + option_group_name = "option-group-test-terraform" + option_group_description = "Test option group for terraform" + engine_name = "mysql" + major_engine_version = "5.6" +} + +resource "aws_db_instance" "bar" { + identifier = "foobarbaz-test-terraform-%d" + + allocated_storage = 10 + engine = "MySQL" + instance_class = "db.m1.small" + name = "baz" + password = "barbarbarbar" + username = "foo" + + backup_retention_period = 0 + + parameter_group_name = "default.mysql5.6" + option_group_name = "${aws_db_option_group.bar.option_group_name}" +}`, acctest.RandInt()) + func testAccReplicaInstanceConfig(val int) string { return fmt.Sprintf(` resource "aws_db_instance" "bar" { diff --git a/builtin/providers/aws/resource_aws_db_option_group.go b/builtin/providers/aws/resource_aws_db_option_group.go new file mode 100644 index 000000000..202542f40 --- /dev/null +++ b/builtin/providers/aws/resource_aws_db_option_group.go @@ -0,0 +1,299 @@ +package aws + +import ( + "bytes" + "fmt" + "log" + "regexp" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/rds" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsDbOptionGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsDbOptionGroupCreate, + Read: resourceAwsDbOptionGroupRead, + Update: resourceAwsDbOptionGroupUpdate, + Delete: resourceAwsDbOptionGroupDelete, + + Schema: map[string]*schema.Schema{ + "arn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Required: true, + ValidateFunc: validateDbOptionGroupName, + }, + "engine_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "major_engine_version": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "option_group_description": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "option": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "option_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + "db_security_group_memberships": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "vpc_security_group_memberships": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + }, + }, + Set: resourceAwsDbOptionHash, + }, + + "tags": tagsSchema(), + }, + } +} + +func resourceAwsDbOptionGroupCreate(d *schema.ResourceData, meta interface{}) error { + rdsconn := meta.(*AWSClient).rdsconn + tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) + + createOpts := &rds.CreateOptionGroupInput{ + EngineName: aws.String(d.Get("engine_name").(string)), + MajorEngineVersion: aws.String(d.Get("major_engine_version").(string)), + OptionGroupDescription: aws.String(d.Get("option_group_description").(string)), + OptionGroupName: aws.String(d.Get("name").(string)), + Tags: tags, + } + + log.Printf("[DEBUG] Create DB Option Group: %#v", createOpts) + _, err := rdsconn.CreateOptionGroup(createOpts) + if err != nil { + return fmt.Errorf("Error creating DB Option Group: %s", err) + } + + d.SetId(d.Get("name").(string)) + log.Printf("[INFO] DB Option Group ID: %s", d.Id()) + + return resourceAwsDbOptionGroupUpdate(d, meta) +} + +func resourceAwsDbOptionGroupRead(d *schema.ResourceData, meta interface{}) error { + rdsconn := meta.(*AWSClient).rdsconn + params := &rds.DescribeOptionGroupsInput{ + OptionGroupName: aws.String(d.Get("name").(string)), + } + + log.Printf("[DEBUG] Describe DB Option Group: %#v", params) + options, err := rdsconn.DescribeOptionGroups(params) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok { + if "OptionGroupNotFoundFault" == awsErr.Code() { + d.SetId("") + log.Printf("[DEBUG] DB Option Group (%s) not found", d.Get("name").(string)) + return nil + } + } + return fmt.Errorf("Error Describing DB Option Group: %s", err) + } + + var option *rds.OptionGroup + for _, ogl := range options.OptionGroupsList { + if *ogl.OptionGroupName == d.Get("name").(string) { + option = ogl + break + } + } + + if option == nil { + return fmt.Errorf("Unable to find Option Group: %#v", options.OptionGroupsList) + } + + d.Set("major_engine_version", option.MajorEngineVersion) + d.Set("engine_name", option.EngineName) + d.Set("option_group_description", option.OptionGroupDescription) + if len(option.Options) != 0 { + d.Set("option", flattenOptions(option.Options)) + } + + optionGroup := options.OptionGroupsList[0] + arn, err := buildRDSOptionGroupARN(d.Id(), meta.(*AWSClient).accountid, meta.(*AWSClient).region) + if err != nil { + name := "" + if optionGroup.OptionGroupName != nil && *optionGroup.OptionGroupName != "" { + name = *optionGroup.OptionGroupName + } + log.Printf("[DEBUG] Error building ARN for DB Option Group, not setting Tags for Option Group %s", name) + } else { + d.Set("arn", arn) + resp, err := rdsconn.ListTagsForResource(&rds.ListTagsForResourceInput{ + ResourceName: aws.String(arn), + }) + + if err != nil { + log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn) + } + + var dt []*rds.Tag + if len(resp.TagList) > 0 { + dt = resp.TagList + } + d.Set("tags", tagsToMapRDS(dt)) + } + + return nil +} + +func resourceAwsDbOptionGroupUpdate(d *schema.ResourceData, meta interface{}) error { + rdsconn := meta.(*AWSClient).rdsconn + if d.HasChange("option") { + o, n := d.GetChange("option") + if o == nil { + o = new(schema.Set) + } + if n == nil { + n = new(schema.Set) + } + + os := o.(*schema.Set) + ns := n.(*schema.Set) + addOptions, addErr := expandOptionConfiguration(ns.Difference(os).List()) + if addErr != nil { + return addErr + } + + removeOptions, removeErr := flattenOptionConfigurationNames(os.Difference(ns).List()) + if removeErr != nil { + return removeErr + } + + modifyOpts := &rds.ModifyOptionGroupInput{ + OptionGroupName: aws.String(d.Id()), + ApplyImmediately: aws.Bool(true), + } + + if len(addOptions) > 0 { + modifyOpts.OptionsToInclude = addOptions + } + + if len(removeOptions) > 0 { + modifyOpts.OptionsToRemove = removeOptions + } + + log.Printf("[DEBUG] Modify DB Option Group: %s", modifyOpts) + _, err := rdsconn.ModifyOptionGroup(modifyOpts) + if err != nil { + return fmt.Errorf("Error modifying DB Option Group: %s", err) + } + d.SetPartial("option") + + } + + if arn, err := buildRDSOptionGroupARN(d.Id(), meta.(*AWSClient).accountid, meta.(*AWSClient).region); err == nil { + if err := setTagsRDS(rdsconn, d, arn); err != nil { + return err + } else { + d.SetPartial("tags") + } + } + + return resourceAwsDbOptionGroupRead(d, meta) +} + +func resourceAwsDbOptionGroupDelete(d *schema.ResourceData, meta interface{}) error { + rdsconn := meta.(*AWSClient).rdsconn + + deleteOpts := &rds.DeleteOptionGroupInput{ + OptionGroupName: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Delete DB Option Group: %#v", deleteOpts) + _, err := rdsconn.DeleteOptionGroup(deleteOpts) + if err != nil { + return fmt.Errorf("Error Deleting DB Option Group: %s", err) + } + + return nil +} + +func flattenOptionConfigurationNames(configured []interface{}) ([]*string, error) { + var optionNames []*string + for _, pRaw := range configured { + data := pRaw.(map[string]interface{}) + optionNames = append(optionNames, aws.String(data["option_name"].(string))) + } + + return optionNames, nil +} + +func resourceAwsDbOptionHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["option_name"].(string))) + if _, ok := m["port"]; ok { + buf.WriteString(fmt.Sprintf("%d-", m["port"].(int))) + } + + return hashcode.String(buf.String()) +} + +func buildRDSOptionGroupARN(identifier, accountid, region string) (string, error) { + if accountid == "" { + return "", fmt.Errorf("Unable to construct RDS Option Group ARN because of missing AWS Account ID") + } + arn := fmt.Sprintf("arn:aws:rds:%s:%s:og:%s", region, accountid, identifier) + return arn, nil +} + +func validateDbOptionGroupName(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + if !regexp.MustCompile(`^[a-z]`).MatchString(value) { + errors = append(errors, fmt.Errorf( + "first character of %q must be a letter", k)) + } + if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) { + errors = append(errors, fmt.Errorf( + "only alphanumeric characters and hyphens allowed in %q", k)) + } + if regexp.MustCompile(`--`).MatchString(value) { + errors = append(errors, fmt.Errorf( + "%q cannot contain two consecutive hyphens", k)) + } + if regexp.MustCompile(`-$`).MatchString(value) { + errors = append(errors, fmt.Errorf( + "%q cannot end with a hyphen", k)) + } + if len(value) > 255 { + errors = append(errors, fmt.Errorf( + "%q cannot be greater than 255 characters", k)) + } + return +} diff --git a/builtin/providers/aws/resource_aws_db_option_group_test.go b/builtin/providers/aws/resource_aws_db_option_group_test.go new file mode 100644 index 000000000..e9611f90b --- /dev/null +++ b/builtin/providers/aws/resource_aws_db_option_group_test.go @@ -0,0 +1,256 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/rds" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSDBOptionGroup_basic(t *testing.T) { + var v rds.OptionGroup + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBOptionGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSDBOptionGroupBasicConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBOptionGroupExists("aws_db_option_group.bar", &v), + testAccCheckAWSDBOptionGroupAttributes(&v), + resource.TestCheckResourceAttr( + "aws_db_option_group.bar", "name", "option-group-test-terraform"), + ), + }, + }, + }) +} + +func TestAccAWSDBOptionGroup_sqlServerOptionsUpdate(t *testing.T) { + var v rds.OptionGroup + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBOptionGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSDBOptionGroupSqlServerEEOptions, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBOptionGroupExists("aws_db_option_group.bar", &v), + resource.TestCheckResourceAttr( + "aws_db_option_group.bar", "name", "option-group-test-terraform"), + ), + }, + + resource.TestStep{ + Config: testAccAWSDBOptionGroupSqlServerEEOptions_update, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBOptionGroupExists("aws_db_option_group.bar", &v), + resource.TestCheckResourceAttr( + "aws_db_option_group.bar", "name", "option-group-test-terraform"), + resource.TestCheckResourceAttr( + "aws_db_option_group.bar", "option.#", "1"), + ), + }, + }, + }) +} + +func TestAccAWSDBOptionGroup_multipleOptions(t *testing.T) { + var v rds.OptionGroup + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBOptionGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSDBOptionGroupMultipleOptions, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBOptionGroupExists("aws_db_option_group.bar", &v), + resource.TestCheckResourceAttr( + "aws_db_option_group.bar", "name", "option-group-test-terraform"), + resource.TestCheckResourceAttr( + "aws_db_option_group.bar", "option.#", "2"), + ), + }, + }, + }) +} + +func testAccCheckAWSDBOptionGroupAttributes(v *rds.OptionGroup) resource.TestCheckFunc { + return func(s *terraform.State) error { + + if *v.EngineName != "mysql" { + return fmt.Errorf("bad engine_name: %#v", *v.EngineName) + } + + if *v.MajorEngineVersion != "5.6" { + return fmt.Errorf("bad major_engine_version: %#v", *v.MajorEngineVersion) + } + + if *v.OptionGroupDescription != "Test option group for terraform" { + return fmt.Errorf("bad option_group_description: %#v", *v.OptionGroupDescription) + } + + return nil + } +} + +func TestResourceAWSDBOptionGroupName_validation(t *testing.T) { + cases := []struct { + Value string + ErrCount int + }{ + { + Value: "testing123!", + ErrCount: 1, + }, + { + Value: "1testing123", + ErrCount: 1, + }, + { + Value: "testing--123", + ErrCount: 1, + }, + { + Value: "testing123-", + ErrCount: 1, + }, + { + Value: randomString(256), + ErrCount: 1, + }, + } + + for _, tc := range cases { + _, errors := validateDbOptionGroupName(tc.Value, "aws_db_option_group_name") + + if len(errors) != tc.ErrCount { + t.Fatalf("Expected the DB Option Group Name to trigger a validation error") + } + } +} + +func testAccCheckAWSDBOptionGroupExists(n string, v *rds.OptionGroup) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No DB Option Group Name is set") + } + + conn := testAccProvider.Meta().(*AWSClient).rdsconn + + opts := rds.DescribeOptionGroupsInput{ + OptionGroupName: aws.String(rs.Primary.ID), + } + + resp, err := conn.DescribeOptionGroups(&opts) + + if err != nil { + return err + } + + if len(resp.OptionGroupsList) != 1 || + *resp.OptionGroupsList[0].OptionGroupName != rs.Primary.ID { + return fmt.Errorf("DB Option Group not found") + } + + *v = *resp.OptionGroupsList[0] + + return nil + } +} + +func testAccCheckAWSDBOptionGroupDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).rdsconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_db_option_group" { + continue + } + + resp, err := conn.DescribeOptionGroups( + &rds.DescribeOptionGroupsInput{ + OptionGroupName: aws.String(rs.Primary.ID), + }) + + if err == nil { + if len(resp.OptionGroupsList) != 0 && + *resp.OptionGroupsList[0].OptionGroupName == rs.Primary.ID { + return fmt.Errorf("DB Option Group still exists") + } + } + + // Verify the error + newerr, ok := err.(awserr.Error) + if !ok { + return err + } + if newerr.Code() != "OptionGroupNotFoundFault" { + return err + } + } + + return nil +} + +const testAccAWSDBOptionGroupBasicConfig = ` +resource "aws_db_option_group" "bar" { + name = "option-group-test-terraform" + option_group_description = "Test option group for terraform" + engine_name = "mysql" + major_engine_version = "5.6" +} +` + +const testAccAWSDBOptionGroupSqlServerEEOptions = ` +resource "aws_db_option_group" "bar" { + name = "option-group-test-terraform" + option_group_description = "Test option group for terraform" + engine_name = "sqlserver-ee" + major_engine_version = "11.00" +} +` + +const testAccAWSDBOptionGroupSqlServerEEOptions_update = ` +resource "aws_db_option_group" "bar" { + name = "option-group-test-terraform" + option_group_description = "Test option group for terraform" + engine_name = "sqlserver-ee" + major_engine_version = "11.00" + + option { + option_name = "Mirroring" + } +} +` + +const testAccAWSDBOptionGroupMultipleOptions = ` +resource "aws_db_option_group" "bar" { + name = "option-group-test-terraform" + option_group_description = "Test option group for terraform" + engine_name = "oracle-se" + major_engine_version = "11.2" + + option { + option_name = "STATSPACK" + } + + option { + option_name = "XMLDB" + } +} +` diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index 9074c6b0b..abff5a7a3 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -262,6 +262,43 @@ func expandRedshiftParameters(configured []interface{}) ([]*redshift.Parameter, return parameters, nil } +func expandOptionConfiguration(configured []interface{}) ([]*rds.OptionConfiguration, error) { + var option []*rds.OptionConfiguration + + for _, pRaw := range configured { + data := pRaw.(map[string]interface{}) + + o := &rds.OptionConfiguration{ + OptionName: aws.String(data["option_name"].(string)), + } + + if raw, ok := data["port"]; ok { + port := raw.(int) + if port != 0 { + o.Port = aws.Int64(int64(port)) + } + } + + if raw, ok := data["db_security_group_memberships"]; ok { + memberships := expandStringList(raw.(*schema.Set).List()) + if len(memberships) > 0 { + o.DBSecurityGroupMemberships = memberships + } + } + + if raw, ok := data["vpc_security_group_memberships"]; ok { + memberships := expandStringList(raw.(*schema.Set).List()) + if len(memberships) > 0 { + o.VpcSecurityGroupMemberships = memberships + } + } + + option = append(option, o) + } + + return option, nil +} + // Takes the result of flatmap.Expand for an array of parameters and // returns Parameter API compatible objects func expandElastiCacheParameters(configured []interface{}) ([]*elasticache.ParameterNameValue, error) { @@ -506,6 +543,41 @@ func flattenEcsContainerDefinitions(definitions []*ecs.ContainerDefinition) (str return string(byteArray[:n]), nil } +func flattenOptions(list []*rds.Option) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(list)) + for _, i := range list { + if i.OptionName != nil { + r := make(map[string]interface{}) + r["option_name"] = strings.ToLower(*i.OptionName) + // Default empty string, guard against nil parameter values + r["port"] = "" + if i.Port != nil { + r["port"] = int(*i.Port) + } + if i.VpcSecurityGroupMemberships != nil { + vpcs := make([]string, 0, len(i.VpcSecurityGroupMemberships)) + for _, vpc := range i.VpcSecurityGroupMemberships { + id := vpc.VpcSecurityGroupId + vpcs = append(vpcs, *id) + } + + r["vpc_security_group_memberships"] = vpcs + } + if i.DBSecurityGroupMemberships != nil { + dbs := make([]string, 0, len(i.DBSecurityGroupMemberships)) + for _, db := range i.DBSecurityGroupMemberships { + id := db.DBSecurityGroupName + dbs = append(dbs, *id) + } + + r["db_security_group_memberships"] = dbs + } + result = append(result, r) + } + } + return result +} + // Flattens an array of Parameters into a []map[string]interface{} func flattenParameters(list []*rds.Parameter) []map[string]interface{} { result := make([]map[string]interface{}, 0, len(list)) diff --git a/website/source/docs/providers/aws/r/db_option_group.html.markdown b/website/source/docs/providers/aws/r/db_option_group.html.markdown new file mode 100644 index 000000000..1d78f2fbd --- /dev/null +++ b/website/source/docs/providers/aws/r/db_option_group.html.markdown @@ -0,0 +1,54 @@ +--- +layout: "aws" +page_title: "AWS: aws_db_option_group" +sidebar_current: "docs-aws-resource-db-option-group" +--- + +# aws\_db\_option\_group + +Provides an RDS DB option group resource. + +## Example Usage + +``` +resource "aws_db_option_group" "bar" { + option_group_name = "option-group-test-terraform" + option_group_description = "Terraform Option Group" + engine_name = "sqlserver-ee" + major_engine_version = "11.00" + + option { + option_name = "mirroring" + } + + option { + option_name = "TDE" + } + + apply_immediately = true +} +``` + +## Argument Reference + +The following arguments are supported: + +* `option_group_name` - (Required) The name of the Option group to be created. +* `option_group_description` - (Required) The description of the option group. +* `engine_name` - (Required) Specifies the name of the engine that this option group should be associated with.. +* `major_engine_version` - (Required) Specifies the major version of the engine that this option group should be associated with. +* `option` - (Optional) A list of Options to apply. +* `tags` - (Optional) A mapping of tags to assign to the resource. + +Option blocks support the following: + +* `option_name` - (Required) The Name of the Option (e.g. MEMCACHED). +* `port` - (Optional) The Port number when connecting to the Option (e.g. 11211). +* `db_security_group_memberships` - (Optional) A list of DB Security Groups for which the option is enabled. +* `vpc_security_group_memberships` - (Optional) A list of VPC Security Groups for which the option is enabled. + +## Attributes Reference + +The following attributes are exported: + +* `arn` - The ARN of the db option group. diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index 7aa965519..49b4f638f 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -543,6 +543,10 @@ aws_db_event_subscription + > + aws_db_option_group + + > aws_db_parameter_group