From 31b52a37acad9cc0aa09cd55c660f15a3b24856b Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 30 Aug 2019 16:46:33 -0400 Subject: [PATCH 1/3] service/elasticache: Support longer Cluster and Replication Group identifiers This also switches some of the hardcoded us-west-2 testing to use the aws_availability_zones data source so the testing is more region agnostic. Now its at least possible to run parallel testing locally in us-east-1 of an EC2-Classic enabled AWS account. References: - https://github.com/terraform-providers/terraform-provider-aws/issues/9906 - https://github.com/terraform-providers/terraform-provider-aws/issues/9131 - https://github.com/terraform-providers/terraform-provider-aws/pull/7409 - https://github.com/terraform-providers/terraform-provider-aws/issues/5381 Output from acceptance testing: ``` --- PASS: TestAccAWSElasticacheCluster_AZMode_Memcached_Ec2Classic (515.21s) --- PASS: TestAccAWSElasticacheCluster_AZMode_Redis_Ec2Classic (507.64s) --- PASS: TestAccAWSElasticacheCluster_Engine_Memcached_Ec2Classic (663.59s) --- PASS: TestAccAWSElasticacheCluster_Engine_Redis_Ec2Classic (595.65s) --- PASS: TestAccAWSElasticacheCluster_EngineVersion_Memcached_Ec2Classic (1260.72s) --- PASS: TestAccAWSElasticacheCluster_EngineVersion_Redis_Ec2Classic (1303.63s) --- PASS: TestAccAWSElasticacheCluster_multiAZInVpc (737.16s) --- PASS: TestAccAWSElasticacheCluster_NodeTypeResize_Memcached_Ec2Classic (954.44s) --- PASS: TestAccAWSElasticacheCluster_NodeTypeResize_Redis_Ec2Classic (1022.11s) --- PASS: TestAccAWSElasticacheCluster_NumCacheNodes_Decrease (995.54s) --- PASS: TestAccAWSElasticacheCluster_NumCacheNodes_Increase (1038.00s) --- PASS: TestAccAWSElasticacheCluster_NumCacheNodes_IncreaseWithPreferredAvailabilityZones (958.56s) --- PASS: TestAccAWSElasticacheCluster_NumCacheNodes_Redis_Ec2Classic (6.63s) --- PASS: TestAccAWSElasticacheCluster_ParameterGroupName_Default (596.16s) --- PASS: TestAccAWSElasticacheCluster_Port_Ec2Classic (576.63s) --- PASS: TestAccAWSElasticacheCluster_ReplicationGroupID_AvailabilityZone_Ec2Classic (1214.33s) --- PASS: TestAccAWSElasticacheCluster_ReplicationGroupID_InvalidAttributes (8.37s) --- PASS: TestAccAWSElasticacheCluster_ReplicationGroupID_MultipleReplica_Ec2Classic (1884.91s) --- PASS: TestAccAWSElasticacheCluster_ReplicationGroupID_SingleReplica_Ec2Classic (1746.94s) --- PASS: TestAccAWSElasticacheCluster_SecurityGroup (626.97s) --- PASS: TestAccAWSElasticacheCluster_snapshotsWithUpdates (1167.22s) --- PASS: TestAccAWSElasticacheCluster_vpc (646.18s) --- PASS: TestAccAWSElasticacheReplicationGroup_basic (1857.56s) --- PASS: TestAccAWSElasticacheReplicationGroup_clusteringAndCacheNodesCausesError (10.99s) --- PASS: TestAccAWSElasticacheReplicationGroup_ClusterMode_Basic (1875.48s) --- PASS: TestAccAWSElasticacheReplicationGroup_ClusterMode_NumNodeGroups (3713.74s) --- PASS: TestAccAWSElasticacheReplicationGroup_enableAtRestEncryption (1419.18s) --- PASS: TestAccAWSElasticacheReplicationGroup_enableAuthTokenTransitEncryption (734.55s) --- PASS: TestAccAWSElasticacheReplicationGroup_enableSnapshotting (1917.01s) --- PASS: TestAccAWSElasticacheReplicationGroup_importBasic (806.91s) --- PASS: TestAccAWSElasticacheReplicationGroup_multiAzInVpc (950.44s) --- PASS: TestAccAWSElasticacheReplicationGroup_NumberCacheClusters (2821.85s) --- PASS: TestAccAWSElasticacheReplicationGroup_NumberCacheClusters_Failover_AutoFailoverDisabled (2029.86s) --- PASS: TestAccAWSElasticacheReplicationGroup_NumberCacheClusters_Failover_AutoFailoverEnabled (1919.87s) --- PASS: TestAccAWSElasticacheReplicationGroup_redisClusterInVpc2 (737.16s) --- PASS: TestAccAWSElasticacheReplicationGroup_updateDescription (1240.24s) --- PASS: TestAccAWSElasticacheReplicationGroup_updateMaintenanceWindow (1047.59s) --- PASS: TestAccAWSElasticacheReplicationGroup_updateNodeSize (1985.53s) --- PASS: TestAccAWSElasticacheReplicationGroup_updateParameterGroup (900.33s) --- PASS: TestAccAWSElasticacheReplicationGroup_Uppercase (594.69s) --- PASS: TestAccAWSElasticacheReplicationGroup_vpc (1355.75s) ``` --- aws/resource_aws_elasticache_cluster.go | 9 +- aws/resource_aws_elasticache_cluster_test.go | 62 +++-- ...ource_aws_elasticache_replication_group.go | 33 +-- ..._aws_elasticache_replication_group_test.go | 235 ++++++++++-------- aws/validators.go | 23 ++ 5 files changed, 206 insertions(+), 156 deletions(-) diff --git a/aws/resource_aws_elasticache_cluster.go b/aws/resource_aws_elasticache_cluster.go index 93e557aa2c8..d8f72b8cff9 100644 --- a/aws/resource_aws_elasticache_cluster.go +++ b/aws/resource_aws_elasticache_cluster.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "log" + "regexp" "sort" "strings" "time" @@ -95,7 +96,13 @@ func resourceAwsElasticacheCluster() *schema.Resource { // with non-converging diffs. return strings.ToLower(val.(string)) }, - ValidateFunc: validateElastiCacheClusterId, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 50), + validation.StringMatch(regexp.MustCompile(`^[0-9a-z-]+$`), "must contain only lowercase alphanumeric characters and hyphens"), + validation.StringMatch(regexp.MustCompile(`^[a-z]`), "must begin with a lowercase letter"), + validateStringNotMatch(regexp.MustCompile(`--`), "cannot contain two consecutive hyphens"), + validateStringNotMatch(regexp.MustCompile(`-$`), "cannot end with a hyphen"), + ), }, "configuration_endpoint": { Type: schema.TypeString, diff --git a/aws/resource_aws_elasticache_cluster_test.go b/aws/resource_aws_elasticache_cluster_test.go index 5326cff4893..3f4340c59d9 100644 --- a/aws/resource_aws_elasticache_cluster_test.go +++ b/aws/resource_aws_elasticache_cluster_test.go @@ -73,7 +73,7 @@ func TestAccAWSElasticacheCluster_Engine_Memcached_Ec2Classic(t *testing.T) { defer os.Setenv("AWS_DEFAULT_REGION", oldvar) var ec elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -110,7 +110,7 @@ func TestAccAWSElasticacheCluster_Engine_Redis_Ec2Classic(t *testing.T) { defer os.Setenv("AWS_DEFAULT_REGION", oldvar) var ec elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -141,7 +141,7 @@ func TestAccAWSElasticacheCluster_Engine_Redis_Ec2Classic(t *testing.T) { func TestAccAWSElasticacheCluster_ParameterGroupName_Default(t *testing.T) { var ec elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.test" resource.ParallelTest(t, resource.TestCase{ @@ -177,7 +177,7 @@ func TestAccAWSElasticacheCluster_Port_Ec2Classic(t *testing.T) { var ec elasticache.CacheCluster port := 11212 - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -271,7 +271,7 @@ func TestAccAWSElasticacheCluster_snapshotsWithUpdates(t *testing.T) { func TestAccAWSElasticacheCluster_NumCacheNodes_Decrease(t *testing.T) { var ec elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -299,7 +299,7 @@ func TestAccAWSElasticacheCluster_NumCacheNodes_Decrease(t *testing.T) { func TestAccAWSElasticacheCluster_NumCacheNodes_Increase(t *testing.T) { var ec elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -327,7 +327,7 @@ func TestAccAWSElasticacheCluster_NumCacheNodes_Increase(t *testing.T) { func TestAccAWSElasticacheCluster_NumCacheNodes_IncreaseWithPreferredAvailabilityZones(t *testing.T) { var ec elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -369,8 +369,6 @@ func TestAccAWSElasticacheCluster_vpc(t *testing.T) { testAccCheckAWSElasticacheSubnetGroupExists("aws_elasticache_subnet_group.bar", &csg), testAccCheckAWSElasticacheClusterExists("aws_elasticache_cluster.bar", &ec), testAccCheckAWSElasticacheClusterAttributes(&ec), - resource.TestCheckResourceAttr( - "aws_elasticache_cluster.bar", "availability_zone", "us-west-2a"), ), }, }, @@ -404,7 +402,7 @@ func TestAccAWSElasticacheCluster_AZMode_Memcached_Ec2Classic(t *testing.T) { defer os.Setenv("AWS_DEFAULT_REGION", oldvar) var cluster elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -441,7 +439,7 @@ func TestAccAWSElasticacheCluster_AZMode_Redis_Ec2Classic(t *testing.T) { defer os.Setenv("AWS_DEFAULT_REGION", oldvar) var cluster elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -474,7 +472,7 @@ func TestAccAWSElasticacheCluster_EngineVersion_Memcached_Ec2Classic(t *testing. defer os.Setenv("AWS_DEFAULT_REGION", oldvar) var pre, mid, post elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -515,7 +513,7 @@ func TestAccAWSElasticacheCluster_EngineVersion_Redis_Ec2Classic(t *testing.T) { defer os.Setenv("AWS_DEFAULT_REGION", oldvar) var pre, mid, post elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -556,7 +554,7 @@ func TestAccAWSElasticacheCluster_NodeTypeResize_Memcached_Ec2Classic(t *testing defer os.Setenv("AWS_DEFAULT_REGION", oldvar) var pre, post elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -589,7 +587,7 @@ func TestAccAWSElasticacheCluster_NodeTypeResize_Redis_Ec2Classic(t *testing.T) defer os.Setenv("AWS_DEFAULT_REGION", oldvar) var pre, post elasticache.CacheCluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_cluster.bar" resource.ParallelTest(t, resource.TestCase{ @@ -621,7 +619,7 @@ func TestAccAWSElasticacheCluster_NumCacheNodes_Redis_Ec2Classic(t *testing.T) { os.Setenv("AWS_DEFAULT_REGION", "us-east-1") defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccEC2ClassicPreCheck(t) }, @@ -641,7 +639,7 @@ func TestAccAWSElasticacheCluster_ReplicationGroupID_InvalidAttributes(t *testin os.Setenv("AWS_DEFAULT_REGION", "us-east-1") defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(8)) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccEC2ClassicPreCheck(t) }, @@ -723,7 +721,7 @@ func TestAccAWSElasticacheCluster_ReplicationGroupID_AvailabilityZone_Ec2Classic var cluster elasticache.CacheCluster var replicationGroup elasticache.ReplicationGroup - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(7)) + rName := acctest.RandomWithPrefix("tf-acc-test") clusterResourceName := "aws_elasticache_cluster.replica" replicationGroupResourceName := "aws_elasticache_replication_group.test" @@ -751,7 +749,7 @@ func TestAccAWSElasticacheCluster_ReplicationGroupID_SingleReplica_Ec2Classic(t var cluster elasticache.CacheCluster var replicationGroup elasticache.ReplicationGroup - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(7)) + rName := acctest.RandomWithPrefix("tf-acc-test") clusterResourceName := "aws_elasticache_cluster.replica" replicationGroupResourceName := "aws_elasticache_replication_group.test" @@ -782,7 +780,7 @@ func TestAccAWSElasticacheCluster_ReplicationGroupID_MultipleReplica_Ec2Classic( var cluster1, cluster2 elasticache.CacheCluster var replicationGroup elasticache.ReplicationGroup - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(7)) + rName := acctest.RandomWithPrefix("tf-acc-test") clusterResourceName1 := "aws_elasticache_cluster.replica.0" clusterResourceName2 := "aws_elasticache_cluster.replica.1" replicationGroupResourceName := "aws_elasticache_replication_group.test" @@ -1095,6 +1093,12 @@ resource "aws_elasticache_cluster" "bar" { } var testAccAWSElasticacheClusterInVPCConfig = fmt.Sprintf(` +data "aws_availability_zones" "available" { + # InsufficientCacheClusterCapacity: cache.m1.small (VPC) is not currently supported in the availability zone us-east-1b + blacklisted_zone_ids = ["use1-az1"] + state = "available" +} + resource "aws_vpc" "foo" { cidr_block = "192.168.0.0/16" tags = { @@ -1105,7 +1109,7 @@ resource "aws_vpc" "foo" { resource "aws_subnet" "foo" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.0.0/20" - availability_zone = "us-west-2a" + availability_zone = "${data.aws_availability_zones.available.names[0]}" tags = { Name = "tf-acc-elasticache-cluster-in-vpc" } @@ -1143,7 +1147,7 @@ resource "aws_elasticache_cluster" "bar" { security_group_ids = ["${aws_security_group.bar.id}"] parameter_group_name = "default.redis2.8" notification_topic_arn = "${aws_sns_topic.topic_example.arn}" - availability_zone = "us-west-2a" + availability_zone = "${data.aws_availability_zones.available.names[0]}" } resource "aws_sns_topic" "topic_example" { @@ -1152,6 +1156,12 @@ resource "aws_sns_topic" "topic_example" { `, acctest.RandInt(), acctest.RandInt(), acctest.RandString(10)) var testAccAWSElasticacheClusterMultiAZInVPCConfig = fmt.Sprintf(` +data "aws_availability_zones" "available" { + # InsufficientCacheClusterCapacity: cache.m1.small (VPC) is not currently supported in the availability zone us-east-1b + blacklisted_zone_ids = ["use1-az1"] + state = "available" +} + resource "aws_vpc" "foo" { cidr_block = "192.168.0.0/16" tags = { @@ -1162,7 +1172,7 @@ resource "aws_vpc" "foo" { resource "aws_subnet" "foo" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.0.0/20" - availability_zone = "us-west-2a" + availability_zone = "${data.aws_availability_zones.available.names[0]}" tags = { Name = "tf-acc-elasticache-cluster-multi-az-in-vpc-foo" } @@ -1171,7 +1181,7 @@ resource "aws_subnet" "foo" { resource "aws_subnet" "bar" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.16.0/20" - availability_zone = "us-east-1c" + availability_zone = "${data.aws_availability_zones.available.names[1]}" tags = { Name = "tf-acc-elasticache-cluster-multi-az-in-vpc-bar" } @@ -1208,8 +1218,8 @@ resource "aws_elasticache_cluster" "bar" { security_group_ids = ["${aws_security_group.bar.id}"] az_mode = "cross-az" preferred_availability_zones = [ - "us-west-2a", - "us-west-2b" + "${data.aws_availability_zones.available.names[0]}", + "${data.aws_availability_zones.available.names[1]}" ] } `, acctest.RandInt(), acctest.RandInt(), acctest.RandString(10)) diff --git a/aws/resource_aws_elasticache_replication_group.go b/aws/resource_aws_elasticache_replication_group.go index 44d96fdf382..2486434c9f0 100644 --- a/aws/resource_aws_elasticache_replication_group.go +++ b/aws/resource_aws_elasticache_replication_group.go @@ -161,7 +161,13 @@ func resourceAwsElasticacheReplicationGroup() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validateAwsElastiCacheReplicationGroupId, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 40), + validation.StringMatch(regexp.MustCompile(`^[0-9a-zA-Z-]+$`), "must contain only alphanumeric characters and hyphens"), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z]`), "must begin with a letter"), + validateStringNotMatch(regexp.MustCompile(`--`), "cannot contain two consecutive hyphens"), + validateStringNotMatch(regexp.MustCompile(`-$`), "cannot end with a hyphen"), + ), StateFunc: func(val interface{}) string { return strings.ToLower(val.(string)) }, @@ -919,28 +925,3 @@ func validateAwsElastiCacheReplicationGroupEngine(v interface{}, k string) (ws [ } return } - -func validateAwsElastiCacheReplicationGroupId(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - if (len(value) < 1) || (len(value) > 20) { - errors = append(errors, fmt.Errorf( - "%q must contain from 1 to 20 alphanumeric characters or hyphens", 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(`^[a-zA-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 regexp.MustCompile(`-$`).MatchString(value) { - errors = append(errors, fmt.Errorf( - "%q cannot end with a hyphen", k)) - } - return -} diff --git a/aws/resource_aws_elasticache_replication_group_test.go b/aws/resource_aws_elasticache_replication_group_test.go index 98aabf2ed44..4da3c656647 100644 --- a/aws/resource_aws_elasticache_replication_group_test.go +++ b/aws/resource_aws_elasticache_replication_group_test.go @@ -5,6 +5,7 @@ import ( "log" "os" "regexp" + "strings" "testing" "time" @@ -62,7 +63,7 @@ func TestAccAWSElasticacheReplicationGroup_importBasic(t *testing.T) { os.Setenv("AWS_DEFAULT_REGION", "us-east-1") defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - name := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_replication_group.bar" @@ -72,7 +73,7 @@ func TestAccAWSElasticacheReplicationGroup_importBasic(t *testing.T) { CheckDestroy: testAccCheckAWSElasticacheReplicationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSElasticacheReplicationGroupConfig(name), + Config: testAccAWSElasticacheReplicationGroupConfig(rName), }, { @@ -87,6 +88,7 @@ func TestAccAWSElasticacheReplicationGroup_importBasic(t *testing.T) { func TestAccAWSElasticacheReplicationGroup_basic(t *testing.T) { var rg elasticache.ReplicationGroup + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -94,7 +96,7 @@ func TestAccAWSElasticacheReplicationGroup_basic(t *testing.T) { CheckDestroy: testAccCheckAWSElasticacheReplicationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSElasticacheReplicationGroupConfig(acctest.RandString(10)), + Config: testAccAWSElasticacheReplicationGroupConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists("aws_elasticache_replication_group.bar", &rg), resource.TestCheckResourceAttr( @@ -113,19 +115,18 @@ func TestAccAWSElasticacheReplicationGroup_basic(t *testing.T) { func TestAccAWSElasticacheReplicationGroup_Uppercase(t *testing.T) { var rg elasticache.ReplicationGroup - rStr := acctest.RandString(5) - rgName := fmt.Sprintf("TF-ELASTIRG-%s", rStr) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSElasticacheReplicationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSElasticacheReplicationGroupConfig_Uppercase(rgName), + Config: testAccAWSElasticacheReplicationGroupConfig_Uppercase(strings.ToUpper(rName)), Check: resource.ComposeTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists("aws_elasticache_replication_group.bar", &rg), resource.TestCheckResourceAttr( - "aws_elasticache_replication_group.bar", "replication_group_id", fmt.Sprintf("tf-elastirg-%s", rStr)), + "aws_elasticache_replication_group.bar", "replication_group_id", rName), ), }, }, @@ -134,7 +135,7 @@ func TestAccAWSElasticacheReplicationGroup_Uppercase(t *testing.T) { func TestAccAWSElasticacheReplicationGroup_updateDescription(t *testing.T) { var rg elasticache.ReplicationGroup - rName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -171,7 +172,7 @@ func TestAccAWSElasticacheReplicationGroup_updateDescription(t *testing.T) { func TestAccAWSElasticacheReplicationGroup_updateMaintenanceWindow(t *testing.T) { var rg elasticache.ReplicationGroup - rName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -199,7 +200,7 @@ func TestAccAWSElasticacheReplicationGroup_updateMaintenanceWindow(t *testing.T) func TestAccAWSElasticacheReplicationGroup_updateNodeSize(t *testing.T) { var rg elasticache.ReplicationGroup - rName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -236,7 +237,7 @@ func TestAccAWSElasticacheReplicationGroup_updateParameterGroup(t *testing.T) { parameterGroupResourceName1 := "aws_elasticache_parameter_group.test.0" parameterGroupResourceName2 := "aws_elasticache_parameter_group.test.1" resourceName := "aws_elasticache_replication_group.test" - rName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -339,7 +340,7 @@ func TestAccAWSElasticacheReplicationGroup_redisClusterInVpc2(t *testing.T) { func TestAccAWSElasticacheReplicationGroup_ClusterMode_Basic(t *testing.T) { var rg elasticache.ReplicationGroup - rName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_replication_group.bar" resource.ParallelTest(t, resource.TestCase{ @@ -365,7 +366,7 @@ func TestAccAWSElasticacheReplicationGroup_ClusterMode_Basic(t *testing.T) { func TestAccAWSElasticacheReplicationGroup_ClusterMode_NumNodeGroups(t *testing.T) { var rg elasticache.ReplicationGroup - rName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_replication_group.bar" resource.ParallelTest(t, resource.TestCase{ @@ -409,7 +410,7 @@ func TestAccAWSElasticacheReplicationGroup_ClusterMode_NumNodeGroups(t *testing. func TestAccAWSElasticacheReplicationGroup_clusteringAndCacheNodesCausesError(t *testing.T) { rInt := acctest.RandInt() - rName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -426,7 +427,7 @@ func TestAccAWSElasticacheReplicationGroup_clusteringAndCacheNodesCausesError(t func TestAccAWSElasticacheReplicationGroup_enableSnapshotting(t *testing.T) { var rg elasticache.ReplicationGroup - rName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -494,7 +495,7 @@ func TestAccAWSElasticacheReplicationGroup_enableAtRestEncryption(t *testing.T) func TestAccAWSElasticacheReplicationGroup_NumberCacheClusters(t *testing.T) { var replicationGroup elasticache.ReplicationGroup - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(4)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_replication_group.test" resource.ParallelTest(t, resource.TestCase{ @@ -532,7 +533,7 @@ func TestAccAWSElasticacheReplicationGroup_NumberCacheClusters(t *testing.T) { func TestAccAWSElasticacheReplicationGroup_NumberCacheClusters_Failover_AutoFailoverDisabled(t *testing.T) { var replicationGroup elasticache.ReplicationGroup - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(4)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_replication_group.test" resource.ParallelTest(t, resource.TestCase{ @@ -577,7 +578,7 @@ func TestAccAWSElasticacheReplicationGroup_NumberCacheClusters_Failover_AutoFail func TestAccAWSElasticacheReplicationGroup_NumberCacheClusters_Failover_AutoFailoverEnabled(t *testing.T) { var replicationGroup elasticache.ReplicationGroup - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(4)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_elasticache_replication_group.test" resource.ParallelTest(t, resource.TestCase{ @@ -648,46 +649,6 @@ func TestAccAWSElasticacheReplicationGroup_NumberCacheClusters_Failover_AutoFail }) } -func TestResourceAWSElastiCacheReplicationGroupIdValidation(t *testing.T) { - cases := []struct { - Value string - ErrCount int - }{ - { - Value: "tEsting", - ErrCount: 0, - }, - { - Value: "t.sting", - ErrCount: 1, - }, - { - Value: "t--sting", - ErrCount: 1, - }, - { - Value: "1testing", - ErrCount: 1, - }, - { - Value: "testing-", - ErrCount: 1, - }, - { - Value: randomString(21), - ErrCount: 1, - }, - } - - for _, tc := range cases { - _, errors := validateAwsElastiCacheReplicationGroupId(tc.Value, "aws_elasticache_replication_group_replication_group_id") - - if len(errors) != tc.ErrCount { - t.Fatalf("Expected the ElastiCache Replication Group Id to trigger a validation error") - } - } -} - func TestResourceAWSElastiCacheReplicationGroupEngineValidation(t *testing.T) { cases := []struct { Value string @@ -776,7 +737,7 @@ provider "aws" { } resource "aws_security_group" "bar" { - name = "tf-test-security-group-%s" + name = %[1]q description = "tf-test-security-group-descr" ingress { @@ -788,13 +749,13 @@ resource "aws_security_group" "bar" { } resource "aws_elasticache_security_group" "bar" { - name = "tf-test-security-group-%s" + name = %[1]q description = "tf-test-security-group-descr" security_group_names = ["${aws_security_group.bar.name}"] } resource "aws_elasticache_replication_group" "bar" { - replication_group_id = "tf-%s" + replication_group_id = %[1]q replication_group_description = "test description" node_type = "cache.m1.small" number_cache_clusters = 2 @@ -805,19 +766,49 @@ resource "aws_elasticache_replication_group" "bar" { maintenance_window = "tue:06:30-tue:07:30" snapshot_window = "01:00-02:00" } -`, rName, rName, rName) +`, rName) } -func testAccAWSElasticacheReplicationGroupConfig_Uppercase(rgName string) string { +func testAccAWSElasticacheReplicationGroupConfig_Uppercase(rName string) string { return fmt.Sprintf(` +data "aws_availability_zones" "available" { + state = "available" +} + +resource "aws_vpc" "test" { + cidr_block = "192.168.0.0/16" + + tags = { + Name = "terraform-testacc-elasticache-replication-group-number-cache-clusters" + } +} + +resource "aws_subnet" "test" { + count = 2 + + availability_zone = "${data.aws_availability_zones.available.names[count.index]}" + cidr_block = "192.168.${count.index}.0/24" + vpc_id = "${aws_vpc.test.id}" + + tags = { + Name = "tf-acc-elasticache-replication-group-number-cache-clusters" + } +} + +resource "aws_elasticache_subnet_group" "test" { + name = %[1]q + subnet_ids = ["${aws_subnet.test.*.id[0]}", "${aws_subnet.test.*.id[1]}"] +} + resource "aws_elasticache_replication_group" "bar" { - replication_group_id = "%s" - replication_group_description = "test description" node_type = "cache.t2.micro" number_cache_clusters = 1 port = 6379 + replication_group_description = "test description" + replication_group_id = %[1]q + subnet_group_name = "${aws_elasticache_subnet_group.test.name}" } -`, rgName) +`, rName) } func testAccAWSElasticacheReplicationGroupConfigEnableSnapshotting(rName string) string { @@ -827,7 +818,7 @@ provider "aws" { } resource "aws_security_group" "bar" { - name = "tf-test-security-group-%s" + name = %[1]q description = "tf-test-security-group-descr" ingress { @@ -839,13 +830,13 @@ resource "aws_security_group" "bar" { } resource "aws_elasticache_security_group" "bar" { - name = "tf-test-security-group-%s" + name = %[1]q description = "tf-test-security-group-descr" security_group_names = ["${aws_security_group.bar.name}"] } resource "aws_elasticache_replication_group" "bar" { - replication_group_id = "tf-%s" + replication_group_id = %[1]q replication_group_description = "test description" node_type = "cache.m1.small" number_cache_clusters = 2 @@ -857,7 +848,7 @@ resource "aws_elasticache_replication_group" "bar" { snapshot_window = "01:00-02:00" snapshot_retention_limit = 2 } -`, rName, rName, rName) +`, rName) } func testAccAWSElasticacheReplicationGroupConfigParameterGroupName(rName string, parameterGroupNameIndex int) string { @@ -869,7 +860,7 @@ resource "aws_elasticache_parameter_group" "test" { # so unfortunately we must hardcode this for now family = "redis5.0" - name = "tf-%s-${count.index}" + name = "%[1]s-${count.index}" parameter { name = "maxmemory-policy" @@ -881,11 +872,11 @@ resource "aws_elasticache_replication_group" "test" { apply_immediately = true node_type = "cache.m1.small" number_cache_clusters = 2 - parameter_group_name = "${aws_elasticache_parameter_group.test.*.name[%d]}" + parameter_group_name = "${aws_elasticache_parameter_group.test.*.name[%[2]d]}" replication_group_description = "test description" - replication_group_id = "tf-%s" + replication_group_id = %[1]q } -`, rName, parameterGroupNameIndex, rName) +`, rName, parameterGroupNameIndex) } func testAccAWSElasticacheReplicationGroupConfigUpdatedDescription(rName string) string { @@ -895,7 +886,7 @@ provider "aws" { } resource "aws_security_group" "bar" { - name = "tf-test-security-group-%s" + name = %[1]q description = "tf-test-security-group-descr" ingress { @@ -907,13 +898,13 @@ resource "aws_security_group" "bar" { } resource "aws_elasticache_security_group" "bar" { - name = "tf-test-security-group-%s" + name = %[1]q description = "tf-test-security-group-descr" security_group_names = ["${aws_security_group.bar.name}"] } resource "aws_elasticache_replication_group" "bar" { - replication_group_id = "tf-%s" + replication_group_id = %[1]q replication_group_description = "updated description" node_type = "cache.m1.small" number_cache_clusters = 2 @@ -922,7 +913,7 @@ resource "aws_elasticache_replication_group" "bar" { apply_immediately = true auto_minor_version_upgrade = true } -`, rName, rName, rName) +`, rName) } func testAccAWSElasticacheReplicationGroupConfigUpdatedMaintenanceWindow(rName string) string { @@ -932,7 +923,7 @@ provider "aws" { } resource "aws_security_group" "bar" { - name = "tf-test-security-group-%s" + name = %[1]q description = "tf-test-security-group-descr" ingress { @@ -944,13 +935,13 @@ resource "aws_security_group" "bar" { } resource "aws_elasticache_security_group" "bar" { - name = "tf-test-security-group-%s" + name = %[1]q description = "tf-test-security-group-descr" security_group_names = ["${aws_security_group.bar.name}"] } resource "aws_elasticache_replication_group" "bar" { - replication_group_id = "tf-%s" + replication_group_id = %[1]q replication_group_description = "updated description" node_type = "cache.m1.small" number_cache_clusters = 2 @@ -961,7 +952,7 @@ resource "aws_elasticache_replication_group" "bar" { maintenance_window = "wed:03:00-wed:06:00" snapshot_window = "01:00-02:00" } -`, rName, rName, rName) +`, rName) } func testAccAWSElasticacheReplicationGroupConfigUpdatedNodeSize(rName string) string { @@ -971,7 +962,7 @@ provider "aws" { } resource "aws_security_group" "bar" { - name = "tf-test-security-group-%s" + name = %[1]q description = "tf-test-security-group-descr" ingress { @@ -983,13 +974,13 @@ resource "aws_security_group" "bar" { } resource "aws_elasticache_security_group" "bar" { - name = "tf-test-security-group-%s" + name = %[1]q description = "tf-test-security-group-descr" security_group_names = ["${aws_security_group.bar.name}"] } resource "aws_elasticache_replication_group" "bar" { - replication_group_id = "tf-%s" + replication_group_id = %[1]q replication_group_description = "updated description" node_type = "cache.m1.medium" number_cache_clusters = 2 @@ -997,10 +988,16 @@ resource "aws_elasticache_replication_group" "bar" { security_group_names = ["${aws_elasticache_security_group.bar.name}"] apply_immediately = true } -`, rName, rName, rName) +`, rName) } var testAccAWSElasticacheReplicationGroupInVPCConfig = fmt.Sprintf(` +data "aws_availability_zones" "available" { + # InvalidParameterValue: Specified node type cache.m1.small is not available in AZ us-east-1b. + blacklisted_zone_ids = ["use1-az1"] + state = "available" +} + resource "aws_vpc" "foo" { cidr_block = "192.168.0.0/16" tags = { @@ -1011,7 +1008,7 @@ resource "aws_vpc" "foo" { resource "aws_subnet" "foo" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.0.0/20" - availability_zone = "us-west-2a" + availability_zone = "${data.aws_availability_zones.available.names[0]}" tags = { Name = "tf-acc-elasticache-replication-group-in-vpc" } @@ -1043,12 +1040,18 @@ resource "aws_elasticache_replication_group" "bar" { port = 6379 subnet_group_name = "${aws_elasticache_subnet_group.bar.name}" security_group_ids = ["${aws_security_group.bar.id}"] - availability_zones = ["us-west-2a"] + availability_zones = ["${data.aws_availability_zones.available.names[0]}"] auto_minor_version_upgrade = false } `, acctest.RandInt(), acctest.RandInt(), acctest.RandString(10)) var testAccAWSElasticacheReplicationGroupMultiAZInVPCConfig = fmt.Sprintf(` +data "aws_availability_zones" "available" { + # InvalidParameterValue: Specified node type cache.m1.small is not available in AZ us-east-1b. + blacklisted_zone_ids = ["use1-az1"] + state = "available" +} + resource "aws_vpc" "foo" { cidr_block = "192.168.0.0/16" tags = { @@ -1059,7 +1062,7 @@ resource "aws_vpc" "foo" { resource "aws_subnet" "foo" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.0.0/20" - availability_zone = "us-west-2a" + availability_zone = "${data.aws_availability_zones.available.names[0]}" tags = { Name = "tf-acc-elasticache-replication-group-multi-az-in-vpc-foo" } @@ -1068,7 +1071,7 @@ resource "aws_subnet" "foo" { resource "aws_subnet" "bar" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.16.0/20" - availability_zone = "us-west-2b" + availability_zone = "${data.aws_availability_zones.available.names[1]}" tags = { Name = "tf-acc-elasticache-replication-group-multi-az-in-vpc-bar" } @@ -1103,7 +1106,7 @@ resource "aws_elasticache_replication_group" "bar" { port = 6379 subnet_group_name = "${aws_elasticache_subnet_group.bar.name}" security_group_ids = ["${aws_security_group.bar.id}"] - availability_zones = ["us-west-2a","us-west-2b"] + availability_zones = ["${data.aws_availability_zones.available.names[0]}","${data.aws_availability_zones.available.names[1]}"] automatic_failover_enabled = true snapshot_window = "02:00-03:00" snapshot_retention_limit = 7 @@ -1111,6 +1114,12 @@ resource "aws_elasticache_replication_group" "bar" { `, acctest.RandInt(), acctest.RandInt(), acctest.RandString(10)) var testAccAWSElasticacheReplicationGroupRedisClusterInVPCConfig = fmt.Sprintf(` +data "aws_availability_zones" "available" { + # InvalidParameterValue: Specified node type cache.m3.medium is not available in AZ us-east-1b. + blacklisted_zone_ids = ["use1-az1"] + state = "available" +} + resource "aws_vpc" "foo" { cidr_block = "192.168.0.0/16" tags = { @@ -1121,7 +1130,7 @@ resource "aws_vpc" "foo" { resource "aws_subnet" "foo" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.0.0/20" - availability_zone = "us-west-2a" + availability_zone = "${data.aws_availability_zones.available.names[0]}" tags = { Name = "tf-acc-elasticache-replication-group-redis-cluster-in-vpc-foo" } @@ -1130,7 +1139,7 @@ resource "aws_subnet" "foo" { resource "aws_subnet" "bar" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.16.0/20" - availability_zone = "us-west-2b" + availability_zone = "${data.aws_availability_zones.available.names[1]}" tags = { Name = "tf-acc-elasticache-replication-group-redis-cluster-in-vpc-bar" } @@ -1165,7 +1174,7 @@ resource "aws_elasticache_replication_group" "bar" { port = 6379 subnet_group_name = "${aws_elasticache_subnet_group.bar.name}" security_group_ids = ["${aws_security_group.bar.id}"] - availability_zones = ["us-west-2a","us-west-2b"] + availability_zones = ["${data.aws_availability_zones.available.names[0]}","${data.aws_availability_zones.available.names[1]}"] automatic_failover_enabled = false snapshot_window = "02:00-03:00" snapshot_retention_limit = 7 @@ -1176,6 +1185,10 @@ resource "aws_elasticache_replication_group" "bar" { func testAccAWSElasticacheReplicationGroupNativeRedisClusterErrorConfig(rInt int, rName string) string { return fmt.Sprintf(` +data "aws_availability_zones" "available" { + state = "available" +} + resource "aws_vpc" "foo" { cidr_block = "192.168.0.0/16" @@ -1187,7 +1200,7 @@ resource "aws_vpc" "foo" { resource "aws_subnet" "foo" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.0.0/20" - availability_zone = "us-west-2a" + availability_zone = "${data.aws_availability_zones.available.names[0]}" tags = { Name = "tf-acc-elasticache-replication-group-native-redis-cluster-err-foo" @@ -1197,7 +1210,7 @@ resource "aws_subnet" "foo" { resource "aws_subnet" "bar" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.16.0/20" - availability_zone = "us-west-2b" + availability_zone = "${data.aws_availability_zones.available.names[1]}" tags = { Name = "tf-acc-elasticache-replication-group-native-redis-cluster-err-bar" @@ -1248,6 +1261,10 @@ resource "aws_elasticache_replication_group" "bar" { func testAccAWSElasticacheReplicationGroupNativeRedisClusterConfig(rName string, numNodeGroups, replicasPerNodeGroup int) string { return fmt.Sprintf(` +data "aws_availability_zones" "available" { + state = "available" +} + resource "aws_vpc" "foo" { cidr_block = "192.168.0.0/16" @@ -1259,7 +1276,7 @@ resource "aws_vpc" "foo" { resource "aws_subnet" "foo" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.0.0/20" - availability_zone = "us-west-2a" + availability_zone = "${data.aws_availability_zones.available.names[0]}" tags = { Name = "tf-acc-elasticache-replication-group-native-redis-cluster-foo" @@ -1269,7 +1286,7 @@ resource "aws_subnet" "foo" { resource "aws_subnet" "bar" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.16.0/20" - availability_zone = "us-west-2b" + availability_zone = "${data.aws_availability_zones.available.names[1]}" tags = { Name = "tf-acc-elasticache-replication-group-native-redis-cluster-bar" @@ -1318,6 +1335,10 @@ resource "aws_elasticache_replication_group" "bar" { func testAccAWSElasticacheReplicationGroup_EnableAtRestEncryptionConfig(rInt int, rString string) string { return fmt.Sprintf(` +data "aws_availability_zones" "available" { + state = "available" +} + resource "aws_vpc" "foo" { cidr_block = "192.168.0.0/16" @@ -1329,7 +1350,7 @@ resource "aws_vpc" "foo" { resource "aws_subnet" "foo" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.0.0/20" - availability_zone = "us-west-2a" + availability_zone = "${data.aws_availability_zones.available.names[0]}" tags = { Name = "tf-acc-elasticache-replication-group-at-rest-encryption" @@ -1367,7 +1388,7 @@ resource "aws_elasticache_replication_group" "bar" { subnet_group_name = "${aws_elasticache_subnet_group.bar.name}" security_group_ids = ["${aws_security_group.bar.id}"] parameter_group_name = "default.redis3.2" - availability_zones = ["us-west-2a"] + availability_zones = ["${data.aws_availability_zones.available.names[0]}"] engine_version = "3.2.6" at_rest_encryption_enabled = true } @@ -1376,6 +1397,10 @@ resource "aws_elasticache_replication_group" "bar" { func testAccAWSElasticacheReplicationGroup_EnableAuthTokenTransitEncryptionConfig(rInt int, rString10 string, rString16 string) string { return fmt.Sprintf(` +data "aws_availability_zones" "available" { + state = "available" +} + resource "aws_vpc" "foo" { cidr_block = "192.168.0.0/16" @@ -1387,7 +1412,7 @@ resource "aws_vpc" "foo" { resource "aws_subnet" "foo" { vpc_id = "${aws_vpc.foo.id}" cidr_block = "192.168.0.0/20" - availability_zone = "us-west-2a" + availability_zone = "${data.aws_availability_zones.available.names[0]}" tags = { Name = "tf-acc-elasticache-replication-group-auth-token-transit-encryption" @@ -1425,7 +1450,7 @@ resource "aws_elasticache_replication_group" "bar" { subnet_group_name = "${aws_elasticache_subnet_group.bar.name}" security_group_ids = ["${aws_security_group.bar.id}"] parameter_group_name = "default.redis3.2" - availability_zones = ["us-west-2a"] + availability_zones = ["${data.aws_availability_zones.available.names[0]}"] engine_version = "3.2.6" transit_encryption_enabled = true auth_token = "%s" @@ -1435,7 +1460,11 @@ resource "aws_elasticache_replication_group" "bar" { func testAccAWSElasticacheReplicationGroupConfig_NumberCacheClusters(rName string, numberCacheClusters int, autoFailover bool) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + # InvalidParameterValue: Specified node type cache.m3.medium is not available in AZ us-east-1b. + blacklisted_zone_ids = ["use1-az1"] + state = "available" +} resource "aws_vpc" "test" { cidr_block = "192.168.0.0/16" diff --git a/aws/validators.go b/aws/validators.go index 81295f77d9f..b3bfd38c775 100644 --- a/aws/validators.go +++ b/aws/validators.go @@ -40,6 +40,29 @@ func FloatAtLeast(min float64) schema.SchemaValidateFunc { } } +// validateStringNotMatch returns a SchemaValidateFunc which tests if the provided value +// does not match a given regexp. Optionally an error message can be provided to +// return something friendlier than "must match some globby regexp". +// This function is an inverse copy of validation.StringMatch and will be +// migrated to the Terraform Provider SDK. +func validateStringNotMatch(r *regexp.Regexp, message string) schema.SchemaValidateFunc { + return func(i interface{}, k string) ([]string, []error) { + v, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("expected type of %s to be string", k)} + } + + if ok := r.MatchString(v); ok { + if message != "" { + return nil, []error{fmt.Errorf("invalid value for %s (%s)", k, message)} + + } + return nil, []error{fmt.Errorf("expected value of %s to not match regular expression %q", k, r)} + } + return nil, nil + } +} + // validateTypeStringNullableBoolean provides custom error messaging for TypeString booleans // Some arguments require three values: true, false, and "" (unspecified). // This ValidateFunc returns a custom message since the message with From f6b1364793fc4306c69b9b32f3d7cda144e64430 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 30 Aug 2019 17:15:16 -0400 Subject: [PATCH 2/3] resource/aws_dax_cluster: Refactor now invalid validateElastiCacheClusterId into inline ValidateFunc Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/8424 Output from acceptance testing: ``` --- PASS: TestAccAWSDAXCluster_encryption_disabled (739.98s) --- PASS: TestAccAWSDAXCluster_basic (756.03s) --- PASS: TestAccAWSDAXCluster_importBasic (796.86s) --- PASS: TestAccAWSDAXCluster_encryption_enabled (865.80s) --- PASS: TestAccAWSDAXCluster_resize (1414.26s) ``` --- aws/resource_aws_dax_cluster.go | 11 +++++++-- aws/validators.go | 25 --------------------- aws/validators_test.go | 40 --------------------------------- 3 files changed, 9 insertions(+), 67 deletions(-) diff --git a/aws/resource_aws_dax_cluster.go b/aws/resource_aws_dax_cluster.go index 68aa1d52fc1..27553469145 100644 --- a/aws/resource_aws_dax_cluster.go +++ b/aws/resource_aws_dax_cluster.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "sort" "strings" "time" @@ -11,6 +12,7 @@ import ( "github.com/aws/aws-sdk-go/service/dax" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" ) func resourceAwsDaxCluster() *schema.Resource { @@ -41,8 +43,13 @@ func resourceAwsDaxCluster() *schema.Resource { StateFunc: func(val interface{}) string { return strings.ToLower(val.(string)) }, - // DAX follows the same naming convention as ElastiCache clusters - ValidateFunc: validateElastiCacheClusterId, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 20), + validation.StringMatch(regexp.MustCompile(`^[0-9a-z-]+$`), "must contain only lowercase alphanumeric characters and hyphens"), + validation.StringMatch(regexp.MustCompile(`^[a-z]`), "must begin with a lowercase letter"), + validateStringNotMatch(regexp.MustCompile(`--`), "cannot contain two consecutive hyphens"), + validateStringNotMatch(regexp.MustCompile(`-$`), "cannot end with a hyphen"), + ), }, "iam_role_arn": { Type: schema.TypeString, diff --git a/aws/validators.go b/aws/validators.go index b3bfd38c775..13d49358b03 100644 --- a/aws/validators.go +++ b/aws/validators.go @@ -218,31 +218,6 @@ func validateNeptuneEngine() schema.SchemaValidateFunc { }, false) } -func validateElastiCacheClusterId(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - if (len(value) < 1) || (len(value) > 20) { - errors = append(errors, fmt.Errorf( - "%q (%q) must contain from 1 to 20 alphanumeric characters or hyphens", k, value)) - } - if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { - errors = append(errors, fmt.Errorf( - "only lowercase alphanumeric characters and hyphens allowed in %q (%q)", k, value)) - } - if !regexp.MustCompile(`^[a-z]`).MatchString(value) { - errors = append(errors, fmt.Errorf( - "first character of %q (%q) must be a letter", k, value)) - } - if regexp.MustCompile(`--`).MatchString(value) { - errors = append(errors, fmt.Errorf( - "%q (%q) cannot contain two consecutive hyphens", k, value)) - } - if regexp.MustCompile(`-$`).MatchString(value) { - errors = append(errors, fmt.Errorf( - "%q (%q) cannot end with a hyphen", k, value)) - } - return -} - func validateASGScheduleTimestamp(v interface{}, k string) (ws []string, errors []error) { value := v.(string) _, err := time.Parse(awsAutoscalingScheduleTimeLayout, value) diff --git a/aws/validators_test.go b/aws/validators_test.go index cbaf8a317a5..623f684f573 100644 --- a/aws/validators_test.go +++ b/aws/validators_test.go @@ -630,46 +630,6 @@ func TestValidateSagemakerName(t *testing.T) { } } -func TestResourceAWSElastiCacheClusterIdValidation(t *testing.T) { - cases := []struct { - Value string - ErrCount int - }{ - { - Value: "tEsting", - ErrCount: 1, - }, - { - Value: "t.sting", - ErrCount: 1, - }, - { - Value: "t--sting", - ErrCount: 1, - }, - { - Value: "1testing", - ErrCount: 1, - }, - { - Value: "testing-", - ErrCount: 1, - }, - { - Value: randomString(65), - ErrCount: 1, - }, - } - - for _, tc := range cases { - _, errors := validateElastiCacheClusterId(tc.Value, "aws_elasticache_cluster_cluster_id") - - if len(errors) != tc.ErrCount { - t.Fatalf("Expected the ElastiCache Cluster cluster_id to trigger a validation error") - } - } -} - func TestValidateDbEventSubscriptionName(t *testing.T) { validNames := []string{ "valid-name", From 5d9aa87534024b8157effbbd17697613bb93296f Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 30 Aug 2019 21:05:06 -0400 Subject: [PATCH 3/3] resource/aws_elasticache_replication_group: go fmt --- aws/resource_aws_elasticache_replication_group.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_elasticache_replication_group.go b/aws/resource_aws_elasticache_replication_group.go index 2486434c9f0..ca461dbe480 100644 --- a/aws/resource_aws_elasticache_replication_group.go +++ b/aws/resource_aws_elasticache_replication_group.go @@ -158,9 +158,9 @@ func resourceAwsElasticacheReplicationGroup() *schema.Resource { Required: true, }, "replication_group_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 40), validation.StringMatch(regexp.MustCompile(`^[0-9a-zA-Z-]+$`), "must contain only alphanumeric characters and hyphens"),