Add `name_prefix` to RDS resources (#13232)

Adds `name_prefix` (or, in some cases, `identifier_prefix`) support to all AWS RDS resources.
This commit is contained in:
Joshua Spence 2017-04-01 04:22:57 +11:00 committed by Paul Stack
parent e7c3e8df68
commit d25c310468
23 changed files with 985 additions and 157 deletions

View File

@ -101,11 +101,19 @@ func resourceAwsDbInstance() *schema.Resource {
}, },
"identifier": { "identifier": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"identifier_prefix"},
ValidateFunc: validateRdsIdentifier,
},
"identifier_prefix": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true, Computed: true,
ForceNew: true, ForceNew: true,
ValidateFunc: validateRdsId, ValidateFunc: validateRdsIdentifierPrefix,
}, },
"instance_class": { "instance_class": {
@ -336,10 +344,16 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error
conn := meta.(*AWSClient).rdsconn conn := meta.(*AWSClient).rdsconn
tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
identifier := d.Get("identifier").(string) var identifier string
// Generate a unique ID for the user if v, ok := d.GetOk("identifier"); ok {
if identifier == "" { identifier = v.(string)
identifier = resource.PrefixedUniqueId("tf-") } else {
if v, ok := d.GetOk("identifier_prefix"); ok {
identifier = resource.PrefixedUniqueId(v.(string))
} else {
identifier = resource.UniqueId()
}
// SQL Server identifier size is max 15 chars, so truncate // SQL Server identifier size is max 15 chars, so truncate
if engine := d.Get("engine").(string); engine != "" { if engine := d.Get("engine").(string); engine != "" {
if strings.Contains(strings.ToLower(engine), "sqlserver") { if strings.Contains(strings.ToLower(engine), "sqlserver") {

View File

@ -53,6 +53,46 @@ func TestAccAWSDBInstance_basic(t *testing.T) {
}) })
} }
func TestAccAWSDBInstance_namePrefix(t *testing.T) {
var v rds.DBInstance
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSDBInstanceConfig_namePrefix,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBInstanceExists("aws_db_instance.test", &v),
testAccCheckAWSDBInstanceAttributes(&v),
resource.TestMatchResourceAttr(
"aws_db_instance.test", "identifier", regexp.MustCompile("^tf-test-")),
),
},
},
})
}
func TestAccAWSDBInstance_generatedName(t *testing.T) {
var v rds.DBInstance
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSDBInstanceConfig_generatedName,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBInstanceExists("aws_db_instance.test", &v),
testAccCheckAWSDBInstanceAttributes(&v),
),
},
},
})
}
func TestAccAWSDBInstance_kmsKey(t *testing.T) { func TestAccAWSDBInstance_kmsKey(t *testing.T) {
var v rds.DBInstance var v rds.DBInstance
keyRegex := regexp.MustCompile("^arn:aws:kms:") keyRegex := regexp.MustCompile("^arn:aws:kms:")
@ -628,6 +668,39 @@ resource "aws_db_instance" "bar" {
} }
}` }`
const testAccAWSDBInstanceConfig_namePrefix = `
resource "aws_db_instance" "test" {
allocated_storage = 10
engine = "MySQL"
identifier_prefix = "tf-test-"
instance_class = "db.t1.micro"
password = "password"
username = "root"
security_group_names = ["default"]
publicly_accessible = true
skip_final_snapshot = true
timeouts {
create = "30m"
}
}`
const testAccAWSDBInstanceConfig_generatedName = `
resource "aws_db_instance" "test" {
allocated_storage = 10
engine = "MySQL"
instance_class = "db.t1.micro"
password = "password"
username = "root"
security_group_names = ["default"]
publicly_accessible = true
skip_final_snapshot = true
timeouts {
create = "30m"
}
}`
var testAccAWSDBInstanceConfigKmsKeyId = ` var testAccAWSDBInstanceConfigKmsKeyId = `
resource "aws_kms_key" "foo" { resource "aws_kms_key" "foo" {
description = "Terraform acc test %s" description = "Terraform acc test %s"

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"log" "log"
"regexp"
"time" "time"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
@ -31,10 +30,19 @@ func resourceAwsDbOptionGroup() *schema.Resource {
Computed: true, Computed: true,
}, },
"name": &schema.Schema{ "name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"name_prefix"},
ValidateFunc: validateDbOptionGroupName,
},
"name_prefix": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true, ForceNew: true,
Required: true, ValidateFunc: validateDbOptionGroupNamePrefix,
ValidateFunc: validateDbOptionGroupName,
}, },
"engine_name": &schema.Schema{ "engine_name": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
@ -48,8 +56,9 @@ func resourceAwsDbOptionGroup() *schema.Resource {
}, },
"option_group_description": &schema.Schema{ "option_group_description": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Optional: true,
ForceNew: true, ForceNew: true,
Default: "Managed by Terraform",
}, },
"option": &schema.Schema{ "option": &schema.Schema{
@ -107,11 +116,20 @@ func resourceAwsDbOptionGroupCreate(d *schema.ResourceData, meta interface{}) er
rdsconn := meta.(*AWSClient).rdsconn rdsconn := meta.(*AWSClient).rdsconn
tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
var groupName string
if v, ok := d.GetOk("name"); ok {
groupName = v.(string)
} else if v, ok := d.GetOk("name_prefix"); ok {
groupName = resource.PrefixedUniqueId(v.(string))
} else {
groupName = resource.UniqueId()
}
createOpts := &rds.CreateOptionGroupInput{ createOpts := &rds.CreateOptionGroupInput{
EngineName: aws.String(d.Get("engine_name").(string)), EngineName: aws.String(d.Get("engine_name").(string)),
MajorEngineVersion: aws.String(d.Get("major_engine_version").(string)), MajorEngineVersion: aws.String(d.Get("major_engine_version").(string)),
OptionGroupDescription: aws.String(d.Get("option_group_description").(string)), OptionGroupDescription: aws.String(d.Get("option_group_description").(string)),
OptionGroupName: aws.String(d.Get("name").(string)), OptionGroupName: aws.String(groupName),
Tags: tags, Tags: tags,
} }
@ -121,7 +139,7 @@ func resourceAwsDbOptionGroupCreate(d *schema.ResourceData, meta interface{}) er
return fmt.Errorf("Error creating DB Option Group: %s", err) return fmt.Errorf("Error creating DB Option Group: %s", err)
} }
d.SetId(d.Get("name").(string)) d.SetId(groupName)
log.Printf("[INFO] DB Option Group ID: %s", d.Id()) log.Printf("[INFO] DB Option Group ID: %s", d.Id())
return resourceAwsDbOptionGroupUpdate(d, meta) return resourceAwsDbOptionGroupUpdate(d, meta)
@ -343,28 +361,3 @@ func buildRDSOptionGroupARN(identifier, partition, accountid, region string) (st
arn := fmt.Sprintf("arn:%s:rds:%s:%s:og:%s", partition, region, accountid, identifier) arn := fmt.Sprintf("arn:%s:rds:%s:%s:og:%s", partition, region, accountid, identifier)
return arn, nil 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
}

View File

@ -2,6 +2,7 @@ package aws
import ( import (
"fmt" "fmt"
"regexp"
"testing" "testing"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
@ -34,6 +35,66 @@ func TestAccAWSDBOptionGroup_basic(t *testing.T) {
}) })
} }
func TestAccAWSDBOptionGroup_namePrefix(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: testAccAWSDBOptionGroup_namePrefix,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBOptionGroupExists("aws_db_option_group.test", &v),
testAccCheckAWSDBOptionGroupAttributes(&v),
resource.TestMatchResourceAttr(
"aws_db_option_group.test", "name", regexp.MustCompile("^tf-test-")),
),
},
},
})
}
func TestAccAWSDBOptionGroup_generatedName(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: testAccAWSDBOptionGroup_generatedName,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBOptionGroupExists("aws_db_option_group.test", &v),
testAccCheckAWSDBOptionGroupAttributes(&v),
),
},
},
})
}
func TestAccAWSDBOptionGroup_defaultDescription(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: testAccAWSDBOptionGroup_defaultDescription(acctest.RandInt()),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBOptionGroupExists("aws_db_option_group.test", &v),
resource.TestCheckResourceAttr(
"aws_db_option_group.test", "option_group_description", "Managed by Terraform"),
),
},
},
})
}
func TestAccAWSDBOptionGroup_basicDestroyWithInstance(t *testing.T) { func TestAccAWSDBOptionGroup_basicDestroyWithInstance(t *testing.T) {
rName := fmt.Sprintf("option-group-test-terraform-%s", acctest.RandString(5)) rName := fmt.Sprintf("option-group-test-terraform-%s", acctest.RandString(5))
@ -160,42 +221,6 @@ func testAccCheckAWSDBOptionGroupAttributes(v *rds.OptionGroup) resource.TestChe
} }
} }
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 { func testAccCheckAWSDBOptionGroupExists(n string, v *rds.OptionGroup) resource.TestCheckFunc {
return func(s *terraform.State) error { return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n] rs, ok := s.RootModule().Resources[n]
@ -387,3 +412,30 @@ resource "aws_db_option_group" "bar" {
} }
`, r) `, r)
} }
const testAccAWSDBOptionGroup_namePrefix = `
resource "aws_db_option_group" "test" {
name_prefix = "tf-test-"
option_group_description = "Test option group for terraform"
engine_name = "mysql"
major_engine_version = "5.6"
}
`
const testAccAWSDBOptionGroup_generatedName = `
resource "aws_db_option_group" "test" {
option_group_description = "Test option group for terraform"
engine_name = "mysql"
major_engine_version = "5.6"
}
`
func testAccAWSDBOptionGroup_defaultDescription(n int) string {
return fmt.Sprintf(`
resource "aws_db_option_group" "test" {
name = "tf-test-%d"
engine_name = "mysql"
major_engine_version = "5.6"
}
`, n)
}

View File

@ -32,10 +32,19 @@ func resourceAwsDbParameterGroup() *schema.Resource {
Computed: true, Computed: true,
}, },
"name": &schema.Schema{ "name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"name_prefix"},
ValidateFunc: validateDbParamGroupName,
},
"name_prefix": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true, ForceNew: true,
Required: true, ValidateFunc: validateDbParamGroupNamePrefix,
ValidateFunc: validateDbParamGroupName,
}, },
"family": &schema.Schema{ "family": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
@ -81,8 +90,17 @@ func resourceAwsDbParameterGroupCreate(d *schema.ResourceData, meta interface{})
rdsconn := meta.(*AWSClient).rdsconn rdsconn := meta.(*AWSClient).rdsconn
tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
var groupName string
if v, ok := d.GetOk("name"); ok {
groupName = v.(string)
} else if v, ok := d.GetOk("name_prefix"); ok {
groupName = resource.PrefixedUniqueId(v.(string))
} else {
groupName = resource.UniqueId()
}
createOpts := rds.CreateDBParameterGroupInput{ createOpts := rds.CreateDBParameterGroupInput{
DBParameterGroupName: aws.String(d.Get("name").(string)), DBParameterGroupName: aws.String(groupName),
DBParameterGroupFamily: aws.String(d.Get("family").(string)), DBParameterGroupFamily: aws.String(d.Get("family").(string)),
Description: aws.String(d.Get("description").(string)), Description: aws.String(d.Get("description").(string)),
Tags: tags, Tags: tags,

View File

@ -3,6 +3,7 @@ package aws
import ( import (
"fmt" "fmt"
"math/rand" "math/rand"
"regexp"
"testing" "testing"
"time" "time"
@ -290,6 +291,44 @@ func TestAccAWSDBParameterGroup_basic(t *testing.T) {
}) })
} }
func TestAccAWSDBParameterGroup_namePrefix(t *testing.T) {
var v rds.DBParameterGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBParameterGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBParameterGroupConfig_namePrefix,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBParameterGroupExists("aws_db_parameter_group.test", &v),
resource.TestMatchResourceAttr(
"aws_db_parameter_group.test", "name", regexp.MustCompile("^tf-test-")),
),
},
},
})
}
func TestAccAWSDBParameterGroup_generatedName(t *testing.T) {
var v rds.DBParameterGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBParameterGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBParameterGroupConfig_generatedName,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBParameterGroupExists("aws_db_parameter_group.test", &v),
),
},
},
})
}
func TestAccAWSDBParameterGroup_withApplyMethod(t *testing.T) { func TestAccAWSDBParameterGroup_withApplyMethod(t *testing.T) {
var v rds.DBParameterGroup var v rds.DBParameterGroup
@ -671,3 +710,16 @@ resource "aws_db_parameter_group" "large" {
parameter { name = "tx_isolation" value = "REPEATABLE-READ" } parameter { name = "tx_isolation" value = "REPEATABLE-READ" }
}`, n) }`, n)
} }
const testAccDBParameterGroupConfig_namePrefix = `
resource "aws_db_parameter_group" "test" {
name_prefix = "tf-test-"
family = "mysql5.6"
}
`
const testAccDBParameterGroupConfig_generatedName = `
resource "aws_db_parameter_group" "test" {
family = "mysql5.6"
}
`

View File

@ -3,7 +3,6 @@ package aws
import ( import (
"fmt" "fmt"
"log" "log"
"regexp"
"strings" "strings"
"time" "time"
@ -31,10 +30,19 @@ func resourceAwsDbSubnetGroup() *schema.Resource {
}, },
"name": &schema.Schema{ "name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"name_prefix"},
ValidateFunc: validateDbSubnetGroupName,
},
"name_prefix": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true, ForceNew: true,
Required: true, ValidateFunc: validateDbSubnetGroupNamePrefix,
ValidateFunc: validateSubnetGroupName,
}, },
"description": &schema.Schema{ "description": &schema.Schema{
@ -65,8 +73,17 @@ func resourceAwsDbSubnetGroupCreate(d *schema.ResourceData, meta interface{}) er
subnetIds[i] = aws.String(subnetId.(string)) subnetIds[i] = aws.String(subnetId.(string))
} }
var groupName string
if v, ok := d.GetOk("name"); ok {
groupName = v.(string)
} else if v, ok := d.GetOk("name_prefix"); ok {
groupName = resource.PrefixedUniqueId(v.(string))
} else {
groupName = resource.UniqueId()
}
createOpts := rds.CreateDBSubnetGroupInput{ createOpts := rds.CreateDBSubnetGroupInput{
DBSubnetGroupName: aws.String(d.Get("name").(string)), DBSubnetGroupName: aws.String(groupName),
DBSubnetGroupDescription: aws.String(d.Get("description").(string)), DBSubnetGroupDescription: aws.String(d.Get("description").(string)),
SubnetIds: subnetIds, SubnetIds: subnetIds,
Tags: tags, Tags: tags,
@ -238,20 +255,3 @@ func buildRDSsubgrpARN(identifier, partition, accountid, region string) (string,
return arn, nil return arn, nil
} }
func validateSubnetGroupName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
}
if len(value) > 255 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 255 characters", k))
}
if regexp.MustCompile(`(?i)^default$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q is not allowed as %q", "Default", k))
}
return
}

View File

@ -2,6 +2,7 @@ package aws
import ( import (
"fmt" "fmt"
"regexp"
"testing" "testing"
"github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/acctest"
@ -43,6 +44,46 @@ func TestAccAWSDBSubnetGroup_basic(t *testing.T) {
}) })
} }
func TestAccAWSDBSubnetGroup_namePrefix(t *testing.T) {
var v rds.DBSubnetGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDBSubnetGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBSubnetGroupConfig_namePrefix,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBSubnetGroupExists(
"aws_db_subnet_group.test", &v),
resource.TestMatchResourceAttr(
"aws_db_subnet_group.test", "name", regexp.MustCompile("^tf_test-")),
),
},
},
})
}
func TestAccAWSDBSubnetGroup_generatedName(t *testing.T) {
var v rds.DBSubnetGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDBSubnetGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBSubnetGroupConfig_generatedName,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBSubnetGroupExists(
"aws_db_subnet_group.test", &v),
),
},
},
})
}
// Regression test for https://github.com/hashicorp/terraform/issues/2603 and // Regression test for https://github.com/hashicorp/terraform/issues/2603 and
// https://github.com/hashicorp/terraform/issues/2664 // https://github.com/hashicorp/terraform/issues/2664
func TestAccAWSDBSubnetGroup_withUndocumentedCharacters(t *testing.T) { func TestAccAWSDBSubnetGroup_withUndocumentedCharacters(t *testing.T) {
@ -105,38 +146,6 @@ func TestAccAWSDBSubnetGroup_updateDescription(t *testing.T) {
}) })
} }
func TestResourceAWSDBSubnetGroupNameValidation(t *testing.T) {
cases := []struct {
Value string
ErrCount int
}{
{
Value: "tEsting",
ErrCount: 1,
},
{
Value: "testing?",
ErrCount: 1,
},
{
Value: "default",
ErrCount: 1,
},
{
Value: randomString(300),
ErrCount: 1,
},
}
for _, tc := range cases {
_, errors := validateSubnetGroupName(tc.Value, "aws_db_subnet_group")
if len(errors) != tc.ErrCount {
t.Fatalf("Expected the DB Subnet Group name to trigger a validation error")
}
}
}
func testAccCheckDBSubnetGroupDestroy(s *terraform.State) error { func testAccCheckDBSubnetGroupDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).rdsconn conn := testAccProvider.Meta().(*AWSClient).rdsconn
@ -263,6 +272,49 @@ resource "aws_db_subnet_group" "foo" {
}`, rName) }`, rName)
} }
const testAccDBSubnetGroupConfig_namePrefix = `
resource "aws_vpc" "test" {
cidr_block = "10.1.0.0/16"
}
resource "aws_subnet" "a" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.1.1.0/24"
availability_zone = "us-west-2a"
}
resource "aws_subnet" "b" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.1.2.0/24"
availability_zone = "us-west-2b"
}
resource "aws_db_subnet_group" "test" {
name_prefix = "tf_test-"
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
}`
const testAccDBSubnetGroupConfig_generatedName = `
resource "aws_vpc" "test" {
cidr_block = "10.1.0.0/16"
}
resource "aws_subnet" "a" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.1.1.0/24"
availability_zone = "us-west-2a"
}
resource "aws_subnet" "b" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.1.2.0/24"
availability_zone = "us-west-2b"
}
resource "aws_db_subnet_group" "test" {
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
}`
const testAccDBSubnetGroupConfig_withUnderscoresAndPeriodsAndSpaces = ` const testAccDBSubnetGroupConfig_withUnderscoresAndPeriodsAndSpaces = `
resource "aws_vpc" "main" { resource "aws_vpc" "main" {
cidr_block = "192.168.0.0/16" cidr_block = "192.168.0.0/16"

View File

@ -36,10 +36,19 @@ func resourceAwsRDSCluster() *schema.Resource {
}, },
"cluster_identifier": { "cluster_identifier": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"cluster_identifier_prefix"},
ValidateFunc: validateRdsIdentifier,
},
"cluster_identifier_prefix": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Optional: true,
Computed: true,
ForceNew: true, ForceNew: true,
ValidateFunc: validateRdsId, ValidateFunc: validateRdsIdentifierPrefix,
}, },
"cluster_members": { "cluster_members": {
@ -225,6 +234,19 @@ func resourceAwsRDSClusterCreate(d *schema.ResourceData, meta interface{}) error
conn := meta.(*AWSClient).rdsconn conn := meta.(*AWSClient).rdsconn
tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
var identifier string
if v, ok := d.GetOk("cluster_identifier"); ok {
identifier = v.(string)
} else {
if v, ok := d.GetOk("cluster_identifier_prefix"); ok {
identifier = resource.PrefixedUniqueId(v.(string))
} else {
identifier = resource.PrefixedUniqueId("tf-")
}
d.Set("cluster_identifier", identifier)
}
if _, ok := d.GetOk("snapshot_identifier"); ok { if _, ok := d.GetOk("snapshot_identifier"); ok {
opts := rds.RestoreDBClusterFromSnapshotInput{ opts := rds.RestoreDBClusterFromSnapshotInput{
DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)), DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)),

View File

@ -24,10 +24,19 @@ func resourceAwsRDSClusterInstance() *schema.Resource {
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"identifier": { "identifier": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"identifier_prefix"},
ValidateFunc: validateRdsIdentifier,
},
"identifier_prefix": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true,
ForceNew: true, ForceNew: true,
ValidateFunc: validateRdsId, ValidateFunc: validateRdsIdentifierPrefix,
}, },
"db_subnet_group_name": { "db_subnet_group_name": {
@ -162,10 +171,14 @@ func resourceAwsRDSClusterInstanceCreate(d *schema.ResourceData, meta interface{
createOpts.DBParameterGroupName = aws.String(attr.(string)) createOpts.DBParameterGroupName = aws.String(attr.(string))
} }
if v := d.Get("identifier").(string); v != "" { if v, ok := d.GetOk("identifier"); ok {
createOpts.DBInstanceIdentifier = aws.String(v) createOpts.DBInstanceIdentifier = aws.String(v.(string))
} else { } else {
createOpts.DBInstanceIdentifier = aws.String(resource.UniqueId()) if v, ok := d.GetOk("identifier_prefix"); ok {
createOpts.DBInstanceIdentifier = aws.String(resource.PrefixedUniqueId(v.(string)))
} else {
createOpts.DBInstanceIdentifier = aws.String(resource.PrefixedUniqueId("tf-"))
}
} }
if attr, ok := d.GetOk("db_subnet_group_name"); ok { if attr, ok := d.GetOk("db_subnet_group_name"); ok {

View File

@ -46,6 +46,48 @@ func TestAccAWSRDSClusterInstance_basic(t *testing.T) {
}) })
} }
func TestAccAWSRDSClusterInstance_namePrefix(t *testing.T) {
var v rds.DBInstance
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSClusterDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSClusterInstanceConfig_namePrefix(acctest.RandInt()),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSClusterInstanceExists("aws_rds_cluster_instance.test", &v),
testAccCheckAWSDBClusterInstanceAttributes(&v),
resource.TestMatchResourceAttr(
"aws_rds_cluster_instance.test", "identifier", regexp.MustCompile("^tf-cluster-instance-")),
),
},
},
})
}
func TestAccAWSRDSClusterInstance_generatedName(t *testing.T) {
var v rds.DBInstance
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSClusterDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSClusterInstanceConfig_generatedName(acctest.RandInt()),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSClusterInstanceExists("aws_rds_cluster_instance.test", &v),
testAccCheckAWSDBClusterInstanceAttributes(&v),
resource.TestMatchResourceAttr(
"aws_rds_cluster_instance.test", "identifier", regexp.MustCompile("^tf-")),
),
},
},
})
}
func TestAccAWSRDSClusterInstance_kmsKey(t *testing.T) { func TestAccAWSRDSClusterInstance_kmsKey(t *testing.T) {
var v rds.DBInstance var v rds.DBInstance
keyRegex := regexp.MustCompile("^arn:aws:kms:") keyRegex := regexp.MustCompile("^arn:aws:kms:")
@ -256,6 +298,83 @@ resource "aws_db_parameter_group" "bar" {
`, n, n, n) `, n, n, n)
} }
func testAccAWSClusterInstanceConfig_namePrefix(n int) string {
return fmt.Sprintf(`
resource "aws_rds_cluster_instance" "test" {
identifier_prefix = "tf-cluster-instance-"
cluster_identifier = "${aws_rds_cluster.test.id}"
instance_class = "db.r3.large"
}
resource "aws_rds_cluster" "test" {
cluster_identifier = "tf-aurora-cluster-%d"
master_username = "root"
master_password = "password"
db_subnet_group_name = "${aws_db_subnet_group.test.name}"
skip_final_snapshot = true
}
resource "aws_vpc" "test" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "a" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.0.0.0/24"
availability_zone = "us-west-2a"
}
resource "aws_subnet" "b" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.0.1.0/24"
availability_zone = "us-west-2b"
}
resource "aws_db_subnet_group" "test" {
name = "tf-test-%d"
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
}
`, n, n)
}
func testAccAWSClusterInstanceConfig_generatedName(n int) string {
return fmt.Sprintf(`
resource "aws_rds_cluster_instance" "test" {
cluster_identifier = "${aws_rds_cluster.test.id}"
instance_class = "db.r3.large"
}
resource "aws_rds_cluster" "test" {
cluster_identifier = "tf-aurora-cluster-%d"
master_username = "root"
master_password = "password"
db_subnet_group_name = "${aws_db_subnet_group.test.name}"
skip_final_snapshot = true
}
resource "aws_vpc" "test" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "a" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.0.0.0/24"
availability_zone = "us-west-2a"
}
resource "aws_subnet" "b" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.0.1.0/24"
availability_zone = "us-west-2b"
}
resource "aws_db_subnet_group" "test" {
name = "tf-test-%d"
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
}
`, n, n)
}
func testAccAWSClusterInstanceConfigKmsKey(n int) string { func testAccAWSClusterInstanceConfigKmsKey(n int) string {
return fmt.Sprintf(` return fmt.Sprintf(`

View File

@ -29,10 +29,19 @@ func resourceAwsRDSClusterParameterGroup() *schema.Resource {
Computed: true, Computed: true,
}, },
"name": &schema.Schema{ "name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"name_prefix"},
ValidateFunc: validateDbParamGroupName,
},
"name_prefix": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true, ForceNew: true,
Required: true, ValidateFunc: validateDbParamGroupNamePrefix,
ValidateFunc: validateDbParamGroupName,
}, },
"family": &schema.Schema{ "family": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
@ -86,8 +95,17 @@ func resourceAwsRDSClusterParameterGroupCreate(d *schema.ResourceData, meta inte
rdsconn := meta.(*AWSClient).rdsconn rdsconn := meta.(*AWSClient).rdsconn
tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
var groupName string
if v, ok := d.GetOk("name"); ok {
groupName = v.(string)
} else if v, ok := d.GetOk("name_prefix"); ok {
groupName = resource.PrefixedUniqueId(v.(string))
} else {
groupName = resource.UniqueId()
}
createOpts := rds.CreateDBClusterParameterGroupInput{ createOpts := rds.CreateDBClusterParameterGroupInput{
DBClusterParameterGroupName: aws.String(d.Get("name").(string)), DBClusterParameterGroupName: aws.String(groupName),
DBParameterGroupFamily: aws.String(d.Get("family").(string)), DBParameterGroupFamily: aws.String(d.Get("family").(string)),
Description: aws.String(d.Get("description").(string)), Description: aws.String(d.Get("description").(string)),
Tags: tags, Tags: tags,

View File

@ -3,6 +3,7 @@ package aws
import ( import (
"errors" "errors"
"fmt" "fmt"
"regexp"
"testing" "testing"
"time" "time"
@ -90,6 +91,44 @@ func TestAccAWSDBClusterParameterGroup_basic(t *testing.T) {
}) })
} }
func TestAccAWSDBClusterParameterGroup_namePrefix(t *testing.T) {
var v rds.DBClusterParameterGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBClusterParameterGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSDBClusterParameterGroupConfig_namePrefix,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBClusterParameterGroupExists("aws_rds_cluster_parameter_group.test", &v),
resource.TestMatchResourceAttr(
"aws_rds_cluster_parameter_group.test", "name", regexp.MustCompile("^tf-test-")),
),
},
},
})
}
func TestAccAWSDBClusterParameterGroup_generatedName(t *testing.T) {
var v rds.DBClusterParameterGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBClusterParameterGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSDBClusterParameterGroupConfig_generatedName,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBClusterParameterGroupExists("aws_rds_cluster_parameter_group.test", &v),
),
},
},
})
}
func TestAccAWSDBClusterParameterGroup_disappears(t *testing.T) { func TestAccAWSDBClusterParameterGroup_disappears(t *testing.T) {
var v rds.DBClusterParameterGroup var v rds.DBClusterParameterGroup
@ -365,3 +404,15 @@ func testAccAWSDBClusterParameterGroupOnlyConfig(name string) string {
family = "aurora5.6" family = "aurora5.6"
}`, name) }`, name)
} }
const testAccAWSDBClusterParameterGroupConfig_namePrefix = `
resource "aws_rds_cluster_parameter_group" "test" {
name_prefix = "tf-test-"
family = "aurora5.6"
}
`
const testAccAWSDBClusterParameterGroupConfig_generatedName = `
resource "aws_rds_cluster_parameter_group" "test" {
family = "aurora5.6"
}
`

View File

@ -40,6 +40,46 @@ func TestAccAWSRDSCluster_basic(t *testing.T) {
}) })
} }
func TestAccAWSRDSCluster_namePrefix(t *testing.T) {
var v rds.DBCluster
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSClusterDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSClusterConfig_namePrefix(acctest.RandInt()),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSClusterExists("aws_rds_cluster.test", &v),
resource.TestMatchResourceAttr(
"aws_rds_cluster.test", "cluster_identifier", regexp.MustCompile("^tf-test-")),
),
},
},
})
}
func TestAccAWSRDSCluster_generatedName(t *testing.T) {
var v rds.DBCluster
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSClusterDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSClusterConfig_generatedName(acctest.RandInt()),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSClusterExists("aws_rds_cluster.test", &v),
resource.TestMatchResourceAttr(
"aws_rds_cluster.test", "cluster_identifier", regexp.MustCompile("^tf-")),
),
},
},
})
}
func TestAccAWSRDSCluster_takeFinalSnapshot(t *testing.T) { func TestAccAWSRDSCluster_takeFinalSnapshot(t *testing.T) {
var v rds.DBCluster var v rds.DBCluster
rInt := acctest.RandInt() rInt := acctest.RandInt()
@ -322,6 +362,71 @@ resource "aws_rds_cluster" "default" {
}`, n) }`, n)
} }
func testAccAWSClusterConfig_namePrefix(n int) string {
return fmt.Sprintf(`
resource "aws_rds_cluster" "test" {
cluster_identifier_prefix = "tf-test-"
master_username = "root"
master_password = "password"
db_subnet_group_name = "${aws_db_subnet_group.test.name}"
skip_final_snapshot = true
}
resource "aws_vpc" "test" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "a" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.0.0.0/24"
availability_zone = "us-west-2a"
}
resource "aws_subnet" "b" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.0.1.0/24"
availability_zone = "us-west-2b"
}
resource "aws_db_subnet_group" "test" {
name = "tf-test-%d"
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
}
`, n)
}
func testAccAWSClusterConfig_generatedName(n int) string {
return fmt.Sprintf(`
resource "aws_rds_cluster" "test" {
master_username = "root"
master_password = "password"
db_subnet_group_name = "${aws_db_subnet_group.test.name}"
skip_final_snapshot = true
}
resource "aws_vpc" "test" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "a" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.0.0.0/24"
availability_zone = "us-west-2a"
}
resource "aws_subnet" "b" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "10.0.1.0/24"
availability_zone = "us-west-2b"
}
resource "aws_db_subnet_group" "test" {
name = "tf-test-%d"
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
}
`, n)
}
func testAccAWSClusterConfigWithFinalSnapshot(n int) string { func testAccAWSClusterConfigWithFinalSnapshot(n int) string {
return fmt.Sprintf(` return fmt.Sprintf(`
resource "aws_rds_cluster" "default" { resource "aws_rds_cluster" "default" {

View File

@ -12,7 +12,7 @@ import (
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
) )
func validateRdsId(v interface{}, k string) (ws []string, errors []error) { func validateRdsIdentifier(v interface{}, k string) (ws []string, errors []error) {
value := v.(string) value := v.(string)
if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf( errors = append(errors, fmt.Errorf(
@ -33,6 +33,23 @@ func validateRdsId(v interface{}, k string) (ws []string, errors []error) {
return return
} }
func validateRdsIdentifierPrefix(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"only lowercase alphanumeric characters and hyphens allowed in %q", k))
}
if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"first character of %q must be a letter", k))
}
if regexp.MustCompile(`--`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q cannot contain two consecutive hyphens", k))
}
return
}
func validateElastiCacheClusterId(v interface{}, k string) (ws []string, errors []error) { func validateElastiCacheClusterId(v interface{}, k string) (ws []string, errors []error) {
value := v.(string) value := v.(string)
if (len(value) < 1) || (len(value) > 20) { if (len(value) < 1) || (len(value) > 20) {
@ -103,7 +120,27 @@ func validateDbParamGroupName(v interface{}, k string) (ws []string, errors []er
"%q cannot be greater than 255 characters", k)) "%q cannot be greater than 255 characters", k))
} }
return return
}
func validateDbParamGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"only lowercase alphanumeric characters and hyphens allowed in %q", k))
}
if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"first character of %q must be a letter", k))
}
if regexp.MustCompile(`--`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q cannot contain two consecutive hyphens", k))
}
if len(value) > 255 {
errors = append(errors, fmt.Errorf(
"%q cannot be greater than 226 characters", k))
}
return
} }
func validateStreamViewType(v interface{}, k string) (ws []string, errors []error) { func validateStreamViewType(v interface{}, k string) (ws []string, errors []error) {
@ -1041,3 +1078,79 @@ func validateApiGatewayUsagePlanQuotaSettings(v map[string]interface{}) (errors
return return
} }
func validateDbSubnetGroupName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
}
if len(value) > 255 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 255 characters", k))
}
if regexp.MustCompile(`(?i)^default$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q is not allowed as %q", "Default", k))
}
return
}
func validateDbSubnetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
}
if len(value) > 229 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 229 characters", k))
}
return
}
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
}
func validateDbOptionGroupNamePrefix(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 len(value) > 229 {
errors = append(errors, fmt.Errorf(
"%q cannot be greater than 229 characters", k))
}
return
}

View File

@ -1785,3 +1785,131 @@ func TestValidateElbNamePrefix(t *testing.T) {
} }
} }
} }
func TestValidateDbSubnetGroupName(t *testing.T) {
cases := []struct {
Value string
ErrCount int
}{
{
Value: "tEsting",
ErrCount: 1,
},
{
Value: "testing?",
ErrCount: 1,
},
{
Value: "default",
ErrCount: 1,
},
{
Value: randomString(300),
ErrCount: 1,
},
}
for _, tc := range cases {
_, errors := validateDbSubnetGroupName(tc.Value, "aws_db_subnet_group")
if len(errors) != tc.ErrCount {
t.Fatalf("Expected the DB Subnet Group name to trigger a validation error")
}
}
}
func TestValidateDbSubnetGroupNamePrefix(t *testing.T) {
cases := []struct {
Value string
ErrCount int
}{
{
Value: "tEsting",
ErrCount: 1,
},
{
Value: "testing?",
ErrCount: 1,
},
{
Value: randomString(230),
ErrCount: 1,
},
}
for _, tc := range cases {
_, errors := validateDbSubnetGroupNamePrefix(tc.Value, "aws_db_subnet_group")
if len(errors) != tc.ErrCount {
t.Fatalf("Expected the DB Subnet Group name prefix to trigger a validation error")
}
}
}
func TestValidateDbOptionGroupName(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 TestValidateDbOptionGroupNamePrefix(t *testing.T) {
cases := []struct {
Value string
ErrCount int
}{
{
Value: "testing123!",
ErrCount: 1,
},
{
Value: "1testing123",
ErrCount: 1,
},
{
Value: "testing--123",
ErrCount: 1,
},
{
Value: randomString(230),
ErrCount: 1,
},
}
for _, tc := range cases {
_, errors := validateDbOptionGroupNamePrefix(tc.Value, "aws_db_option_group_name")
if len(errors) != tc.ErrCount {
t.Fatalf("Expected the DB Option Group name prefix to trigger a validation error")
}
}
}

View File

@ -55,7 +55,8 @@ The following arguments are supported:
* `allocated_storage` - (Required unless a `snapshot_identifier` or `replicate_source_db` is provided) The allocated storage in gigabytes. * `allocated_storage` - (Required unless a `snapshot_identifier` or `replicate_source_db` is provided) The allocated storage in gigabytes.
* `engine` - (Required unless a `snapshot_identifier` or `replicate_source_db` is provided) The database engine to use. * `engine` - (Required unless a `snapshot_identifier` or `replicate_source_db` is provided) The database engine to use.
* `engine_version` - (Optional) The engine version to use. * `engine_version` - (Optional) The engine version to use.
* `identifier` - (Optional) The name of the RDS instance, if omitted, Terraform will assign a random, unique name * `identifier` - (Optional, Forces new resource) The name of the RDS instance, if omitted, Terraform will assign a random, unique identifier.
* `identifier_prefix` - (Optional, Forces new resource) Creates a unique identifier beginning with the specified prefix. Conflicts with `identifer`.
* `instance_class` - (Required) The instance type of the RDS instance. * `instance_class` - (Required) The instance type of the RDS instance.
* `storage_type` - (Optional) One of "standard" (magnetic), "gp2" (general * `storage_type` - (Optional) One of "standard" (magnetic), "gp2" (general
purpose SSD), or "io1" (provisioned IOPS SSD). The default is "io1" if purpose SSD), or "io1" (provisioned IOPS SSD). The default is "io1" if

View File

@ -38,8 +38,9 @@ resource "aws_db_option_group" "bar" {
The following arguments are supported: The following arguments are supported:
* `name` - (Required) The name of the Option group to be created. * `name` - (Optional, Forces new resource) The name of the option group. If omitted, Terraform will assign a random, unique name.
* `option_group_description` - (Required) The description of the option group. * `name_prefix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`.
* `option_group_description` - (Optional) The description of the option group. Defaults to "Managed by Terraform".
* `engine_name` - (Required) Specifies the name of the engine that this option group should be associated with.. * `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. * `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. * `option` - (Optional) A list of Options to apply.

View File

@ -31,7 +31,8 @@ resource "aws_db_parameter_group" "default" {
The following arguments are supported: The following arguments are supported:
* `name` - (Required) The name of the DB parameter group. * `name` - (Optional, Forces new resource) The name of the DB parameter group. If omitted, Terraform will assign a random, unique name.
* `name_prefix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`.
* `family` - (Required) The family of the DB parameter group. * `family` - (Required) The family of the DB parameter group.
* `description` - (Optional) The description of the DB parameter group. Defaults to "Managed by Terraform". * `description` - (Optional) The description of the DB parameter group. Defaults to "Managed by Terraform".
* `parameter` - (Optional) A list of DB parameters to apply. * `parameter` - (Optional) A list of DB parameters to apply.

View File

@ -27,7 +27,8 @@ resource "aws_db_subnet_group" "default" {
The following arguments are supported: The following arguments are supported:
* `name` - (Required) The name of the DB subnet group. * `name` - (Optional, Forces new resource) The name of the DB subnet group. If omitted, Terraform will assign a random, unique name.
* `name_prefix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`.
* `description` - (Optional) The description of the DB subnet group. Defaults to "Managed by Terraform". * `description` - (Optional) The description of the DB subnet group. Defaults to "Managed by Terraform".
* `subnet_ids` - (Required) A list of VPC subnet IDs. * `subnet_ids` - (Required) A list of VPC subnet IDs.
* `tags` - (Optional) A mapping of tags to assign to the resource. * `tags` - (Optional) A mapping of tags to assign to the resource.

View File

@ -53,8 +53,8 @@ the [AWS official documentation](https://docs.aws.amazon.com/AmazonRDS/latest/Co
The following arguments are supported: The following arguments are supported:
* `cluster_identifier` - (Required) The Cluster Identifier. Must be a lower case * `cluster_identifier` - (Optional, Forces new resources) The cluster identifier. If omitted, Terraform will assign a random, unique identifier.
string. * `cluster_identifier_prefix` - (Optional, Forces new resource) Creates a unique cluster identifier beginning with the specified prefix. Conflicts with `cluster_identifer`.
* `database_name` - (Optional) The name for your database of up to 8 alpha-numeric * `database_name` - (Optional) The name for your database of up to 8 alpha-numeric
characters. If you do not provide a name, Amazon RDS will not create a characters. If you do not provide a name, Amazon RDS will not create a
database in the DB cluster you are creating database in the DB cluster you are creating

View File

@ -47,8 +47,8 @@ the [AWS official documentation](https://docs.aws.amazon.com/AmazonRDS/latest/Co
The following arguments are supported: The following arguments are supported:
* `identifier` - (Optional) The Instance Identifier. Must be a lower case * `identifier` - (Optional, Forces new resource) The indentifier for the RDS instance, if omitted, Terraform will assign a random, unique identifier.
string. If omitted, a unique identifier will be generated. * `identifier_prefix` - (Optional, Forces new resource) Creates a unique identifier beginning with the specified prefix. Conflicts with `identifer`.
* `cluster_identifier` - (Required) The identifier of the [`aws_rds_cluster`](/docs/providers/aws/r/rds_cluster.html) in which to launch this instance. * `cluster_identifier` - (Required) The identifier of the [`aws_rds_cluster`](/docs/providers/aws/r/rds_cluster.html) in which to launch this instance.
* `instance_class` - (Required) The instance class to use. For details on CPU * `instance_class` - (Required) The instance class to use. For details on CPU
and memory, see [Scaling Aurora DB Instances][4]. Aurora currently and memory, see [Scaling Aurora DB Instances][4]. Aurora currently

View File

@ -32,9 +32,10 @@ resource "aws_rds_cluster_parameter_group" "default" {
The following arguments are supported: The following arguments are supported:
* `name` - (Required) The name of the DB cluster parameter group. * `name` - (Optional, Forces new resource) The name of the DB cluster parameter group. If omitted, Terraform will assign a random, unique name.
* `name_prefix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`.
* `family` - (Required) The family of the DB cluster parameter group. * `family` - (Required) The family of the DB cluster parameter group.
* `description` - (Required) The description of the DB cluster parameter group. * `description` - (Optional) The description of the DB cluster parameter group. Defaults to "Managed by Terraform".
* `parameter` - (Optional) A list of DB parameters to apply. * `parameter` - (Optional) A list of DB parameters to apply.
* `tags` - (Optional) A mapping of tags to assign to the resource. * `tags` - (Optional) A mapping of tags to assign to the resource.