github.com/jrperritt/terraform@v0.1.1-0.20170525065507-96f391dafc38/builtin/providers/aws/validators.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"net/url"
     7  	"regexp"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/aws/aws-sdk-go/service/apigateway"
    12  	"github.com/aws/aws-sdk-go/service/s3"
    13  	"github.com/hashicorp/terraform/helper/schema"
    14  )
    15  
    16  func validateRdsIdentifier(v interface{}, k string) (ws []string, errors []error) {
    17  	value := v.(string)
    18  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
    19  		errors = append(errors, fmt.Errorf(
    20  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
    21  	}
    22  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
    23  		errors = append(errors, fmt.Errorf(
    24  			"first character of %q must be a letter", k))
    25  	}
    26  	if regexp.MustCompile(`--`).MatchString(value) {
    27  		errors = append(errors, fmt.Errorf(
    28  			"%q cannot contain two consecutive hyphens", k))
    29  	}
    30  	if regexp.MustCompile(`-$`).MatchString(value) {
    31  		errors = append(errors, fmt.Errorf(
    32  			"%q cannot end with a hyphen", k))
    33  	}
    34  	return
    35  }
    36  
    37  func validateRdsIdentifierPrefix(v interface{}, k string) (ws []string, errors []error) {
    38  	value := v.(string)
    39  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
    40  		errors = append(errors, fmt.Errorf(
    41  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
    42  	}
    43  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
    44  		errors = append(errors, fmt.Errorf(
    45  			"first character of %q must be a letter", k))
    46  	}
    47  	if regexp.MustCompile(`--`).MatchString(value) {
    48  		errors = append(errors, fmt.Errorf(
    49  			"%q cannot contain two consecutive hyphens", k))
    50  	}
    51  	return
    52  }
    53  
    54  func validateElastiCacheClusterId(v interface{}, k string) (ws []string, errors []error) {
    55  	value := v.(string)
    56  	if (len(value) < 1) || (len(value) > 20) {
    57  		errors = append(errors, fmt.Errorf(
    58  			"%q (%q) must contain from 1 to 20 alphanumeric characters or hyphens", k, value))
    59  	}
    60  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
    61  		errors = append(errors, fmt.Errorf(
    62  			"only lowercase alphanumeric characters and hyphens allowed in %q (%q)", k, value))
    63  	}
    64  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
    65  		errors = append(errors, fmt.Errorf(
    66  			"first character of %q (%q) must be a letter", k, value))
    67  	}
    68  	if regexp.MustCompile(`--`).MatchString(value) {
    69  		errors = append(errors, fmt.Errorf(
    70  			"%q (%q) cannot contain two consecutive hyphens", k, value))
    71  	}
    72  	if regexp.MustCompile(`-$`).MatchString(value) {
    73  		errors = append(errors, fmt.Errorf(
    74  			"%q (%q) cannot end with a hyphen", k, value))
    75  	}
    76  	return
    77  }
    78  
    79  func validateASGScheduleTimestamp(v interface{}, k string) (ws []string, errors []error) {
    80  	value := v.(string)
    81  	_, err := time.Parse(awsAutoscalingScheduleTimeLayout, value)
    82  	if err != nil {
    83  		errors = append(errors, fmt.Errorf(
    84  			"%q cannot be parsed as iso8601 Timestamp Format", value))
    85  	}
    86  
    87  	return
    88  }
    89  
    90  // validateTagFilters confirms the "value" component of a tag filter is one of
    91  // AWS's three allowed types.
    92  func validateTagFilters(v interface{}, k string) (ws []string, errors []error) {
    93  	value := v.(string)
    94  	if value != "KEY_ONLY" && value != "VALUE_ONLY" && value != "KEY_AND_VALUE" {
    95  		errors = append(errors, fmt.Errorf(
    96  			"%q must be one of \"KEY_ONLY\", \"VALUE_ONLY\", or \"KEY_AND_VALUE\"", k))
    97  	}
    98  	return
    99  }
   100  
   101  func validateDbParamGroupName(v interface{}, k string) (ws []string, errors []error) {
   102  	value := v.(string)
   103  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
   104  		errors = append(errors, fmt.Errorf(
   105  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
   106  	}
   107  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
   108  		errors = append(errors, fmt.Errorf(
   109  			"first character of %q must be a letter", k))
   110  	}
   111  	if regexp.MustCompile(`--`).MatchString(value) {
   112  		errors = append(errors, fmt.Errorf(
   113  			"%q cannot contain two consecutive hyphens", k))
   114  	}
   115  	if regexp.MustCompile(`-$`).MatchString(value) {
   116  		errors = append(errors, fmt.Errorf(
   117  			"%q cannot end with a hyphen", k))
   118  	}
   119  	if len(value) > 255 {
   120  		errors = append(errors, fmt.Errorf(
   121  			"%q cannot be greater than 255 characters", k))
   122  	}
   123  	return
   124  }
   125  
   126  func validateDbParamGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
   127  	value := v.(string)
   128  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
   129  		errors = append(errors, fmt.Errorf(
   130  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
   131  	}
   132  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
   133  		errors = append(errors, fmt.Errorf(
   134  			"first character of %q must be a letter", k))
   135  	}
   136  	if regexp.MustCompile(`--`).MatchString(value) {
   137  		errors = append(errors, fmt.Errorf(
   138  			"%q cannot contain two consecutive hyphens", k))
   139  	}
   140  	if len(value) > 255 {
   141  		errors = append(errors, fmt.Errorf(
   142  			"%q cannot be greater than 226 characters", k))
   143  	}
   144  	return
   145  }
   146  
   147  func validateStreamViewType(v interface{}, k string) (ws []string, errors []error) {
   148  	value := v.(string)
   149  	viewTypes := map[string]bool{
   150  		"KEYS_ONLY":          true,
   151  		"NEW_IMAGE":          true,
   152  		"OLD_IMAGE":          true,
   153  		"NEW_AND_OLD_IMAGES": true,
   154  	}
   155  
   156  	if !viewTypes[value] {
   157  		errors = append(errors, fmt.Errorf("%q must be a valid DynamoDB StreamViewType", k))
   158  	}
   159  	return
   160  }
   161  
   162  func validateElbName(v interface{}, k string) (ws []string, errors []error) {
   163  	value := v.(string)
   164  	if len(value) == 0 {
   165  		return // short-circuit
   166  	}
   167  	if len(value) > 32 {
   168  		errors = append(errors, fmt.Errorf(
   169  			"%q cannot be longer than 32 characters: %q", k, value))
   170  	}
   171  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   172  		errors = append(errors, fmt.Errorf(
   173  			"only alphanumeric characters and hyphens allowed in %q: %q",
   174  			k, value))
   175  	}
   176  	if regexp.MustCompile(`^-`).MatchString(value) {
   177  		errors = append(errors, fmt.Errorf(
   178  			"%q cannot begin with a hyphen: %q", k, value))
   179  	}
   180  	if regexp.MustCompile(`-$`).MatchString(value) {
   181  		errors = append(errors, fmt.Errorf(
   182  			"%q cannot end with a hyphen: %q", k, value))
   183  	}
   184  	return
   185  }
   186  
   187  func validateElbNamePrefix(v interface{}, k string) (ws []string, errors []error) {
   188  	value := v.(string)
   189  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   190  		errors = append(errors, fmt.Errorf(
   191  			"only alphanumeric characters and hyphens allowed in %q: %q",
   192  			k, value))
   193  	}
   194  	if len(value) > 6 {
   195  		errors = append(errors, fmt.Errorf(
   196  			"%q cannot be longer than 6 characters: %q", k, value))
   197  	}
   198  	if regexp.MustCompile(`^-`).MatchString(value) {
   199  		errors = append(errors, fmt.Errorf(
   200  			"%q cannot begin with a hyphen: %q", k, value))
   201  	}
   202  	return
   203  }
   204  
   205  func validateEcrRepositoryName(v interface{}, k string) (ws []string, errors []error) {
   206  	value := v.(string)
   207  	if len(value) < 2 {
   208  		errors = append(errors, fmt.Errorf(
   209  			"%q must be at least 2 characters long: %q", k, value))
   210  	}
   211  	if len(value) > 256 {
   212  		errors = append(errors, fmt.Errorf(
   213  			"%q cannot be longer than 256 characters: %q", k, value))
   214  	}
   215  
   216  	// http://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_CreateRepository.html
   217  	pattern := `^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)*[a-z0-9]+(?:[._-][a-z0-9]+)*$`
   218  	if !regexp.MustCompile(pattern).MatchString(value) {
   219  		errors = append(errors, fmt.Errorf(
   220  			"%q doesn't comply with restrictions (%q): %q",
   221  			k, pattern, value))
   222  	}
   223  
   224  	return
   225  }
   226  
   227  func validateCloudWatchEventRuleName(v interface{}, k string) (ws []string, errors []error) {
   228  	value := v.(string)
   229  	if len(value) > 64 {
   230  		errors = append(errors, fmt.Errorf(
   231  			"%q cannot be longer than 64 characters: %q", k, value))
   232  	}
   233  
   234  	// http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_PutRule.html
   235  	pattern := `^[\.\-_A-Za-z0-9]+$`
   236  	if !regexp.MustCompile(pattern).MatchString(value) {
   237  		errors = append(errors, fmt.Errorf(
   238  			"%q doesn't comply with restrictions (%q): %q",
   239  			k, pattern, value))
   240  	}
   241  
   242  	return
   243  }
   244  
   245  func validateMaxLength(length int) schema.SchemaValidateFunc {
   246  	return func(v interface{}, k string) (ws []string, errors []error) {
   247  		value := v.(string)
   248  		if len(value) > length {
   249  			errors = append(errors, fmt.Errorf(
   250  				"%q cannot be longer than %d characters: %q", k, length, value))
   251  		}
   252  		return
   253  	}
   254  }
   255  
   256  func validateIntegerInRange(min, max int) schema.SchemaValidateFunc {
   257  	return func(v interface{}, k string) (ws []string, errors []error) {
   258  		value := v.(int)
   259  		if value < min {
   260  			errors = append(errors, fmt.Errorf(
   261  				"%q cannot be lower than %d: %d", k, min, value))
   262  		}
   263  		if value > max {
   264  			errors = append(errors, fmt.Errorf(
   265  				"%q cannot be higher than %d: %d", k, max, value))
   266  		}
   267  		return
   268  	}
   269  }
   270  
   271  func validateCloudWatchEventTargetId(v interface{}, k string) (ws []string, errors []error) {
   272  	value := v.(string)
   273  	if len(value) > 64 {
   274  		errors = append(errors, fmt.Errorf(
   275  			"%q cannot be longer than 64 characters: %q", k, value))
   276  	}
   277  
   278  	// http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_Target.html
   279  	pattern := `^[\.\-_A-Za-z0-9]+$`
   280  	if !regexp.MustCompile(pattern).MatchString(value) {
   281  		errors = append(errors, fmt.Errorf(
   282  			"%q doesn't comply with restrictions (%q): %q",
   283  			k, pattern, value))
   284  	}
   285  
   286  	return
   287  }
   288  
   289  func validateLambdaFunctionName(v interface{}, k string) (ws []string, errors []error) {
   290  	value := v.(string)
   291  	if len(value) > 140 {
   292  		errors = append(errors, fmt.Errorf(
   293  			"%q cannot be longer than 140 characters: %q", k, value))
   294  	}
   295  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   296  	pattern := `^(arn:[\w-]+:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?$`
   297  	if !regexp.MustCompile(pattern).MatchString(value) {
   298  		errors = append(errors, fmt.Errorf(
   299  			"%q doesn't comply with restrictions (%q): %q",
   300  			k, pattern, value))
   301  	}
   302  
   303  	return
   304  }
   305  
   306  func validateLambdaQualifier(v interface{}, k string) (ws []string, errors []error) {
   307  	value := v.(string)
   308  	if len(value) > 128 {
   309  		errors = append(errors, fmt.Errorf(
   310  			"%q cannot be longer than 128 characters: %q", k, value))
   311  	}
   312  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   313  	pattern := `^[a-zA-Z0-9$_-]+$`
   314  	if !regexp.MustCompile(pattern).MatchString(value) {
   315  		errors = append(errors, fmt.Errorf(
   316  			"%q doesn't comply with restrictions (%q): %q",
   317  			k, pattern, value))
   318  	}
   319  
   320  	return
   321  }
   322  
   323  func validateLambdaPermissionAction(v interface{}, k string) (ws []string, errors []error) {
   324  	value := v.(string)
   325  
   326  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   327  	pattern := `^(lambda:[*]|lambda:[a-zA-Z]+|[*])$`
   328  	if !regexp.MustCompile(pattern).MatchString(value) {
   329  		errors = append(errors, fmt.Errorf(
   330  			"%q doesn't comply with restrictions (%q): %q",
   331  			k, pattern, value))
   332  	}
   333  
   334  	return
   335  }
   336  
   337  func validateAwsAccountId(v interface{}, k string) (ws []string, errors []error) {
   338  	value := v.(string)
   339  
   340  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   341  	pattern := `^\d{12}$`
   342  	if !regexp.MustCompile(pattern).MatchString(value) {
   343  		errors = append(errors, fmt.Errorf(
   344  			"%q doesn't look like AWS Account ID (exactly 12 digits): %q",
   345  			k, value))
   346  	}
   347  
   348  	return
   349  }
   350  
   351  func validateArn(v interface{}, k string) (ws []string, errors []error) {
   352  	value := v.(string)
   353  
   354  	if value == "" {
   355  		return
   356  	}
   357  
   358  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   359  	pattern := `^arn:[\w-]+:([a-zA-Z0-9\-])+:([a-z]{2}-(gov-)?[a-z]+-\d{1})?:(\d{12})?:(.*)$`
   360  	if !regexp.MustCompile(pattern).MatchString(value) {
   361  		errors = append(errors, fmt.Errorf(
   362  			"%q doesn't look like a valid ARN (%q): %q",
   363  			k, pattern, value))
   364  	}
   365  
   366  	return
   367  }
   368  
   369  func validatePolicyStatementId(v interface{}, k string) (ws []string, errors []error) {
   370  	value := v.(string)
   371  
   372  	if len(value) > 100 {
   373  		errors = append(errors, fmt.Errorf(
   374  			"%q cannot be longer than 100 characters: %q", k, value))
   375  	}
   376  
   377  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   378  	pattern := `^[a-zA-Z0-9-_]+$`
   379  	if !regexp.MustCompile(pattern).MatchString(value) {
   380  		errors = append(errors, fmt.Errorf(
   381  			"%q doesn't look like a valid statement ID (%q): %q",
   382  			k, pattern, value))
   383  	}
   384  
   385  	return
   386  }
   387  
   388  // validateCIDRNetworkAddress ensures that the string value is a valid CIDR that
   389  // represents a network address - it adds an error otherwise
   390  func validateCIDRNetworkAddress(v interface{}, k string) (ws []string, errors []error) {
   391  	value := v.(string)
   392  	_, ipnet, err := net.ParseCIDR(value)
   393  	if err != nil {
   394  		errors = append(errors, fmt.Errorf(
   395  			"%q must contain a valid CIDR, got error parsing: %s", k, err))
   396  		return
   397  	}
   398  
   399  	if ipnet == nil || value != ipnet.String() {
   400  		errors = append(errors, fmt.Errorf(
   401  			"%q must contain a valid network CIDR, expected %q, got %q",
   402  			k, ipnet, value))
   403  	}
   404  
   405  	return
   406  }
   407  
   408  func validateHTTPMethod(v interface{}, k string) (ws []string, errors []error) {
   409  	value := v.(string)
   410  
   411  	validMethods := map[string]bool{
   412  		"ANY":     true,
   413  		"DELETE":  true,
   414  		"GET":     true,
   415  		"HEAD":    true,
   416  		"OPTIONS": true,
   417  		"PATCH":   true,
   418  		"POST":    true,
   419  		"PUT":     true,
   420  	}
   421  
   422  	if _, ok := validMethods[value]; !ok {
   423  		errors = append(errors, fmt.Errorf(
   424  			"%q contains an invalid method %q. Valid methods are either %q, %q, %q, %q, %q, %q, %q, or %q.",
   425  			k, value, "ANY", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"))
   426  	}
   427  	return
   428  }
   429  
   430  func validateLogMetricFilterName(v interface{}, k string) (ws []string, errors []error) {
   431  	value := v.(string)
   432  
   433  	if len(value) > 512 {
   434  		errors = append(errors, fmt.Errorf(
   435  			"%q cannot be longer than 512 characters: %q", k, value))
   436  	}
   437  
   438  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutMetricFilter.html
   439  	pattern := `^[^:*]+$`
   440  	if !regexp.MustCompile(pattern).MatchString(value) {
   441  		errors = append(errors, fmt.Errorf(
   442  			"%q isn't a valid log metric name (must not contain colon nor asterisk): %q",
   443  			k, value))
   444  	}
   445  
   446  	return
   447  }
   448  
   449  func validateLogMetricFilterTransformationName(v interface{}, k string) (ws []string, errors []error) {
   450  	value := v.(string)
   451  
   452  	if len(value) > 255 {
   453  		errors = append(errors, fmt.Errorf(
   454  			"%q cannot be longer than 255 characters: %q", k, value))
   455  	}
   456  
   457  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_MetricTransformation.html
   458  	pattern := `^[^:*$]*$`
   459  	if !regexp.MustCompile(pattern).MatchString(value) {
   460  		errors = append(errors, fmt.Errorf(
   461  			"%q isn't a valid log metric transformation name (must not contain"+
   462  				" colon, asterisk nor dollar sign): %q",
   463  			k, value))
   464  	}
   465  
   466  	return
   467  }
   468  
   469  func validateLogGroupName(v interface{}, k string) (ws []string, errors []error) {
   470  	value := v.(string)
   471  
   472  	if len(value) > 512 {
   473  		errors = append(errors, fmt.Errorf(
   474  			"%q cannot be longer than 512 characters: %q", k, value))
   475  	}
   476  
   477  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html
   478  	pattern := `^[\.\-_/#A-Za-z0-9]+$`
   479  	if !regexp.MustCompile(pattern).MatchString(value) {
   480  		errors = append(errors, fmt.Errorf(
   481  			"%q isn't a valid log group name (alphanumeric characters, underscores,"+
   482  				" hyphens, slashes, hash signs and dots are allowed): %q",
   483  			k, value))
   484  	}
   485  
   486  	return
   487  }
   488  
   489  func validateLogGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
   490  	value := v.(string)
   491  
   492  	if len(value) > 483 {
   493  		errors = append(errors, fmt.Errorf(
   494  			"%q cannot be longer than 483 characters: %q", k, value))
   495  	}
   496  
   497  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html
   498  	pattern := `^[\.\-_/#A-Za-z0-9]+$`
   499  	if !regexp.MustCompile(pattern).MatchString(value) {
   500  		errors = append(errors, fmt.Errorf(
   501  			"%q isn't a valid log group name (alphanumeric characters, underscores,"+
   502  				" hyphens, slashes, hash signs and dots are allowed): %q",
   503  			k, value))
   504  	}
   505  
   506  	return
   507  }
   508  
   509  func validateS3BucketLifecycleTimestamp(v interface{}, k string) (ws []string, errors []error) {
   510  	value := v.(string)
   511  	_, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", value))
   512  	if err != nil {
   513  		errors = append(errors, fmt.Errorf(
   514  			"%q cannot be parsed as RFC3339 Timestamp Format", value))
   515  	}
   516  
   517  	return
   518  }
   519  
   520  func validateS3BucketLifecycleStorageClass(v interface{}, k string) (ws []string, errors []error) {
   521  	value := v.(string)
   522  	if value != s3.TransitionStorageClassStandardIa && value != s3.TransitionStorageClassGlacier {
   523  		errors = append(errors, fmt.Errorf(
   524  			"%q must be one of '%q', '%q'", k, s3.TransitionStorageClassStandardIa, s3.TransitionStorageClassGlacier))
   525  	}
   526  
   527  	return
   528  }
   529  
   530  func validateS3BucketReplicationRuleId(v interface{}, k string) (ws []string, errors []error) {
   531  	value := v.(string)
   532  	if len(value) > 255 {
   533  		errors = append(errors, fmt.Errorf(
   534  			"%q cannot be longer than 255 characters: %q", k, value))
   535  	}
   536  
   537  	return
   538  }
   539  
   540  func validateS3BucketReplicationRulePrefix(v interface{}, k string) (ws []string, errors []error) {
   541  	value := v.(string)
   542  	if len(value) > 1024 {
   543  		errors = append(errors, fmt.Errorf(
   544  			"%q cannot be longer than 1024 characters: %q", k, value))
   545  	}
   546  
   547  	return
   548  }
   549  
   550  func validateS3BucketReplicationDestinationStorageClass(v interface{}, k string) (ws []string, errors []error) {
   551  	value := v.(string)
   552  	if value != s3.StorageClassStandard && value != s3.StorageClassStandardIa && value != s3.StorageClassReducedRedundancy {
   553  		errors = append(errors, fmt.Errorf(
   554  			"%q must be one of '%q', '%q' or '%q'", k, s3.StorageClassStandard, s3.StorageClassStandardIa, s3.StorageClassReducedRedundancy))
   555  	}
   556  
   557  	return
   558  }
   559  
   560  func validateS3BucketReplicationRuleStatus(v interface{}, k string) (ws []string, errors []error) {
   561  	value := v.(string)
   562  	if value != s3.ReplicationRuleStatusEnabled && value != s3.ReplicationRuleStatusDisabled {
   563  		errors = append(errors, fmt.Errorf(
   564  			"%q must be one of '%q' or '%q'", k, s3.ReplicationRuleStatusEnabled, s3.ReplicationRuleStatusDisabled))
   565  	}
   566  
   567  	return
   568  }
   569  
   570  func validateS3BucketLifecycleRuleId(v interface{}, k string) (ws []string, errors []error) {
   571  	value := v.(string)
   572  	if len(value) > 255 {
   573  		errors = append(errors, fmt.Errorf(
   574  			"%q cannot exceed 255 characters", k))
   575  	}
   576  	return
   577  }
   578  
   579  func validateDbEventSubscriptionName(v interface{}, k string) (ws []string, errors []error) {
   580  	value := v.(string)
   581  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   582  		errors = append(errors, fmt.Errorf(
   583  			"only alphanumeric characters and hyphens allowed in %q", k))
   584  	}
   585  	if len(value) > 255 {
   586  		errors = append(errors, fmt.Errorf(
   587  			"%q cannot be longer than 255 characters", k))
   588  	}
   589  	return
   590  }
   591  
   592  func validateApiGatewayIntegrationPassthroughBehavior(v interface{}, k string) (ws []string, errors []error) {
   593  	value := v.(string)
   594  	if value != "WHEN_NO_MATCH" && value != "WHEN_NO_TEMPLATES" && value != "NEVER" {
   595  		errors = append(errors, fmt.Errorf(
   596  			"%q must be one of 'WHEN_NO_MATCH', 'WHEN_NO_TEMPLATES', 'NEVER'", k))
   597  	}
   598  	return
   599  }
   600  
   601  func validateJsonString(v interface{}, k string) (ws []string, errors []error) {
   602  	if _, err := normalizeJsonString(v); err != nil {
   603  		errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
   604  	}
   605  	return
   606  }
   607  
   608  func validateIAMPolicyJson(v interface{}, k string) (ws []string, errors []error) {
   609  	// IAM Policy documents need to be valid JSON, and pass legacy parsing
   610  	value := v.(string)
   611  	if len(value) < 1 {
   612  		errors = append(errors, fmt.Errorf("%q contains an invalid JSON policy", k))
   613  		return
   614  	}
   615  	if value[:1] != "{" {
   616  		errors = append(errors, fmt.Errorf("%q conatains an invalid JSON policy", k))
   617  		return
   618  	}
   619  	if _, err := normalizeJsonString(v); err != nil {
   620  		errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
   621  	}
   622  	return
   623  }
   624  
   625  func validateCloudFormationTemplate(v interface{}, k string) (ws []string, errors []error) {
   626  	if looksLikeJsonString(v) {
   627  		if _, err := normalizeJsonString(v); err != nil {
   628  			errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
   629  		}
   630  	} else {
   631  		if _, err := checkYamlString(v); err != nil {
   632  			errors = append(errors, fmt.Errorf("%q contains an invalid YAML: %s", k, err))
   633  		}
   634  	}
   635  	return
   636  }
   637  
   638  func validateApiGatewayIntegrationType(v interface{}, k string) (ws []string, errors []error) {
   639  	value := v.(string)
   640  
   641  	validTypes := map[string]bool{
   642  		"AWS":        true,
   643  		"AWS_PROXY":  true,
   644  		"HTTP":       true,
   645  		"HTTP_PROXY": true,
   646  		"MOCK":       true,
   647  	}
   648  
   649  	if _, ok := validTypes[value]; !ok {
   650  		errors = append(errors, fmt.Errorf(
   651  			"%q contains an invalid integration type %q. Valid types are either %q, %q, %q, %q, or %q.",
   652  			k, value, "AWS", "AWS_PROXY", "HTTP", "HTTP_PROXY", "MOCK"))
   653  	}
   654  	return
   655  }
   656  
   657  func validateApiGatewayIntegrationContentHandling(v interface{}, k string) (ws []string, errors []error) {
   658  	value := v.(string)
   659  
   660  	validTypes := map[string]bool{
   661  		"CONVERT_TO_BINARY": true,
   662  		"CONVERT_TO_TEXT":   true,
   663  	}
   664  
   665  	if _, ok := validTypes[value]; !ok {
   666  		errors = append(errors, fmt.Errorf(
   667  			"%q contains an invalid integration type %q. Valid types are either %q or %q.",
   668  			k, value, "CONVERT_TO_BINARY", "CONVERT_TO_TEXT"))
   669  	}
   670  	return
   671  }
   672  
   673  func validateSQSQueueName(v interface{}, k string) (errors []error) {
   674  	value := v.(string)
   675  	if len(value) > 80 {
   676  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   677  	}
   678  
   679  	if !regexp.MustCompile(`^[0-9A-Za-z-_]+$`).MatchString(value) {
   680  		errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k))
   681  	}
   682  	return
   683  }
   684  
   685  func validateSQSFifoQueueName(v interface{}, k string) (errors []error) {
   686  	value := v.(string)
   687  
   688  	if len(value) > 80 {
   689  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   690  	}
   691  
   692  	if !regexp.MustCompile(`^[0-9A-Za-z-_.]+$`).MatchString(value) {
   693  		errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k))
   694  	}
   695  
   696  	if regexp.MustCompile(`^[^a-zA-Z0-9-_]`).MatchString(value) {
   697  		errors = append(errors, fmt.Errorf("FIFO queue name must start with one of these characters [a-zA-Z0-9-_]: %v", value))
   698  	}
   699  
   700  	if !regexp.MustCompile(`\.fifo$`).MatchString(value) {
   701  		errors = append(errors, fmt.Errorf("FIFO queue name should ends with \".fifo\": %v", value))
   702  	}
   703  
   704  	return
   705  }
   706  
   707  func validateSNSSubscriptionProtocol(v interface{}, k string) (ws []string, errors []error) {
   708  	value := strings.ToLower(v.(string))
   709  	forbidden := []string{"email", "sms"}
   710  	for _, f := range forbidden {
   711  		if strings.Contains(value, f) {
   712  			errors = append(
   713  				errors,
   714  				fmt.Errorf("Unsupported protocol (%s) for SNS Topic", value),
   715  			)
   716  		}
   717  	}
   718  	return
   719  }
   720  
   721  func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) {
   722  	value := strings.ToLower(v.(string))
   723  
   724  	validTypes := map[string]bool{
   725  		"ingress": true,
   726  		"egress":  true,
   727  	}
   728  
   729  	if _, ok := validTypes[value]; !ok {
   730  		errors = append(errors, fmt.Errorf(
   731  			"%q contains an invalid Security Group Rule type %q. Valid types are either %q or %q.",
   732  			k, value, "ingress", "egress"))
   733  	}
   734  	return
   735  }
   736  
   737  func validateOnceAWeekWindowFormat(v interface{}, k string) (ws []string, errors []error) {
   738  	// valid time format is "ddd:hh24:mi"
   739  	validTimeFormat := "(sun|mon|tue|wed|thu|fri|sat):([0-1][0-9]|2[0-3]):([0-5][0-9])"
   740  	validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$"
   741  
   742  	value := strings.ToLower(v.(string))
   743  	if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) {
   744  		errors = append(errors, fmt.Errorf(
   745  			"%q must satisfy the format of \"ddd:hh24:mi-ddd:hh24:mi\".", k))
   746  	}
   747  	return
   748  }
   749  
   750  func validateOnceADayWindowFormat(v interface{}, k string) (ws []string, errors []error) {
   751  	// valid time format is "hh24:mi"
   752  	validTimeFormat := "([0-1][0-9]|2[0-3]):([0-5][0-9])"
   753  	validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$"
   754  
   755  	value := v.(string)
   756  	if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) {
   757  		errors = append(errors, fmt.Errorf(
   758  			"%q must satisfy the format of \"hh24:mi-hh24:mi\".", k))
   759  	}
   760  	return
   761  }
   762  
   763  func validateRoute53RecordType(v interface{}, k string) (ws []string, errors []error) {
   764  	// Valid Record types
   765  	// SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA
   766  	validTypes := map[string]struct{}{
   767  		"SOA":   {},
   768  		"A":     {},
   769  		"TXT":   {},
   770  		"NS":    {},
   771  		"CNAME": {},
   772  		"MX":    {},
   773  		"NAPTR": {},
   774  		"PTR":   {},
   775  		"SRV":   {},
   776  		"SPF":   {},
   777  		"AAAA":  {},
   778  	}
   779  
   780  	value := v.(string)
   781  	if _, ok := validTypes[value]; !ok {
   782  		errors = append(errors, fmt.Errorf(
   783  			"%q must be one of [SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA]", k))
   784  	}
   785  	return
   786  }
   787  
   788  // Validates that ECS Placement Constraints are set correctly
   789  // Takes type, and expression as strings
   790  func validateAwsEcsPlacementConstraint(constType, constExpr string) error {
   791  	switch constType {
   792  	case "distinctInstance":
   793  		// Expression can be nil for distinctInstance
   794  		return nil
   795  	case "memberOf":
   796  		if constExpr == "" {
   797  			return fmt.Errorf("Expression cannot be nil for 'memberOf' type")
   798  		}
   799  	default:
   800  		return fmt.Errorf("Unknown type provided: %q", constType)
   801  	}
   802  	return nil
   803  }
   804  
   805  // Validates that an Ecs placement strategy is set correctly
   806  // Takes type, and field as strings
   807  func validateAwsEcsPlacementStrategy(stratType, stratField string) error {
   808  	switch stratType {
   809  	case "random":
   810  		// random does not need the field attribute set, could error, but it isn't read at the API level
   811  		return nil
   812  	case "spread":
   813  		//  For the spread placement strategy, valid values are instanceId
   814  		// (or host, which has the same effect), or any platform or custom attribute
   815  		// that is applied to a container instance
   816  		// stratField is already cased to a string
   817  		return nil
   818  	case "binpack":
   819  		if stratField != "cpu" && stratField != "memory" {
   820  			return fmt.Errorf("Binpack type requires the field attribute to be either 'cpu' or 'memory'. Got: %s",
   821  				stratField)
   822  		}
   823  	default:
   824  		return fmt.Errorf("Unknown type %s. Must be one of 'random', 'spread', or 'binpack'.", stratType)
   825  	}
   826  	return nil
   827  }
   828  
   829  func validateAwsEmrEbsVolumeType(v interface{}, k string) (ws []string, errors []error) {
   830  	validTypes := map[string]struct{}{
   831  		"gp2":      {},
   832  		"io1":      {},
   833  		"standard": {},
   834  	}
   835  
   836  	value := v.(string)
   837  
   838  	if _, ok := validTypes[value]; !ok {
   839  		errors = append(errors, fmt.Errorf(
   840  			"%q must be one of ['gp2', 'io1', 'standard']", k))
   841  	}
   842  	return
   843  }
   844  
   845  func validateSfnActivityName(v interface{}, k string) (ws []string, errors []error) {
   846  	value := v.(string)
   847  	if len(value) > 80 {
   848  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   849  	}
   850  
   851  	return
   852  }
   853  
   854  func validateSfnStateMachineDefinition(v interface{}, k string) (ws []string, errors []error) {
   855  	value := v.(string)
   856  	if len(value) > 1048576 {
   857  		errors = append(errors, fmt.Errorf("%q cannot be longer than 1048576 characters", k))
   858  	}
   859  	return
   860  }
   861  
   862  func validateSfnStateMachineName(v interface{}, k string) (ws []string, errors []error) {
   863  	value := v.(string)
   864  	if len(value) > 80 {
   865  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   866  	}
   867  
   868  	if !regexp.MustCompile(`^[a-zA-Z0-9-_]+$`).MatchString(value) {
   869  		errors = append(errors, fmt.Errorf(
   870  			"%q must be composed with only these characters [a-zA-Z0-9-_]: %v", k, value))
   871  	}
   872  	return
   873  }
   874  
   875  func validateDmsCertificateId(v interface{}, k string) (ws []string, es []error) {
   876  	val := v.(string)
   877  
   878  	if len(val) > 255 {
   879  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   880  	}
   881  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   882  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   883  	}
   884  	if strings.Contains(val, "--") {
   885  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   886  	}
   887  	if strings.HasSuffix(val, "-") {
   888  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   889  	}
   890  
   891  	return
   892  }
   893  
   894  func validateDmsEndpointId(v interface{}, k string) (ws []string, es []error) {
   895  	val := v.(string)
   896  
   897  	if len(val) > 255 {
   898  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   899  	}
   900  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   901  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   902  	}
   903  	if strings.Contains(val, "--") {
   904  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   905  	}
   906  	if strings.HasSuffix(val, "-") {
   907  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   908  	}
   909  
   910  	return
   911  }
   912  
   913  func validateDmsReplicationInstanceId(v interface{}, k string) (ws []string, es []error) {
   914  	val := v.(string)
   915  
   916  	if len(val) > 63 {
   917  		es = append(es, fmt.Errorf("%q must not be longer than 63 characters", k))
   918  	}
   919  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   920  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   921  	}
   922  	if strings.Contains(val, "--") {
   923  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   924  	}
   925  	if strings.HasSuffix(val, "-") {
   926  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   927  	}
   928  
   929  	return
   930  }
   931  
   932  func validateDmsReplicationSubnetGroupId(v interface{}, k string) (ws []string, es []error) {
   933  	val := v.(string)
   934  
   935  	if val == "default" {
   936  		es = append(es, fmt.Errorf("%q must not be default", k))
   937  	}
   938  	if len(val) > 255 {
   939  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   940  	}
   941  	if !regexp.MustCompile(`^[a-zA-Z0-9. _-]+$`).MatchString(val) {
   942  		es = append(es, fmt.Errorf("%q must only contain alphanumeric characters, periods, spaces, underscores and hyphens", k))
   943  	}
   944  
   945  	return
   946  }
   947  
   948  func validateDmsReplicationTaskId(v interface{}, k string) (ws []string, es []error) {
   949  	val := v.(string)
   950  
   951  	if len(val) > 255 {
   952  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   953  	}
   954  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   955  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   956  	}
   957  	if strings.Contains(val, "--") {
   958  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   959  	}
   960  	if strings.HasSuffix(val, "-") {
   961  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   962  	}
   963  
   964  	return
   965  }
   966  
   967  func validateAppautoscalingScalableDimension(v interface{}, k string) (ws []string, errors []error) {
   968  	value := v.(string)
   969  	dimensions := map[string]bool{
   970  		"ecs:service:DesiredCount":                     true,
   971  		"ec2:spot-fleet-request:TargetCapacity":        true,
   972  		"elasticmapreduce:instancegroup:InstanceCount": true,
   973  	}
   974  
   975  	if !dimensions[value] {
   976  		errors = append(errors, fmt.Errorf("%q must be a valid scalable dimension value: %q", k, value))
   977  	}
   978  	return
   979  }
   980  
   981  func validateAppautoscalingServiceNamespace(v interface{}, k string) (ws []string, errors []error) {
   982  	value := v.(string)
   983  	namespaces := map[string]bool{
   984  		"ecs":              true,
   985  		"ec2":              true,
   986  		"elasticmapreduce": true,
   987  	}
   988  
   989  	if !namespaces[value] {
   990  		errors = append(errors, fmt.Errorf("%q must be a valid service namespace value: %q", k, value))
   991  	}
   992  	return
   993  }
   994  
   995  func validateConfigRuleSourceOwner(v interface{}, k string) (ws []string, errors []error) {
   996  	validOwners := []string{
   997  		"CUSTOM_LAMBDA",
   998  		"AWS",
   999  	}
  1000  	owner := v.(string)
  1001  	for _, o := range validOwners {
  1002  		if owner == o {
  1003  			return
  1004  		}
  1005  	}
  1006  	errors = append(errors, fmt.Errorf(
  1007  		"%q contains an invalid owner %q. Valid owners are %q.",
  1008  		k, owner, validOwners))
  1009  	return
  1010  }
  1011  
  1012  func validateConfigExecutionFrequency(v interface{}, k string) (ws []string, errors []error) {
  1013  	validFrequencies := []string{
  1014  		"One_Hour",
  1015  		"Three_Hours",
  1016  		"Six_Hours",
  1017  		"Twelve_Hours",
  1018  		"TwentyFour_Hours",
  1019  	}
  1020  	frequency := v.(string)
  1021  	for _, f := range validFrequencies {
  1022  		if frequency == f {
  1023  			return
  1024  		}
  1025  	}
  1026  	errors = append(errors, fmt.Errorf(
  1027  		"%q contains an invalid frequency %q. Valid frequencies are %q.",
  1028  		k, frequency, validFrequencies))
  1029  	return
  1030  }
  1031  
  1032  func validateAccountAlias(v interface{}, k string) (ws []string, es []error) {
  1033  	val := v.(string)
  1034  
  1035  	if (len(val) < 3) || (len(val) > 63) {
  1036  		es = append(es, fmt.Errorf("%q must contain from 3 to 63 alphanumeric characters or hyphens", k))
  1037  	}
  1038  	if !regexp.MustCompile("^[a-z0-9][a-z0-9-]+$").MatchString(val) {
  1039  		es = append(es, fmt.Errorf("%q must start with an alphanumeric character and only contain lowercase alphanumeric characters and hyphens", k))
  1040  	}
  1041  	if strings.Contains(val, "--") {
  1042  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
  1043  	}
  1044  	if strings.HasSuffix(val, "-") {
  1045  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
  1046  	}
  1047  	return
  1048  }
  1049  
  1050  func validateApiGatewayApiKeyValue(v interface{}, k string) (ws []string, errors []error) {
  1051  	value := v.(string)
  1052  	if len(value) < 30 {
  1053  		errors = append(errors, fmt.Errorf(
  1054  			"%q must be at least 30 characters long", k))
  1055  	}
  1056  	if len(value) > 128 {
  1057  		errors = append(errors, fmt.Errorf(
  1058  			"%q cannot be longer than 128 characters", k))
  1059  	}
  1060  	return
  1061  }
  1062  
  1063  func validateIamRolePolicyName(v interface{}, k string) (ws []string, errors []error) {
  1064  	// https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8291-L8296
  1065  	value := v.(string)
  1066  	if len(value) > 128 {
  1067  		errors = append(errors, fmt.Errorf(
  1068  			"%q cannot be longer than 128 characters", k))
  1069  	}
  1070  	if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
  1071  		errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k))
  1072  	}
  1073  	return
  1074  }
  1075  
  1076  func validateIamRolePolicyNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1077  	value := v.(string)
  1078  	if len(value) > 100 {
  1079  		errors = append(errors, fmt.Errorf(
  1080  			"%q cannot be longer than 100 characters", k))
  1081  	}
  1082  	if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
  1083  		errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k))
  1084  	}
  1085  	return
  1086  }
  1087  
  1088  func validateApiGatewayUsagePlanQuotaSettingsPeriod(v interface{}, k string) (ws []string, errors []error) {
  1089  	validPeriods := []string{
  1090  		apigateway.QuotaPeriodTypeDay,
  1091  		apigateway.QuotaPeriodTypeWeek,
  1092  		apigateway.QuotaPeriodTypeMonth,
  1093  	}
  1094  	period := v.(string)
  1095  	for _, f := range validPeriods {
  1096  		if period == f {
  1097  			return
  1098  		}
  1099  	}
  1100  	errors = append(errors, fmt.Errorf(
  1101  		"%q contains an invalid period %q. Valid period are %q.",
  1102  		k, period, validPeriods))
  1103  	return
  1104  }
  1105  
  1106  func validateApiGatewayUsagePlanQuotaSettings(v map[string]interface{}) (errors []error) {
  1107  	period := v["period"].(string)
  1108  	offset := v["offset"].(int)
  1109  
  1110  	if period == apigateway.QuotaPeriodTypeDay && offset != 0 {
  1111  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be zero in the DAY period"))
  1112  	}
  1113  
  1114  	if period == apigateway.QuotaPeriodTypeWeek && (offset < 0 || offset > 6) {
  1115  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 6 inclusive in the WEEK period"))
  1116  	}
  1117  
  1118  	if period == apigateway.QuotaPeriodTypeMonth && (offset < 0 || offset > 27) {
  1119  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 27 inclusive in the MONTH period"))
  1120  	}
  1121  
  1122  	return
  1123  }
  1124  
  1125  func validateDbSubnetGroupName(v interface{}, k string) (ws []string, errors []error) {
  1126  	value := v.(string)
  1127  	if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
  1128  		errors = append(errors, fmt.Errorf(
  1129  			"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
  1130  	}
  1131  	if len(value) > 255 {
  1132  		errors = append(errors, fmt.Errorf(
  1133  			"%q cannot be longer than 255 characters", k))
  1134  	}
  1135  	if regexp.MustCompile(`(?i)^default$`).MatchString(value) {
  1136  		errors = append(errors, fmt.Errorf(
  1137  			"%q is not allowed as %q", "Default", k))
  1138  	}
  1139  	return
  1140  }
  1141  
  1142  func validateDbSubnetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1143  	value := v.(string)
  1144  	if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
  1145  		errors = append(errors, fmt.Errorf(
  1146  			"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
  1147  	}
  1148  	if len(value) > 229 {
  1149  		errors = append(errors, fmt.Errorf(
  1150  			"%q cannot be longer than 229 characters", k))
  1151  	}
  1152  	return
  1153  }
  1154  
  1155  func validateDbOptionGroupName(v interface{}, k string) (ws []string, errors []error) {
  1156  	value := v.(string)
  1157  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
  1158  		errors = append(errors, fmt.Errorf(
  1159  			"first character of %q must be a letter", k))
  1160  	}
  1161  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
  1162  		errors = append(errors, fmt.Errorf(
  1163  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
  1164  	}
  1165  	if regexp.MustCompile(`--`).MatchString(value) {
  1166  		errors = append(errors, fmt.Errorf(
  1167  			"%q cannot contain two consecutive hyphens", k))
  1168  	}
  1169  	if regexp.MustCompile(`-$`).MatchString(value) {
  1170  		errors = append(errors, fmt.Errorf(
  1171  			"%q cannot end with a hyphen", k))
  1172  	}
  1173  	if len(value) > 255 {
  1174  		errors = append(errors, fmt.Errorf(
  1175  			"%q cannot be greater than 255 characters", k))
  1176  	}
  1177  	return
  1178  }
  1179  
  1180  func validateDbOptionGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1181  	value := v.(string)
  1182  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
  1183  		errors = append(errors, fmt.Errorf(
  1184  			"first character of %q must be a letter", k))
  1185  	}
  1186  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
  1187  		errors = append(errors, fmt.Errorf(
  1188  			"only alphanumeric characters and hyphens allowed in %q", k))
  1189  	}
  1190  	if regexp.MustCompile(`--`).MatchString(value) {
  1191  		errors = append(errors, fmt.Errorf(
  1192  			"%q cannot contain two consecutive hyphens", k))
  1193  	}
  1194  	if len(value) > 229 {
  1195  		errors = append(errors, fmt.Errorf(
  1196  			"%q cannot be greater than 229 characters", k))
  1197  	}
  1198  	return
  1199  }
  1200  
  1201  func validateAwsAlbTargetGroupName(v interface{}, k string) (ws []string, errors []error) {
  1202  	name := v.(string)
  1203  	if len(name) > 32 {
  1204  		errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '32' characters", k, name))
  1205  	}
  1206  	return
  1207  }
  1208  
  1209  func validateAwsAlbTargetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1210  	name := v.(string)
  1211  	if len(name) > 32 {
  1212  		errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '6' characters", k, name))
  1213  	}
  1214  	return
  1215  }
  1216  
  1217  func validateOpenIdURL(v interface{}, k string) (ws []string, errors []error) {
  1218  	value := v.(string)
  1219  	u, err := url.Parse(value)
  1220  	if err != nil {
  1221  		errors = append(errors, fmt.Errorf("%q has to be a valid URL", k))
  1222  		return
  1223  	}
  1224  	if u.Scheme != "https" {
  1225  		errors = append(errors, fmt.Errorf("%q has to use HTTPS scheme (i.e. begin with https://)", k))
  1226  	}
  1227  	if len(u.Query()) > 0 {
  1228  		errors = append(errors, fmt.Errorf("%q cannot contain query parameters per the OIDC standard", k))
  1229  	}
  1230  	return
  1231  }
  1232  
  1233  func validateAwsKmsName(v interface{}, k string) (ws []string, es []error) {
  1234  	value := v.(string)
  1235  	if !regexp.MustCompile(`^(alias\/)[a-zA-Z0-9:/_-]+$`).MatchString(value) {
  1236  		es = append(es, fmt.Errorf(
  1237  			"%q must begin with 'alias/' and be comprised of only [a-zA-Z0-9:/_-]", k))
  1238  	}
  1239  	return
  1240  }
  1241  
  1242  func validateCognitoIdentityPoolName(v interface{}, k string) (ws []string, errors []error) {
  1243  	val := v.(string)
  1244  	if !regexp.MustCompile("^[\\w _]+$").MatchString(val) {
  1245  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters and spaces", k))
  1246  	}
  1247  
  1248  	return
  1249  }
  1250  
  1251  func validateCognitoProviderDeveloperName(v interface{}, k string) (ws []string, errors []error) {
  1252  	value := v.(string)
  1253  	if len(value) > 100 {
  1254  		errors = append(errors, fmt.Errorf("%q cannot be longer than 100 caracters", k))
  1255  	}
  1256  
  1257  	if !regexp.MustCompile("^[\\w._-]+$").MatchString(value) {
  1258  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, underscores and hyphens", k))
  1259  	}
  1260  
  1261  	return
  1262  }
  1263  
  1264  func validateCognitoSupportedLoginProviders(v interface{}, k string) (ws []string, errors []error) {
  1265  	value := v.(string)
  1266  	if len(value) < 1 {
  1267  		errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k))
  1268  	}
  1269  
  1270  	if len(value) > 128 {
  1271  		errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k))
  1272  	}
  1273  
  1274  	if !regexp.MustCompile("^[\\w.;_/-]+$").MatchString(value) {
  1275  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, semicolons, underscores, slashes and hyphens", k))
  1276  	}
  1277  
  1278  	return
  1279  }
  1280  
  1281  func validateCognitoIdentityProvidersClientId(v interface{}, k string) (ws []string, errors []error) {
  1282  	value := v.(string)
  1283  	if len(value) < 1 {
  1284  		errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k))
  1285  	}
  1286  
  1287  	if len(value) > 128 {
  1288  		errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k))
  1289  	}
  1290  
  1291  	if !regexp.MustCompile("^[\\w_]+$").MatchString(value) {
  1292  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters and underscores", k))
  1293  	}
  1294  
  1295  	return
  1296  }
  1297  
  1298  func validateCognitoIdentityProvidersProviderName(v interface{}, k string) (ws []string, errors []error) {
  1299  	value := v.(string)
  1300  	if len(value) < 1 {
  1301  		errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k))
  1302  	}
  1303  
  1304  	if len(value) > 128 {
  1305  		errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k))
  1306  	}
  1307  
  1308  	if !regexp.MustCompile("^[\\w._:/-]+$").MatchString(value) {
  1309  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, underscores, colons, slashes and hyphens", k))
  1310  	}
  1311  
  1312  	return
  1313  }
  1314  
  1315  func validateWafMetricName(v interface{}, k string) (ws []string, errors []error) {
  1316  	value := v.(string)
  1317  	if !regexp.MustCompile(`^[0-9A-Za-z]+$`).MatchString(value) {
  1318  		errors = append(errors, fmt.Errorf(
  1319  			"Only alphanumeric characters allowed in %q: %q",
  1320  			k, value))
  1321  	}
  1322  	return
  1323  }
  1324  
  1325  func validateIamRoleDescription(v interface{}, k string) (ws []string, errors []error) {
  1326  	value := v.(string)
  1327  
  1328  	if len(value) > 1000 {
  1329  		errors = append(errors, fmt.Errorf("%q cannot be longer than 1000 caracters", k))
  1330  	}
  1331  
  1332  	if !regexp.MustCompile(`[\p{L}\p{M}\p{Z}\p{S}\p{N}\p{P}]*`).MatchString(value) {
  1333  		errors = append(errors, fmt.Errorf(
  1334  			"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}]*)",
  1335  			k, value))
  1336  	}
  1337  	return
  1338  }