diff --git a/builtin/providers/aws/resource_aws_autoscaling_schedule.go b/builtin/providers/aws/resource_aws_autoscaling_schedule.go index b8a1135deee0..f6e3745d1739 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_schedule.go +++ b/builtin/providers/aws/resource_aws_autoscaling_schedule.go @@ -176,14 +176,3 @@ func resourceAwsASGScheduledActionRetrieve(d *schema.ResourceData, meta interfac return actions.ScheduledUpdateGroupActions[0], nil } - -func validateASGScheduleTimestamp(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - _, err := time.Parse(awsAutoscalingScheduleTimeLayout, value) - if err != nil { - errors = append(errors, fmt.Errorf( - "%q cannot be parsed as iso8601 Timestamp Format", value)) - } - - return -} diff --git a/builtin/providers/aws/resource_aws_codedeploy_deployment_group.go b/builtin/providers/aws/resource_aws_codedeploy_deployment_group.go index ee81f1cf3cab..457368aed8af 100644 --- a/builtin/providers/aws/resource_aws_codedeploy_deployment_group.go +++ b/builtin/providers/aws/resource_aws_codedeploy_deployment_group.go @@ -344,17 +344,6 @@ func onPremisesTagFiltersToMap(list []*codedeploy.TagFilter) []map[string]string return result } -// validateTagFilters confirms the "value" component of a tag filter is one of -// AWS's three allowed types. -func validateTagFilters(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - if value != "KEY_ONLY" && value != "VALUE_ONLY" && value != "KEY_AND_VALUE" { - errors = append(errors, fmt.Errorf( - "%q must be one of \"KEY_ONLY\", \"VALUE_ONLY\", or \"KEY_AND_VALUE\"", k)) - } - return -} - func resourceAwsCodeDeployTagFilterHash(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) diff --git a/builtin/providers/aws/resource_aws_db_parameter_group.go b/builtin/providers/aws/resource_aws_db_parameter_group.go index 0513be0b54cf..7204c82826a9 100644 --- a/builtin/providers/aws/resource_aws_db_parameter_group.go +++ b/builtin/providers/aws/resource_aws_db_parameter_group.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "log" - "regexp" "strings" "time" @@ -285,29 +284,3 @@ func buildRDSPGARN(d *schema.ResourceData, meta interface{}) (string, error) { arn := fmt.Sprintf("arn:aws:rds:%s:%s:pg:%s", region, accountID, d.Id()) return arn, nil } - -func validateDbParamGroupName(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)) - } - if len(value) > 255 { - errors = append(errors, fmt.Errorf( - "%q cannot be greater than 255 characters", k)) - } - return - -} diff --git a/builtin/providers/aws/resource_aws_dynamodb_table.go b/builtin/providers/aws/resource_aws_dynamodb_table.go index 0606cde2e828..8f1ac41c5a23 100644 --- a/builtin/providers/aws/resource_aws_dynamodb_table.go +++ b/builtin/providers/aws/resource_aws_dynamodb_table.go @@ -801,18 +801,3 @@ func waitForTableToBeActive(tableName string, meta interface{}) error { return nil } - -func validateStreamViewType(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - viewTypes := map[string]bool{ - "KEYS_ONLY": true, - "NEW_IMAGE": true, - "OLD_IMAGE": true, - "NEW_AND_OLD_IMAGES": true, - } - - if !viewTypes[value] { - errors = append(errors, fmt.Errorf("%q be a valid DynamoDB StreamViewType", k)) - } - return -} diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index 1bc6ddc2838c..23042aa5bd31 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "log" - "regexp" "strings" "time" @@ -673,29 +672,6 @@ func isLoadBalancerNotFound(err error) bool { return ok && elberr.Code() == "LoadBalancerNotFound" } -func validateElbName(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: %q", - k, value)) - } - if len(value) > 32 { - errors = append(errors, fmt.Errorf( - "%q cannot be longer than 32 characters: %q", k, value)) - } - if regexp.MustCompile(`^-`).MatchString(value) { - errors = append(errors, fmt.Errorf( - "%q cannot begin with a hyphen: %q", k, value)) - } - if regexp.MustCompile(`-$`).MatchString(value) { - errors = append(errors, fmt.Errorf( - "%q cannot end with a hyphen: %q", k, value)) - } - return - -} - func sourceSGIdByName(meta interface{}, sg, vpcId string) (string, error) { conn := meta.(*AWSClient).ec2conn var filters []*ec2.Filter diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index 748ecc88be8d..35b7ba4e11cc 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - "regexp" "sort" "strings" @@ -516,27 +515,6 @@ func expandResourceRecords(recs []interface{}, typeStr string) []*route53.Resour return records } -func validateRdsId(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 expandESClusterConfig(m map[string]interface{}) *elasticsearch.ElasticsearchClusterConfig { config := elasticsearch.ElasticsearchClusterConfig{} diff --git a/builtin/providers/aws/validators.go b/builtin/providers/aws/validators.go new file mode 100644 index 000000000000..ede6b36dd78d --- /dev/null +++ b/builtin/providers/aws/validators.go @@ -0,0 +1,136 @@ +package aws + +import ( + "fmt" + "regexp" + "time" +) + +func validateRdsId(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 validateASGScheduleTimestamp(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + _, err := time.Parse(awsAutoscalingScheduleTimeLayout, value) + if err != nil { + errors = append(errors, fmt.Errorf( + "%q cannot be parsed as iso8601 Timestamp Format", value)) + } + + return +} + +// validateTagFilters confirms the "value" component of a tag filter is one of +// AWS's three allowed types. +func validateTagFilters(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + if value != "KEY_ONLY" && value != "VALUE_ONLY" && value != "KEY_AND_VALUE" { + errors = append(errors, fmt.Errorf( + "%q must be one of \"KEY_ONLY\", \"VALUE_ONLY\", or \"KEY_AND_VALUE\"", k)) + } + return +} + +func validateDbParamGroupName(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)) + } + if len(value) > 255 { + errors = append(errors, fmt.Errorf( + "%q cannot be greater than 255 characters", k)) + } + return + +} + +func validateStreamViewType(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + viewTypes := map[string]bool{ + "KEYS_ONLY": true, + "NEW_IMAGE": true, + "OLD_IMAGE": true, + "NEW_AND_OLD_IMAGES": true, + } + + if !viewTypes[value] { + errors = append(errors, fmt.Errorf("%q be a valid DynamoDB StreamViewType", k)) + } + return +} + +func validateElbName(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: %q", + k, value)) + } + if len(value) > 32 { + errors = append(errors, fmt.Errorf( + "%q cannot be longer than 32 characters: %q", k, value)) + } + if regexp.MustCompile(`^-`).MatchString(value) { + errors = append(errors, fmt.Errorf( + "%q cannot begin with a hyphen: %q", k, value)) + } + if regexp.MustCompile(`-$`).MatchString(value) { + errors = append(errors, fmt.Errorf( + "%q cannot end with a hyphen: %q", k, value)) + } + return + +} + +func validateEcrRepositoryName(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + if len(value) < 2 { + errors = append(errors, fmt.Errorf( + "%q must be at least 2 characters long: %q", k, value)) + } + if len(value) > 256 { + errors = append(errors, fmt.Errorf( + "%q cannot be longer than 256 characters: %q", k, value)) + } + + // http://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_CreateRepository.html + pattern := `^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)*[a-z0-9]+(?:[._-][a-z0-9]+)*$` + if !regexp.MustCompile(pattern).MatchString(value) { + errors = append(errors, fmt.Errorf( + "%q doesn't comply with restrictions (%q): %q", + k, pattern, value)) + } + + return +} diff --git a/builtin/providers/aws/validators_test.go b/builtin/providers/aws/validators_test.go new file mode 100644 index 000000000000..0b2ee011ea49 --- /dev/null +++ b/builtin/providers/aws/validators_test.go @@ -0,0 +1,45 @@ +package aws + +import ( + "testing" +) + +func TestValidateEcrRepositoryName(t *testing.T) { + validNames := []string{ + "nginx-web-app", + "project-a/nginx-web-app", + "domain.ltd/nginx-web-app", + "3chosome-thing.com/01different-pattern", + "0123456789/999999999", + "double/forward/slash", + "000000000000000", + } + for _, v := range validNames { + _, errors := validateEcrRepositoryName(v, "name") + if len(errors) != 0 { + t.Fatalf("%q should be a valid ECR repository name: %q", v, errors) + } + } + + invalidNames := []string{ + // length > 256 + "3cho_some-thing.com/01different.-_pattern01different.-_pattern01diff" + + "erent.-_pattern01different.-_pattern01different.-_pattern01different" + + ".-_pattern01different.-_pattern01different.-_pattern01different.-_pa" + + "ttern01different.-_pattern01different.-_pattern234567", + // length < 2 + "i", + "special@character", + "different+special=character", + "double//slash", + "double..dot", + "/slash-at-the-beginning", + "slash-at-the-end/", + } + for _, v := range invalidNames { + _, errors := validateEcrRepositoryName(v, "name") + if len(errors) == 0 { + t.Fatalf("%q should be an invalid ECR repository name", v) + } + } +}