terraform/builtin/providers/aws/validators.go

1353 lines
41 KiB
Go
Raw Normal View History

package aws
import (
"fmt"
"net"
"net/url"
"regexp"
"strings"
"time"
"github.com/aws/aws-sdk-go/service/apigateway"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/hashicorp/terraform/helper/schema"
)
func validateRdsIdentifier(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 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) {
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)
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 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) {
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 must be a valid DynamoDB StreamViewType", k))
}
return
}
func validateElbName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
2017-05-09 08:06:59 +02:00
if len(value) == 0 {
return // short-circuit
}
if len(value) > 32 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 32 characters: %q", k, value))
}
2017-05-09 08:06:59 +02:00
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 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 validateElbNamePrefix(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) > 6 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 6 characters: %q", k, value))
}
if regexp.MustCompile(`^-`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q cannot begin 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
}
func validateCloudWatchEventRuleName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 64 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 64 characters: %q", k, value))
}
// http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_PutRule.html
pattern := `^[\.\-_A-Za-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
}
func validateMaxLength(length int) schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > length {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than %d characters: %q", k, length, value))
}
return
}
}
func validateIntegerInRange(min, max int) schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
value := v.(int)
if value < min {
errors = append(errors, fmt.Errorf(
"%q cannot be lower than %d: %d", k, min, value))
}
if value > max {
errors = append(errors, fmt.Errorf(
"%q cannot be higher than %d: %d", k, max, value))
}
return
}
}
func validateCloudWatchEventTargetId(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 64 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 64 characters: %q", k, value))
}
// http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_Target.html
pattern := `^[\.\-_A-Za-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
}
func validateLambdaFunctionName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 140 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 140 characters: %q", k, value))
}
// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
pattern := `^(arn:[\w-]+:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-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
}
func validateLambdaQualifier(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 128 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 128 characters: %q", k, value))
}
// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
pattern := `^[a-zA-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
}
func validateLambdaPermissionAction(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
pattern := `^(lambda:[*]|lambda:[a-zA-Z]+|[*])$`
if !regexp.MustCompile(pattern).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q doesn't comply with restrictions (%q): %q",
k, pattern, value))
}
return
}
func validateAwsAccountId(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
pattern := `^\d{12}$`
if !regexp.MustCompile(pattern).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q doesn't look like AWS Account ID (exactly 12 digits): %q",
k, value))
}
return
}
func validateArn(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if value == "" {
return
}
// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
pattern := `^arn:[\w-]+:([a-zA-Z0-9\-])+:([a-z]{2}-(gov-)?[a-z]+-\d{1})?:(\d{12})?:(.*)$`
if !regexp.MustCompile(pattern).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q doesn't look like a valid ARN (%q): %q",
k, pattern, value))
}
return
}
func validatePolicyStatementId(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 100 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 100 characters: %q", k, value))
}
// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
pattern := `^[a-zA-Z0-9-_]+$`
if !regexp.MustCompile(pattern).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q doesn't look like a valid statement ID (%q): %q",
k, pattern, value))
}
return
}
// validateCIDRNetworkAddress ensures that the string value is a valid CIDR that
// represents a network address - it adds an error otherwise
func validateCIDRNetworkAddress(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
_, ipnet, err := net.ParseCIDR(value)
if err != nil {
errors = append(errors, fmt.Errorf(
"%q must contain a valid CIDR, got error parsing: %s", k, err))
return
}
if ipnet == nil || value != ipnet.String() {
errors = append(errors, fmt.Errorf(
"%q must contain a valid network CIDR, expected %q, got %q",
k, ipnet, value))
}
return
}
2016-03-05 23:15:22 +01:00
func validateHTTPMethod(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
validMethods := map[string]bool{
"ANY": true,
"DELETE": true,
"GET": true,
"HEAD": true,
"OPTIONS": true,
"PATCH": true,
"POST": true,
"PUT": true,
}
if _, ok := validMethods[value]; !ok {
2016-03-05 23:15:22 +01:00
errors = append(errors, fmt.Errorf(
"%q contains an invalid method %q. Valid methods are either %q, %q, %q, %q, %q, %q, %q, or %q.",
k, value, "ANY", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"))
2016-03-05 23:15:22 +01:00
}
return
}
func validateLogMetricFilterName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 512 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 512 characters: %q", k, value))
}
// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutMetricFilter.html
pattern := `^[^:*]+$`
if !regexp.MustCompile(pattern).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q isn't a valid log metric name (must not contain colon nor asterisk): %q",
k, value))
}
return
}
func validateLogMetricFilterTransformationName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 255 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 255 characters: %q", k, value))
}
// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_MetricTransformation.html
pattern := `^[^:*$]*$`
if !regexp.MustCompile(pattern).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q isn't a valid log metric transformation name (must not contain"+
" colon, asterisk nor dollar sign): %q",
k, value))
}
return
}
func validateLogGroupName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 512 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 512 characters: %q", k, value))
}
// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html
pattern := `^[\.\-_/#A-Za-z0-9]+$`
if !regexp.MustCompile(pattern).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q isn't a valid log group name (alphanumeric characters, underscores,"+
" hyphens, slashes, hash signs and dots are allowed): %q",
k, value))
}
return
}
func validateLogGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 483 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 483 characters: %q", k, value))
}
// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html
pattern := `^[\.\-_/#A-Za-z0-9]+$`
if !regexp.MustCompile(pattern).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q isn't a valid log group name (alphanumeric characters, underscores,"+
" hyphens, slashes, hash signs and dots are allowed): %q",
k, value))
}
return
}
func validateS3BucketLifecycleTimestamp(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
_, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", value))
if err != nil {
errors = append(errors, fmt.Errorf(
"%q cannot be parsed as RFC3339 Timestamp Format", value))
}
return
}
func validateS3BucketLifecycleStorageClass(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if value != s3.TransitionStorageClassStandardIa && value != s3.TransitionStorageClassGlacier {
errors = append(errors, fmt.Errorf(
"%q must be one of '%q', '%q'", k, s3.TransitionStorageClassStandardIa, s3.TransitionStorageClassGlacier))
}
return
}
func validateS3BucketReplicationRuleId(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 255 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 255 characters: %q", k, value))
}
return
}
func validateS3BucketReplicationRulePrefix(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 1024 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 1024 characters: %q", k, value))
}
return
}
func validateS3BucketReplicationDestinationStorageClass(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if value != s3.StorageClassStandard && value != s3.StorageClassStandardIa && value != s3.StorageClassReducedRedundancy {
errors = append(errors, fmt.Errorf(
"%q must be one of '%q', '%q' or '%q'", k, s3.StorageClassStandard, s3.StorageClassStandardIa, s3.StorageClassReducedRedundancy))
}
return
}
func validateS3BucketReplicationRuleStatus(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if value != s3.ReplicationRuleStatusEnabled && value != s3.ReplicationRuleStatusDisabled {
errors = append(errors, fmt.Errorf(
"%q must be one of '%q' or '%q'", k, s3.ReplicationRuleStatusEnabled, s3.ReplicationRuleStatusDisabled))
}
return
}
func validateS3BucketLifecycleRuleId(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 255 {
errors = append(errors, fmt.Errorf(
"%q cannot exceed 255 characters", k))
}
return
}
2016-05-05 12:14:25 +02:00
func validateDbEventSubscriptionName(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 len(value) > 255 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 255 characters", k))
}
return
}
func validateApiGatewayIntegrationPassthroughBehavior(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if value != "WHEN_NO_MATCH" && value != "WHEN_NO_TEMPLATES" && value != "NEVER" {
errors = append(errors, fmt.Errorf(
"%q must be one of 'WHEN_NO_MATCH', 'WHEN_NO_TEMPLATES', 'NEVER'", k))
}
return
}
func validateJsonString(v interface{}, k string) (ws []string, errors []error) {
if _, err := normalizeJsonString(v); err != nil {
errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
}
return
}
2016-10-04 18:51:18 +02:00
provider/aws: validation: Add validation function for IAM Policies The previous JSON validator that we were using for IAM policy documents wouldn't catch AWS IAM Policy errors. The supplied policy document would pass our validator, then fail with the following API error: ``` * aws_iam_role_policy.foo: Error putting IAM role policy tf_test_policy_ymw7hbil9w: MalformedPolicyDocument: The policy failed legacy parsing status code: 400, request id: e7615d90-3c99-11e7-babc-c14e741605bf ``` This happens if the Policy Document doesn't start with the opening JSON bracket, and often happens in the following case: ``` policy = <<EOF { "Version": "2012-10-17", "Statement": [ { ... } ] } EOF ``` Where, when using a HEREDOC, the policy document is indented incorrectly. The new validation function for the IAM policies verifies that the first character of the supplied policy document is the leading JSON bracket, prior to validating the JSON string. Test Output: ``` $ make test TEST=./builtin/providers/aws/ TESTARGS="-v -run=TestValidateIAMPolicyJsonString" ==> Checking that code complies with gofmt requirements... ==> Checking AWS provider for unchecked errors... ==> NOTE: at this time we only look for uncheck errors in the AWS package go generate $(go list ./... | grep -v /terraform/vendor/) 2017/05/19 10:56:32 Generated command/internal_plugin_list.go go test -i ./builtin/providers/aws/ || exit 1 echo ./builtin/providers/aws/ | \ xargs -t -n4 go test -v -run=TestValidateIAMPolicyJsonString -timeout=60s -parallel=4 go test -v -run=TestValidateIAMPolicyJsonString -timeout=60s -parallel=4 ./builtin/providers/aws/ === RUN TestValidateIAMPolicyJsonString --- PASS: TestValidateIAMPolicyJsonString (0.00s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 0.009s ``` ``` $ make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAWSPolicy_' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2017/05/19 10:38:43 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAWSPolicy_ -timeout 120m === RUN TestAWSPolicy_namePrefix --- PASS: TestAWSPolicy_namePrefix (20.01s) === RUN TestAWSPolicy_invalidJson --- PASS: TestAWSPolicy_invalidJson (0.00s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 20.027s ``` ``` $ make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSIAMRolePolicy_' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2017/05/19 11:02:56 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSIAMRolePolicy_ -timeout 120m === RUN TestAccAWSIAMRolePolicy_importBasic --- PASS: TestAccAWSIAMRolePolicy_importBasic (18.45s) === RUN TestAccAWSIAMRolePolicy_basic --- PASS: TestAccAWSIAMRolePolicy_basic (35.92s) === RUN TestAccAWSIAMRolePolicy_namePrefix --- PASS: TestAccAWSIAMRolePolicy_namePrefix (14.78s) === RUN TestAccAWSIAMRolePolicy_generatedName --- PASS: TestAccAWSIAMRolePolicy_generatedName (20.20s) === RUN TestAccAWSIAMRolePolicy_invalidJSON --- PASS: TestAccAWSIAMRolePolicy_invalidJSON (0.00s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 89.363s ```
2017-05-19 17:11:44 +02:00
func validateIAMPolicyJson(v interface{}, k string) (ws []string, errors []error) {
// IAM Policy documents need to be valid JSON, and pass legacy parsing
value := v.(string)
if len(value) < 1 {
errors = append(errors, fmt.Errorf("%q contains an invalid JSON policy", k))
return
}
if value[:1] != "{" {
errors = append(errors, fmt.Errorf("%q contains an invalid JSON policy", k))
provider/aws: validation: Add validation function for IAM Policies The previous JSON validator that we were using for IAM policy documents wouldn't catch AWS IAM Policy errors. The supplied policy document would pass our validator, then fail with the following API error: ``` * aws_iam_role_policy.foo: Error putting IAM role policy tf_test_policy_ymw7hbil9w: MalformedPolicyDocument: The policy failed legacy parsing status code: 400, request id: e7615d90-3c99-11e7-babc-c14e741605bf ``` This happens if the Policy Document doesn't start with the opening JSON bracket, and often happens in the following case: ``` policy = <<EOF { "Version": "2012-10-17", "Statement": [ { ... } ] } EOF ``` Where, when using a HEREDOC, the policy document is indented incorrectly. The new validation function for the IAM policies verifies that the first character of the supplied policy document is the leading JSON bracket, prior to validating the JSON string. Test Output: ``` $ make test TEST=./builtin/providers/aws/ TESTARGS="-v -run=TestValidateIAMPolicyJsonString" ==> Checking that code complies with gofmt requirements... ==> Checking AWS provider for unchecked errors... ==> NOTE: at this time we only look for uncheck errors in the AWS package go generate $(go list ./... | grep -v /terraform/vendor/) 2017/05/19 10:56:32 Generated command/internal_plugin_list.go go test -i ./builtin/providers/aws/ || exit 1 echo ./builtin/providers/aws/ | \ xargs -t -n4 go test -v -run=TestValidateIAMPolicyJsonString -timeout=60s -parallel=4 go test -v -run=TestValidateIAMPolicyJsonString -timeout=60s -parallel=4 ./builtin/providers/aws/ === RUN TestValidateIAMPolicyJsonString --- PASS: TestValidateIAMPolicyJsonString (0.00s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 0.009s ``` ``` $ make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAWSPolicy_' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2017/05/19 10:38:43 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAWSPolicy_ -timeout 120m === RUN TestAWSPolicy_namePrefix --- PASS: TestAWSPolicy_namePrefix (20.01s) === RUN TestAWSPolicy_invalidJson --- PASS: TestAWSPolicy_invalidJson (0.00s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 20.027s ``` ``` $ make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSIAMRolePolicy_' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2017/05/19 11:02:56 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSIAMRolePolicy_ -timeout 120m === RUN TestAccAWSIAMRolePolicy_importBasic --- PASS: TestAccAWSIAMRolePolicy_importBasic (18.45s) === RUN TestAccAWSIAMRolePolicy_basic --- PASS: TestAccAWSIAMRolePolicy_basic (35.92s) === RUN TestAccAWSIAMRolePolicy_namePrefix --- PASS: TestAccAWSIAMRolePolicy_namePrefix (14.78s) === RUN TestAccAWSIAMRolePolicy_generatedName --- PASS: TestAccAWSIAMRolePolicy_generatedName (20.20s) === RUN TestAccAWSIAMRolePolicy_invalidJSON --- PASS: TestAccAWSIAMRolePolicy_invalidJSON (0.00s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 89.363s ```
2017-05-19 17:11:44 +02:00
return
}
if _, err := normalizeJsonString(v); err != nil {
errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
}
return
}
func validateCloudFormationTemplate(v interface{}, k string) (ws []string, errors []error) {
if looksLikeJsonString(v) {
if _, err := normalizeJsonString(v); err != nil {
errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
}
} else {
if _, err := checkYamlString(v); err != nil {
errors = append(errors, fmt.Errorf("%q contains an invalid YAML: %s", k, err))
}
}
return
}
2016-10-04 18:51:18 +02:00
func validateApiGatewayIntegrationType(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
validTypes := map[string]bool{
"AWS": true,
"AWS_PROXY": true,
"HTTP": true,
"HTTP_PROXY": true,
"MOCK": true,
}
if _, ok := validTypes[value]; !ok {
2016-10-04 18:51:18 +02:00
errors = append(errors, fmt.Errorf(
"%q contains an invalid integration type %q. Valid types are either %q, %q, %q, %q, or %q.",
k, value, "AWS", "AWS_PROXY", "HTTP", "HTTP_PROXY", "MOCK"))
2016-10-04 18:51:18 +02:00
}
return
}
func validateApiGatewayIntegrationContentHandling(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
validTypes := map[string]bool{
"CONVERT_TO_BINARY": true,
"CONVERT_TO_TEXT": true,
}
if _, ok := validTypes[value]; !ok {
errors = append(errors, fmt.Errorf(
"%q contains an invalid integration type %q. Valid types are either %q or %q.",
k, value, "CONVERT_TO_BINARY", "CONVERT_TO_TEXT"))
}
return
}
func validateSQSQueueName(v interface{}, k string) (errors []error) {
value := v.(string)
if len(value) > 80 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
}
if !regexp.MustCompile(`^[0-9A-Za-z-_]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k))
}
return
}
func validateSQSFifoQueueName(v interface{}, k string) (errors []error) {
value := v.(string)
if len(value) > 80 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", 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-Z0-9-_]`).MatchString(value) {
errors = append(errors, fmt.Errorf("FIFO queue name must start with one of these characters [a-zA-Z0-9-_]: %v", value))
}
if !regexp.MustCompile(`\.fifo$`).MatchString(value) {
errors = append(errors, fmt.Errorf("FIFO queue name should ends with \".fifo\": %v", value))
}
return
}
func validateSNSSubscriptionProtocol(v interface{}, k string) (ws []string, errors []error) {
value := strings.ToLower(v.(string))
forbidden := []string{"email", "sms"}
for _, f := range forbidden {
if strings.Contains(value, f) {
errors = append(
errors,
fmt.Errorf("Unsupported protocol (%s) for SNS Topic", value),
)
}
}
return
}
func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) {
value := strings.ToLower(v.(string))
validTypes := map[string]bool{
"ingress": true,
"egress": true,
}
if _, ok := validTypes[value]; !ok {
errors = append(errors, fmt.Errorf(
"%q contains an invalid Security Group Rule type %q. Valid types are either %q or %q.",
k, value, "ingress", "egress"))
}
return
}
func validateOnceAWeekWindowFormat(v interface{}, k string) (ws []string, errors []error) {
// valid time format is "ddd:hh24:mi"
validTimeFormat := "(sun|mon|tue|wed|thu|fri|sat):([0-1][0-9]|2[0-3]):([0-5][0-9])"
validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$"
value := strings.ToLower(v.(string))
if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q must satisfy the format of \"ddd:hh24:mi-ddd:hh24:mi\".", k))
}
return
}
func validateOnceADayWindowFormat(v interface{}, k string) (ws []string, errors []error) {
// valid time format is "hh24:mi"
validTimeFormat := "([0-1][0-9]|2[0-3]):([0-5][0-9])"
validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$"
value := v.(string)
if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q must satisfy the format of \"hh24:mi-hh24:mi\".", k))
}
return
}
func validateRoute53RecordType(v interface{}, k string) (ws []string, errors []error) {
// Valid Record types
// SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA
validTypes := map[string]struct{}{
"SOA": {},
"A": {},
"TXT": {},
"NS": {},
"CNAME": {},
"MX": {},
"NAPTR": {},
"PTR": {},
"SRV": {},
"SPF": {},
"AAAA": {},
}
value := v.(string)
if _, ok := validTypes[value]; !ok {
errors = append(errors, fmt.Errorf(
"%q must be one of [SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA]", k))
}
return
}
// Validates that ECS Placement Constraints are set correctly
// Takes type, and expression as strings
func validateAwsEcsPlacementConstraint(constType, constExpr string) error {
switch constType {
case "distinctInstance":
// Expression can be nil for distinctInstance
return nil
case "memberOf":
if constExpr == "" {
return fmt.Errorf("Expression cannot be nil for 'memberOf' type")
}
default:
return fmt.Errorf("Unknown type provided: %q", constType)
}
return nil
}
// Validates that an Ecs placement strategy is set correctly
// Takes type, and field as strings
func validateAwsEcsPlacementStrategy(stratType, stratField string) error {
switch stratType {
case "random":
// random does not need the field attribute set, could error, but it isn't read at the API level
return nil
case "spread":
// For the spread placement strategy, valid values are instanceId
// (or host, which has the same effect), or any platform or custom attribute
// that is applied to a container instance
// stratField is already cased to a string
return nil
case "binpack":
if stratField != "cpu" && stratField != "memory" {
return fmt.Errorf("Binpack type requires the field attribute to be either 'cpu' or 'memory'. Got: %s",
stratField)
}
default:
return fmt.Errorf("Unknown type %s. Must be one of 'random', 'spread', or 'binpack'.", stratType)
}
return nil
}
func validateAwsEmrEbsVolumeType(v interface{}, k string) (ws []string, errors []error) {
validTypes := map[string]struct{}{
"gp2": {},
"io1": {},
"standard": {},
}
value := v.(string)
if _, ok := validTypes[value]; !ok {
errors = append(errors, fmt.Errorf(
"%q must be one of ['gp2', 'io1', 'standard']", k))
}
return
}
func validateSfnActivityName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 80 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
}
return
}
func validateSfnStateMachineDefinition(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 1048576 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 1048576 characters", k))
}
return
}
func validateSfnStateMachineName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 80 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
}
if !regexp.MustCompile(`^[a-zA-Z0-9-_]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q must be composed with only these characters [a-zA-Z0-9-_]: %v", k, value))
}
return
}
func validateDmsCertificateId(v interface{}, k string) (ws []string, es []error) {
val := v.(string)
if len(val) > 255 {
es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
}
if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
}
if strings.Contains(val, "--") {
es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
}
if strings.HasSuffix(val, "-") {
es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
}
return
}
func validateDmsEndpointId(v interface{}, k string) (ws []string, es []error) {
val := v.(string)
if len(val) > 255 {
es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
}
if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
}
if strings.Contains(val, "--") {
es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
}
if strings.HasSuffix(val, "-") {
es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
}
return
}
func validateDmsReplicationInstanceId(v interface{}, k string) (ws []string, es []error) {
val := v.(string)
if len(val) > 63 {
es = append(es, fmt.Errorf("%q must not be longer than 63 characters", k))
}
if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
}
if strings.Contains(val, "--") {
es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
}
if strings.HasSuffix(val, "-") {
es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
}
return
}
func validateDmsReplicationSubnetGroupId(v interface{}, k string) (ws []string, es []error) {
val := v.(string)
if val == "default" {
es = append(es, fmt.Errorf("%q must not be default", k))
}
if len(val) > 255 {
es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
}
if !regexp.MustCompile(`^[a-zA-Z0-9. _-]+$`).MatchString(val) {
es = append(es, fmt.Errorf("%q must only contain alphanumeric characters, periods, spaces, underscores and hyphens", k))
}
return
}
func validateDmsReplicationTaskId(v interface{}, k string) (ws []string, es []error) {
val := v.(string)
if len(val) > 255 {
es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
}
if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
}
if strings.Contains(val, "--") {
es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
}
if strings.HasSuffix(val, "-") {
es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
}
return
}
func validateAppautoscalingScalableDimension(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
dimensions := map[string]bool{
"ecs:service:DesiredCount": true,
"ec2:spot-fleet-request:TargetCapacity": true,
"elasticmapreduce:instancegroup:InstanceCount": true,
}
if !dimensions[value] {
errors = append(errors, fmt.Errorf("%q must be a valid scalable dimension value: %q", k, value))
}
return
}
func validateAppautoscalingServiceNamespace(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
namespaces := map[string]bool{
"ecs": true,
"ec2": true,
"elasticmapreduce": true,
}
if !namespaces[value] {
errors = append(errors, fmt.Errorf("%q must be a valid service namespace value: %q", k, value))
}
return
}
func validateConfigRuleSourceOwner(v interface{}, k string) (ws []string, errors []error) {
validOwners := []string{
"CUSTOM_LAMBDA",
"AWS",
}
owner := v.(string)
for _, o := range validOwners {
if owner == o {
return
}
}
errors = append(errors, fmt.Errorf(
"%q contains an invalid owner %q. Valid owners are %q.",
k, owner, validOwners))
return
}
func validateConfigExecutionFrequency(v interface{}, k string) (ws []string, errors []error) {
validFrequencies := []string{
"One_Hour",
"Three_Hours",
"Six_Hours",
"Twelve_Hours",
"TwentyFour_Hours",
}
frequency := v.(string)
for _, f := range validFrequencies {
if frequency == f {
return
}
}
errors = append(errors, fmt.Errorf(
"%q contains an invalid frequency %q. Valid frequencies are %q.",
k, frequency, validFrequencies))
return
}
func validateAccountAlias(v interface{}, k string) (ws []string, es []error) {
val := v.(string)
if (len(val) < 3) || (len(val) > 63) {
es = append(es, fmt.Errorf("%q must contain from 3 to 63 alphanumeric characters or hyphens", k))
}
if !regexp.MustCompile("^[a-z0-9][a-z0-9-]+$").MatchString(val) {
es = append(es, fmt.Errorf("%q must start with an alphanumeric character and only contain lowercase alphanumeric characters and hyphens", k))
}
if strings.Contains(val, "--") {
es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
}
if strings.HasSuffix(val, "-") {
es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
}
return
}
func validateApiGatewayApiKeyValue(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) < 30 {
errors = append(errors, fmt.Errorf(
"%q must be at least 30 characters long", k))
}
if len(value) > 128 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 128 characters", k))
}
return
}
func validateIamRolePolicyName(v interface{}, k string) (ws []string, errors []error) {
// https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8291-L8296
value := v.(string)
if len(value) > 128 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 128 characters", k))
}
if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k))
}
return
}
func validateIamRolePolicyNamePrefix(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 100 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 100 characters", k))
}
if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k))
}
return
}
func validateApiGatewayUsagePlanQuotaSettingsPeriod(v interface{}, k string) (ws []string, errors []error) {
validPeriods := []string{
apigateway.QuotaPeriodTypeDay,
apigateway.QuotaPeriodTypeWeek,
apigateway.QuotaPeriodTypeMonth,
}
period := v.(string)
for _, f := range validPeriods {
if period == f {
return
}
}
errors = append(errors, fmt.Errorf(
"%q contains an invalid period %q. Valid period are %q.",
k, period, validPeriods))
return
}
func validateApiGatewayUsagePlanQuotaSettings(v map[string]interface{}) (errors []error) {
period := v["period"].(string)
offset := v["offset"].(int)
if period == apigateway.QuotaPeriodTypeDay && offset != 0 {
errors = append(errors, fmt.Errorf("Usage Plan quota offset must be zero in the DAY period"))
}
if period == apigateway.QuotaPeriodTypeWeek && (offset < 0 || offset > 6) {
errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 6 inclusive in the WEEK period"))
}
if period == apigateway.QuotaPeriodTypeMonth && (offset < 0 || offset > 27) {
errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 27 inclusive in the MONTH period"))
}
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-z-]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"only lowercase 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-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
}
func validateAwsAlbTargetGroupName(v interface{}, k string) (ws []string, errors []error) {
name := v.(string)
if len(name) > 32 {
errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '32' characters", k, name))
}
return
}
func validateAwsAlbTargetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
name := v.(string)
if len(name) > 32 {
errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '6' characters", k, name))
}
return
}
func validateOpenIdURL(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
u, err := url.Parse(value)
if err != nil {
errors = append(errors, fmt.Errorf("%q has to be a valid URL", k))
return
}
if u.Scheme != "https" {
errors = append(errors, fmt.Errorf("%q has to use HTTPS scheme (i.e. begin with https://)", k))
}
if len(u.Query()) > 0 {
errors = append(errors, fmt.Errorf("%q cannot contain query parameters per the OIDC standard", k))
}
return
}
func validateAwsKmsName(v interface{}, k string) (ws []string, es []error) {
value := v.(string)
if !regexp.MustCompile(`^(alias\/)[a-zA-Z0-9:/_-]+$`).MatchString(value) {
es = append(es, fmt.Errorf(
"%q must begin with 'alias/' and be comprised of only [a-zA-Z0-9:/_-]", k))
}
return
}
func validateCognitoIdentityPoolName(v interface{}, k string) (ws []string, errors []error) {
val := v.(string)
if !regexp.MustCompile("^[\\w _]+$").MatchString(val) {
errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters and spaces", k))
}
return
}
func validateCognitoProviderDeveloperName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 100 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 100 caracters", k))
}
if !regexp.MustCompile("^[\\w._-]+$").MatchString(value) {
errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, underscores and hyphens", k))
}
return
}
func validateCognitoSupportedLoginProviders(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) < 1 {
errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k))
}
if len(value) > 128 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k))
}
if !regexp.MustCompile("^[\\w.;_/-]+$").MatchString(value) {
errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, semicolons, underscores, slashes and hyphens", k))
}
return
}
func validateCognitoIdentityProvidersClientId(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) < 1 {
errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k))
}
if len(value) > 128 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k))
}
if !regexp.MustCompile("^[\\w_]+$").MatchString(value) {
errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters and underscores", k))
}
return
}
func validateCognitoIdentityProvidersProviderName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) < 1 {
errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k))
}
if len(value) > 128 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k))
}
if !regexp.MustCompile("^[\\w._:/-]+$").MatchString(value) {
errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, underscores, colons, slashes and hyphens", k))
}
return
}
func validateWafMetricName(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 allowed in %q: %q",
k, value))
}
return
}
func validateIamRoleDescription(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 1000 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 1000 caracters", k))
}
if !regexp.MustCompile(`[\p{L}\p{M}\p{Z}\p{S}\p{N}\p{P}]*`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"Only alphanumeric & accented characters allowed in %q: %q (Must satisfy regular expression pattern: [\\p{L}\\p{M}\\p{Z}\\p{S}\\p{N}\\p{P}]*)",
k, value))
}
return
}
func validateSsmParameterType(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
types := map[string]bool{
"String": true,
"StringList": true,
"SecureString": true,
}
if !types[value] {
errors = append(errors, fmt.Errorf("Parameter type %s is invalid. Valid types are String, StringList or SecureString", value))
}
return
}