Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

service/redshift: tech debt: replace existing custom validators #13019

Merged
merged 2 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 43 additions & 120 deletions aws/resource_aws_redshift_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,26 @@ func resourceAwsRedshiftCluster() *schema.Resource {
},

"database_name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validateRedshiftClusterDbName,
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.All(
validation.StringLenBetween(1, 64),
validation.StringMatch(regexp.MustCompile(`^[0-9a-z_$]+$`), "must contain only lowercase alphanumeric characters, underscores, and dollar signs"),
validation.StringMatch(regexp.MustCompile(`(?i)^[a-z_]`), "first character must be a letter or underscore"),
),
},

"cluster_identifier": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validateRedshiftClusterIdentifier,
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.All(
validation.StringMatch(regexp.MustCompile(`^[0-9a-z-]+$`), "must contain only lowercase alphanumeric characters and hyphens"),
validation.StringMatch(regexp.MustCompile(`(?i)^[a-z]`), "first character must be a letter"),
validation.StringDoesNotMatch(regexp.MustCompile(`--`), "cannot contain two consecutive hyphens"),
validation.StringDoesNotMatch(regexp.MustCompile(`-$`), "cannot end with a hyphen"),
),
},
"cluster_type": {
Type: schema.TypeString,
Expand All @@ -63,17 +72,27 @@ func resourceAwsRedshiftCluster() *schema.Resource {
},

"master_username": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validateRedshiftClusterMasterUsername,
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.All(
validation.StringLenBetween(1, 128),
validation.StringMatch(regexp.MustCompile(`^\w+$`), "must contain only alphanumeric characters"),
validation.StringMatch(regexp.MustCompile(`(?i)^[a-z_]`), "first character must be a letter"),
),
},

"master_password": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
ValidateFunc: validateRedshiftClusterMasterPassword,
Type: schema.TypeString,
Optional: true,
Sensitive: true,
ValidateFunc: validation.All(
validation.StringLenBetween(8, 64),
validation.StringMatch(regexp.MustCompile(`^.*[a-z].*`), "must contain at least one lowercase letter"),
validation.StringMatch(regexp.MustCompile(`^.*[A-Z].*`), "must contain at least one uppercase letter"),
validation.StringMatch(regexp.MustCompile(`^.*[0-9].*`), "must contain at least one number"),
validation.StringMatch(regexp.MustCompile(`^[^\@\/'" ]*$`), "cannot contain [/@\"' ]"),
),
},

"cluster_security_groups": {
Expand Down Expand Up @@ -187,9 +206,14 @@ func resourceAwsRedshiftCluster() *schema.Resource {
},

"final_snapshot_identifier": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validateRedshiftClusterFinalSnapshotIdentifier,
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.All(
validation.StringLenBetween(1, 255),
validation.StringMatch(regexp.MustCompile(`^[0-9A-Za-z-]+$`), "must only contain alphanumeric characters and hyphens"),
validation.StringDoesNotMatch(regexp.MustCompile(`--`), "cannot contain two consecutive hyphens"),
validation.StringDoesNotMatch(regexp.MustCompile(`-$`), "cannot end in a hyphen"),
),
},

"skip_final_snapshot": {
Expand Down Expand Up @@ -962,104 +986,3 @@ func resourceAwsRedshiftClusterStateRefreshFunc(id string, conn *redshift.Redshi
return rsc, *rsc.ClusterStatus, nil
}
}

func validateRedshiftClusterIdentifier(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 regexp.MustCompile(`-$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q cannot end with a hyphen", k))
}
return
}

func validateRedshiftClusterDbName(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, underscores, and dollar signs are 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 or underscore", k))
}
if len(value) > 64 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 64 characters: %q", k, value))
}
if value == "" {
errors = append(errors, fmt.Errorf(
"%q cannot be an empty string", k))
}

return
}

func validateRedshiftClusterFinalSnapshotIdentifier(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
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 in a hyphen", k))
}
if len(value) > 255 {
errors = append(errors, fmt.Errorf("%q cannot be more than 255 characters", k))
}
return
}

func validateRedshiftClusterMasterUsername(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`^\w+$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"only alphanumeric characters 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 len(value) > 128 {
errors = append(errors, fmt.Errorf("%q cannot be more than 128 characters", k))
}
return
}

func validateRedshiftClusterMasterPassword(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`^.*[a-z].*`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q must contain at least one lowercase letter", k))
}
if !regexp.MustCompile(`^.*[A-Z].*`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q must contain at least one uppercase letter", k))
}
if !regexp.MustCompile(`^.*[0-9].*`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q must contain at least one number", k))
}
if !regexp.MustCompile(`^[^\@\/'" ]*$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q cannot contain [/@\"' ]", k))
}
if len(value) < 8 {
errors = append(errors, fmt.Errorf("%q must be at least 8 characters", k))
}
return
}
176 changes: 0 additions & 176 deletions aws/resource_aws_redshift_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,42 +59,6 @@ func testSweepRedshiftClusters(region string) error {
return nil
}

func TestValidateRedshiftClusterDbName(t *testing.T) {
anGie44 marked this conversation as resolved.
Show resolved Hide resolved
validNames := []string{
"testdbname",
"test_dbname",
"testdbname123",
"testdbname$hashicorp",
"_dbname",
}
for _, v := range validNames {
_, errors := validateRedshiftClusterDbName(v, "name")
if len(errors) != 0 {
t.Fatalf("%q should be a valid Redshift DBName: %q", v, errors)
}
}

invalidNames := []string{
"!",
"/",
" ",
":",
";",
"test name",
"/slash-at-the-beginning",
"slash-at-the-end/",
"",
acctest.RandStringFromCharSet(100, acctest.CharSetAlpha),
"TestDBname",
}
for _, v := range invalidNames {
_, errors := validateRedshiftClusterDbName(v, "name")
if len(errors) == 0 {
t.Fatalf("%q should be an invalid Redshift DBName", v)
}
}
}

func TestAccAWSRedshiftCluster_basic(t *testing.T) {
var v redshift.Cluster

Expand Down Expand Up @@ -747,146 +711,6 @@ func testAccCheckAWSRedshiftClusterAvailabilityZone(c *redshift.Cluster, value s
}
}

func TestResourceAWSRedshiftClusterIdentifierValidation(t *testing.T) {
cases := []struct {
Value string
ErrCount int
}{
{
Value: "tEsting",
ErrCount: 1,
},
{
Value: "1testing",
ErrCount: 1,
},
{
Value: "testing--123",
ErrCount: 1,
},
{
Value: "testing!",
ErrCount: 1,
},
{
Value: "testing-",
ErrCount: 1,
},
}

for _, tc := range cases {
_, errors := validateRedshiftClusterIdentifier(tc.Value, "aws_redshift_cluster_identifier")

if len(errors) != tc.ErrCount {
t.Fatalf("Expected the Redshift Cluster cluster_identifier to trigger a validation error")
}
}
}

func TestResourceAWSRedshiftClusterFinalSnapshotIdentifierValidation(t *testing.T) {
cases := []struct {
Value string
ErrCount int
}{
{
Value: "testing--123",
ErrCount: 1,
},
{
Value: "testing-",
ErrCount: 1,
},
{
Value: "Testingq123!",
ErrCount: 1,
},
{
Value: acctest.RandStringFromCharSet(256, acctest.CharSetAlpha),
ErrCount: 1,
},
}

for _, tc := range cases {
_, errors := validateRedshiftClusterFinalSnapshotIdentifier(tc.Value, "aws_redshift_cluster_final_snapshot_identifier")

if len(errors) != tc.ErrCount {
t.Fatalf("Expected the Redshift Cluster final_snapshot_identifier to trigger a validation error")
}
}
}

func TestResourceAWSRedshiftClusterMasterUsernameValidation(t *testing.T) {
cases := []struct {
Value string
ErrCount int
}{
{
Value: "1Testing",
ErrCount: 1,
},
{
Value: "Testing!!",
ErrCount: 1,
},
{
Value: acctest.RandStringFromCharSet(129, acctest.CharSetAlpha),
ErrCount: 1,
},
{
Value: "testing_testing123",
ErrCount: 0,
},
}

for _, tc := range cases {
_, errors := validateRedshiftClusterMasterUsername(tc.Value, "aws_redshift_cluster_master_username")

if len(errors) != tc.ErrCount {
t.Fatalf("Expected the Redshift Cluster master_username to trigger a validation error")
}
}
}

func TestResourceAWSRedshiftClusterMasterPasswordValidation(t *testing.T) {
cases := []struct {
Value string
ErrCount int
}{
{
Value: "1TESTING",
ErrCount: 1,
},
{
Value: "1testing",
ErrCount: 1,
},
{
Value: "TestTest",
ErrCount: 1,
},
{
Value: "T3st",
ErrCount: 1,
},
{
Value: "1Testing",
ErrCount: 0,
},
{
Value: "1Testing@",
ErrCount: 1,
},
}

for _, tc := range cases {
_, errors := validateRedshiftClusterMasterPassword(tc.Value, "aws_redshift_cluster_master_password")

if len(errors) != tc.ErrCount {
t.Fatalf("Expected the Redshift Cluster master_password to trigger a validation error")
}
}
}

func testAccCheckAWSRedshiftClusterNotRecreated(i, j *redshift.Cluster) resource.TestCheckFunc {
return func(s *terraform.State) error {
// In lieu of some other uniquely identifying attribute from the API that always changes
Expand Down
Loading