github.com/meteor/terraform@v0.6.15-0.20210412225145-79ec4bc057c6/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 validateCloudFormationTemplate(v interface{}, k string) (ws []string, errors []error) {
   609  	if looksLikeJsonString(v) {
   610  		if _, err := normalizeJsonString(v); err != nil {
   611  			errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
   612  		}
   613  	} else {
   614  		if _, err := checkYamlString(v); err != nil {
   615  			errors = append(errors, fmt.Errorf("%q contains an invalid YAML: %s", k, err))
   616  		}
   617  	}
   618  	return
   619  }
   620  
   621  func validateApiGatewayIntegrationType(v interface{}, k string) (ws []string, errors []error) {
   622  	value := v.(string)
   623  
   624  	validTypes := map[string]bool{
   625  		"AWS":        true,
   626  		"AWS_PROXY":  true,
   627  		"HTTP":       true,
   628  		"HTTP_PROXY": true,
   629  		"MOCK":       true,
   630  	}
   631  
   632  	if _, ok := validTypes[value]; !ok {
   633  		errors = append(errors, fmt.Errorf(
   634  			"%q contains an invalid integration type %q. Valid types are either %q, %q, %q, %q, or %q.",
   635  			k, value, "AWS", "AWS_PROXY", "HTTP", "HTTP_PROXY", "MOCK"))
   636  	}
   637  	return
   638  }
   639  
   640  func validateApiGatewayIntegrationContentHandling(v interface{}, k string) (ws []string, errors []error) {
   641  	value := v.(string)
   642  
   643  	validTypes := map[string]bool{
   644  		"CONVERT_TO_BINARY": true,
   645  		"CONVERT_TO_TEXT":   true,
   646  	}
   647  
   648  	if _, ok := validTypes[value]; !ok {
   649  		errors = append(errors, fmt.Errorf(
   650  			"%q contains an invalid integration type %q. Valid types are either %q or %q.",
   651  			k, value, "CONVERT_TO_BINARY", "CONVERT_TO_TEXT"))
   652  	}
   653  	return
   654  }
   655  
   656  func validateSQSQueueName(v interface{}, k string) (errors []error) {
   657  	value := v.(string)
   658  	if len(value) > 80 {
   659  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   660  	}
   661  
   662  	if !regexp.MustCompile(`^[0-9A-Za-z-_]+$`).MatchString(value) {
   663  		errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k))
   664  	}
   665  	return
   666  }
   667  
   668  func validateSQSFifoQueueName(v interface{}, k string) (errors []error) {
   669  	value := v.(string)
   670  
   671  	if len(value) > 80 {
   672  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   673  	}
   674  
   675  	if !regexp.MustCompile(`^[0-9A-Za-z-_.]+$`).MatchString(value) {
   676  		errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k))
   677  	}
   678  
   679  	if regexp.MustCompile(`^[^a-zA-Z0-9-_]`).MatchString(value) {
   680  		errors = append(errors, fmt.Errorf("FIFO queue name must start with one of these characters [a-zA-Z0-9-_]: %v", value))
   681  	}
   682  
   683  	if !regexp.MustCompile(`\.fifo$`).MatchString(value) {
   684  		errors = append(errors, fmt.Errorf("FIFO queue name should ends with \".fifo\": %v", value))
   685  	}
   686  
   687  	return
   688  }
   689  
   690  func validateSNSSubscriptionProtocol(v interface{}, k string) (ws []string, errors []error) {
   691  	value := strings.ToLower(v.(string))
   692  	forbidden := []string{"email", "sms"}
   693  	for _, f := range forbidden {
   694  		if strings.Contains(value, f) {
   695  			errors = append(
   696  				errors,
   697  				fmt.Errorf("Unsupported protocol (%s) for SNS Topic", value),
   698  			)
   699  		}
   700  	}
   701  	return
   702  }
   703  
   704  func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) {
   705  	value := strings.ToLower(v.(string))
   706  
   707  	validTypes := map[string]bool{
   708  		"ingress": true,
   709  		"egress":  true,
   710  	}
   711  
   712  	if _, ok := validTypes[value]; !ok {
   713  		errors = append(errors, fmt.Errorf(
   714  			"%q contains an invalid Security Group Rule type %q. Valid types are either %q or %q.",
   715  			k, value, "ingress", "egress"))
   716  	}
   717  	return
   718  }
   719  
   720  func validateOnceAWeekWindowFormat(v interface{}, k string) (ws []string, errors []error) {
   721  	// valid time format is "ddd:hh24:mi"
   722  	validTimeFormat := "(sun|mon|tue|wed|thu|fri|sat):([0-1][0-9]|2[0-3]):([0-5][0-9])"
   723  	validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$"
   724  
   725  	value := strings.ToLower(v.(string))
   726  	if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) {
   727  		errors = append(errors, fmt.Errorf(
   728  			"%q must satisfy the format of \"ddd:hh24:mi-ddd:hh24:mi\".", k))
   729  	}
   730  	return
   731  }
   732  
   733  func validateOnceADayWindowFormat(v interface{}, k string) (ws []string, errors []error) {
   734  	// valid time format is "hh24:mi"
   735  	validTimeFormat := "([0-1][0-9]|2[0-3]):([0-5][0-9])"
   736  	validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$"
   737  
   738  	value := v.(string)
   739  	if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) {
   740  		errors = append(errors, fmt.Errorf(
   741  			"%q must satisfy the format of \"hh24:mi-hh24:mi\".", k))
   742  	}
   743  	return
   744  }
   745  
   746  func validateRoute53RecordType(v interface{}, k string) (ws []string, errors []error) {
   747  	// Valid Record types
   748  	// SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA
   749  	validTypes := map[string]struct{}{
   750  		"SOA":   {},
   751  		"A":     {},
   752  		"TXT":   {},
   753  		"NS":    {},
   754  		"CNAME": {},
   755  		"MX":    {},
   756  		"NAPTR": {},
   757  		"PTR":   {},
   758  		"SRV":   {},
   759  		"SPF":   {},
   760  		"AAAA":  {},
   761  	}
   762  
   763  	value := v.(string)
   764  	if _, ok := validTypes[value]; !ok {
   765  		errors = append(errors, fmt.Errorf(
   766  			"%q must be one of [SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA]", k))
   767  	}
   768  	return
   769  }
   770  
   771  // Validates that ECS Placement Constraints are set correctly
   772  // Takes type, and expression as strings
   773  func validateAwsEcsPlacementConstraint(constType, constExpr string) error {
   774  	switch constType {
   775  	case "distinctInstance":
   776  		// Expression can be nil for distinctInstance
   777  		return nil
   778  	case "memberOf":
   779  		if constExpr == "" {
   780  			return fmt.Errorf("Expression cannot be nil for 'memberOf' type")
   781  		}
   782  	default:
   783  		return fmt.Errorf("Unknown type provided: %q", constType)
   784  	}
   785  	return nil
   786  }
   787  
   788  // Validates that an Ecs placement strategy is set correctly
   789  // Takes type, and field as strings
   790  func validateAwsEcsPlacementStrategy(stratType, stratField string) error {
   791  	switch stratType {
   792  	case "random":
   793  		// random does not need the field attribute set, could error, but it isn't read at the API level
   794  		return nil
   795  	case "spread":
   796  		//  For the spread placement strategy, valid values are instanceId
   797  		// (or host, which has the same effect), or any platform or custom attribute
   798  		// that is applied to a container instance
   799  		// stratField is already cased to a string
   800  		return nil
   801  	case "binpack":
   802  		if stratField != "cpu" && stratField != "memory" {
   803  			return fmt.Errorf("Binpack type requires the field attribute to be either 'cpu' or 'memory'. Got: %s",
   804  				stratField)
   805  		}
   806  	default:
   807  		return fmt.Errorf("Unknown type %s. Must be one of 'random', 'spread', or 'binpack'.", stratType)
   808  	}
   809  	return nil
   810  }
   811  
   812  func validateAwsEmrEbsVolumeType(v interface{}, k string) (ws []string, errors []error) {
   813  	validTypes := map[string]struct{}{
   814  		"gp2":      {},
   815  		"io1":      {},
   816  		"standard": {},
   817  	}
   818  
   819  	value := v.(string)
   820  
   821  	if _, ok := validTypes[value]; !ok {
   822  		errors = append(errors, fmt.Errorf(
   823  			"%q must be one of ['gp2', 'io1', 'standard']", k))
   824  	}
   825  	return
   826  }
   827  
   828  func validateSfnActivityName(v interface{}, k string) (ws []string, errors []error) {
   829  	value := v.(string)
   830  	if len(value) > 80 {
   831  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   832  	}
   833  
   834  	return
   835  }
   836  
   837  func validateSfnStateMachineDefinition(v interface{}, k string) (ws []string, errors []error) {
   838  	value := v.(string)
   839  	if len(value) > 1048576 {
   840  		errors = append(errors, fmt.Errorf("%q cannot be longer than 1048576 characters", k))
   841  	}
   842  	return
   843  }
   844  
   845  func validateSfnStateMachineName(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  	if !regexp.MustCompile(`^[a-zA-Z0-9-_]+$`).MatchString(value) {
   852  		errors = append(errors, fmt.Errorf(
   853  			"%q must be composed with only these characters [a-zA-Z0-9-_]: %v", k, value))
   854  	}
   855  	return
   856  }
   857  
   858  func validateDmsCertificateId(v interface{}, k string) (ws []string, es []error) {
   859  	val := v.(string)
   860  
   861  	if len(val) > 255 {
   862  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   863  	}
   864  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   865  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   866  	}
   867  	if strings.Contains(val, "--") {
   868  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   869  	}
   870  	if strings.HasSuffix(val, "-") {
   871  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   872  	}
   873  
   874  	return
   875  }
   876  
   877  func validateDmsEndpointId(v interface{}, k string) (ws []string, es []error) {
   878  	val := v.(string)
   879  
   880  	if len(val) > 255 {
   881  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   882  	}
   883  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   884  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   885  	}
   886  	if strings.Contains(val, "--") {
   887  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   888  	}
   889  	if strings.HasSuffix(val, "-") {
   890  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   891  	}
   892  
   893  	return
   894  }
   895  
   896  func validateDmsReplicationInstanceId(v interface{}, k string) (ws []string, es []error) {
   897  	val := v.(string)
   898  
   899  	if len(val) > 63 {
   900  		es = append(es, fmt.Errorf("%q must not be longer than 63 characters", k))
   901  	}
   902  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   903  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   904  	}
   905  	if strings.Contains(val, "--") {
   906  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   907  	}
   908  	if strings.HasSuffix(val, "-") {
   909  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   910  	}
   911  
   912  	return
   913  }
   914  
   915  func validateDmsReplicationSubnetGroupId(v interface{}, k string) (ws []string, es []error) {
   916  	val := v.(string)
   917  
   918  	if val == "default" {
   919  		es = append(es, fmt.Errorf("%q must not be default", k))
   920  	}
   921  	if len(val) > 255 {
   922  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   923  	}
   924  	if !regexp.MustCompile(`^[a-zA-Z0-9. _-]+$`).MatchString(val) {
   925  		es = append(es, fmt.Errorf("%q must only contain alphanumeric characters, periods, spaces, underscores and hyphens", k))
   926  	}
   927  
   928  	return
   929  }
   930  
   931  func validateDmsReplicationTaskId(v interface{}, k string) (ws []string, es []error) {
   932  	val := v.(string)
   933  
   934  	if len(val) > 255 {
   935  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   936  	}
   937  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   938  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   939  	}
   940  	if strings.Contains(val, "--") {
   941  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   942  	}
   943  	if strings.HasSuffix(val, "-") {
   944  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   945  	}
   946  
   947  	return
   948  }
   949  
   950  func validateAppautoscalingScalableDimension(v interface{}, k string) (ws []string, errors []error) {
   951  	value := v.(string)
   952  	dimensions := map[string]bool{
   953  		"ecs:service:DesiredCount":                     true,
   954  		"ec2:spot-fleet-request:TargetCapacity":        true,
   955  		"elasticmapreduce:instancegroup:InstanceCount": true,
   956  	}
   957  
   958  	if !dimensions[value] {
   959  		errors = append(errors, fmt.Errorf("%q must be a valid scalable dimension value: %q", k, value))
   960  	}
   961  	return
   962  }
   963  
   964  func validateAppautoscalingServiceNamespace(v interface{}, k string) (ws []string, errors []error) {
   965  	value := v.(string)
   966  	namespaces := map[string]bool{
   967  		"ecs":              true,
   968  		"ec2":              true,
   969  		"elasticmapreduce": true,
   970  	}
   971  
   972  	if !namespaces[value] {
   973  		errors = append(errors, fmt.Errorf("%q must be a valid service namespace value: %q", k, value))
   974  	}
   975  	return
   976  }
   977  
   978  func validateConfigRuleSourceOwner(v interface{}, k string) (ws []string, errors []error) {
   979  	validOwners := []string{
   980  		"CUSTOM_LAMBDA",
   981  		"AWS",
   982  	}
   983  	owner := v.(string)
   984  	for _, o := range validOwners {
   985  		if owner == o {
   986  			return
   987  		}
   988  	}
   989  	errors = append(errors, fmt.Errorf(
   990  		"%q contains an invalid owner %q. Valid owners are %q.",
   991  		k, owner, validOwners))
   992  	return
   993  }
   994  
   995  func validateConfigExecutionFrequency(v interface{}, k string) (ws []string, errors []error) {
   996  	validFrequencies := []string{
   997  		"One_Hour",
   998  		"Three_Hours",
   999  		"Six_Hours",
  1000  		"Twelve_Hours",
  1001  		"TwentyFour_Hours",
  1002  	}
  1003  	frequency := v.(string)
  1004  	for _, f := range validFrequencies {
  1005  		if frequency == f {
  1006  			return
  1007  		}
  1008  	}
  1009  	errors = append(errors, fmt.Errorf(
  1010  		"%q contains an invalid frequency %q. Valid frequencies are %q.",
  1011  		k, frequency, validFrequencies))
  1012  	return
  1013  }
  1014  
  1015  func validateAccountAlias(v interface{}, k string) (ws []string, es []error) {
  1016  	val := v.(string)
  1017  
  1018  	if (len(val) < 3) || (len(val) > 63) {
  1019  		es = append(es, fmt.Errorf("%q must contain from 3 to 63 alphanumeric characters or hyphens", k))
  1020  	}
  1021  	if !regexp.MustCompile("^[a-z0-9][a-z0-9-]+$").MatchString(val) {
  1022  		es = append(es, fmt.Errorf("%q must start with an alphanumeric character and only contain lowercase alphanumeric characters and hyphens", k))
  1023  	}
  1024  	if strings.Contains(val, "--") {
  1025  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
  1026  	}
  1027  	if strings.HasSuffix(val, "-") {
  1028  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
  1029  	}
  1030  	return
  1031  }
  1032  
  1033  func validateApiGatewayApiKeyValue(v interface{}, k string) (ws []string, errors []error) {
  1034  	value := v.(string)
  1035  	if len(value) < 30 {
  1036  		errors = append(errors, fmt.Errorf(
  1037  			"%q must be at least 30 characters long", k))
  1038  	}
  1039  	if len(value) > 128 {
  1040  		errors = append(errors, fmt.Errorf(
  1041  			"%q cannot be longer than 128 characters", k))
  1042  	}
  1043  	return
  1044  }
  1045  
  1046  func validateIamRolePolicyName(v interface{}, k string) (ws []string, errors []error) {
  1047  	// https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8291-L8296
  1048  	value := v.(string)
  1049  	if len(value) > 128 {
  1050  		errors = append(errors, fmt.Errorf(
  1051  			"%q cannot be longer than 128 characters", k))
  1052  	}
  1053  	if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
  1054  		errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k))
  1055  	}
  1056  	return
  1057  }
  1058  
  1059  func validateIamRolePolicyNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1060  	value := v.(string)
  1061  	if len(value) > 100 {
  1062  		errors = append(errors, fmt.Errorf(
  1063  			"%q cannot be longer than 100 characters", k))
  1064  	}
  1065  	if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
  1066  		errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k))
  1067  	}
  1068  	return
  1069  }
  1070  
  1071  func validateApiGatewayUsagePlanQuotaSettingsPeriod(v interface{}, k string) (ws []string, errors []error) {
  1072  	validPeriods := []string{
  1073  		apigateway.QuotaPeriodTypeDay,
  1074  		apigateway.QuotaPeriodTypeWeek,
  1075  		apigateway.QuotaPeriodTypeMonth,
  1076  	}
  1077  	period := v.(string)
  1078  	for _, f := range validPeriods {
  1079  		if period == f {
  1080  			return
  1081  		}
  1082  	}
  1083  	errors = append(errors, fmt.Errorf(
  1084  		"%q contains an invalid period %q. Valid period are %q.",
  1085  		k, period, validPeriods))
  1086  	return
  1087  }
  1088  
  1089  func validateApiGatewayUsagePlanQuotaSettings(v map[string]interface{}) (errors []error) {
  1090  	period := v["period"].(string)
  1091  	offset := v["offset"].(int)
  1092  
  1093  	if period == apigateway.QuotaPeriodTypeDay && offset != 0 {
  1094  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be zero in the DAY period"))
  1095  	}
  1096  
  1097  	if period == apigateway.QuotaPeriodTypeWeek && (offset < 0 || offset > 6) {
  1098  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 6 inclusive in the WEEK period"))
  1099  	}
  1100  
  1101  	if period == apigateway.QuotaPeriodTypeMonth && (offset < 0 || offset > 27) {
  1102  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 27 inclusive in the MONTH period"))
  1103  	}
  1104  
  1105  	return
  1106  }
  1107  
  1108  func validateDbSubnetGroupName(v interface{}, k string) (ws []string, errors []error) {
  1109  	value := v.(string)
  1110  	if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
  1111  		errors = append(errors, fmt.Errorf(
  1112  			"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
  1113  	}
  1114  	if len(value) > 255 {
  1115  		errors = append(errors, fmt.Errorf(
  1116  			"%q cannot be longer than 255 characters", k))
  1117  	}
  1118  	if regexp.MustCompile(`(?i)^default$`).MatchString(value) {
  1119  		errors = append(errors, fmt.Errorf(
  1120  			"%q is not allowed as %q", "Default", k))
  1121  	}
  1122  	return
  1123  }
  1124  
  1125  func validateDbSubnetGroupNamePrefix(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) > 229 {
  1132  		errors = append(errors, fmt.Errorf(
  1133  			"%q cannot be longer than 229 characters", k))
  1134  	}
  1135  	return
  1136  }
  1137  
  1138  func validateDbOptionGroupName(v interface{}, k string) (ws []string, errors []error) {
  1139  	value := v.(string)
  1140  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
  1141  		errors = append(errors, fmt.Errorf(
  1142  			"first character of %q must be a letter", k))
  1143  	}
  1144  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
  1145  		errors = append(errors, fmt.Errorf(
  1146  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
  1147  	}
  1148  	if regexp.MustCompile(`--`).MatchString(value) {
  1149  		errors = append(errors, fmt.Errorf(
  1150  			"%q cannot contain two consecutive hyphens", k))
  1151  	}
  1152  	if regexp.MustCompile(`-$`).MatchString(value) {
  1153  		errors = append(errors, fmt.Errorf(
  1154  			"%q cannot end with a hyphen", k))
  1155  	}
  1156  	if len(value) > 255 {
  1157  		errors = append(errors, fmt.Errorf(
  1158  			"%q cannot be greater than 255 characters", k))
  1159  	}
  1160  	return
  1161  }
  1162  
  1163  func validateDbOptionGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1164  	value := v.(string)
  1165  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
  1166  		errors = append(errors, fmt.Errorf(
  1167  			"first character of %q must be a letter", k))
  1168  	}
  1169  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
  1170  		errors = append(errors, fmt.Errorf(
  1171  			"only alphanumeric characters and hyphens allowed in %q", k))
  1172  	}
  1173  	if regexp.MustCompile(`--`).MatchString(value) {
  1174  		errors = append(errors, fmt.Errorf(
  1175  			"%q cannot contain two consecutive hyphens", k))
  1176  	}
  1177  	if len(value) > 229 {
  1178  		errors = append(errors, fmt.Errorf(
  1179  			"%q cannot be greater than 229 characters", k))
  1180  	}
  1181  	return
  1182  }
  1183  
  1184  func validateAwsAlbTargetGroupName(v interface{}, k string) (ws []string, errors []error) {
  1185  	name := v.(string)
  1186  	if len(name) > 32 {
  1187  		errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '32' characters", k, name))
  1188  	}
  1189  	return
  1190  }
  1191  
  1192  func validateAwsAlbTargetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1193  	name := v.(string)
  1194  	if len(name) > 32 {
  1195  		errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '6' characters", k, name))
  1196  	}
  1197  	return
  1198  }
  1199  
  1200  func validateOpenIdURL(v interface{}, k string) (ws []string, errors []error) {
  1201  	value := v.(string)
  1202  	u, err := url.Parse(value)
  1203  	if err != nil {
  1204  		errors = append(errors, fmt.Errorf("%q has to be a valid URL", k))
  1205  		return
  1206  	}
  1207  	if u.Scheme != "https" {
  1208  		errors = append(errors, fmt.Errorf("%q has to use HTTPS scheme (i.e. begin with https://)", k))
  1209  	}
  1210  	if len(u.Query()) > 0 {
  1211  		errors = append(errors, fmt.Errorf("%q cannot contain query parameters per the OIDC standard", k))
  1212  	}
  1213  	return
  1214  }
  1215  
  1216  func validateAwsKmsName(v interface{}, k string) (ws []string, es []error) {
  1217  	value := v.(string)
  1218  	if !regexp.MustCompile(`^(alias\/)[a-zA-Z0-9:/_-]+$`).MatchString(value) {
  1219  		es = append(es, fmt.Errorf(
  1220  			"%q must begin with 'alias/' and be comprised of only [a-zA-Z0-9:/_-]", k))
  1221  	}
  1222  	return
  1223  }
  1224  
  1225  func validateCognitoIdentityPoolName(v interface{}, k string) (ws []string, errors []error) {
  1226  	val := v.(string)
  1227  	if !regexp.MustCompile("^[\\w _]+$").MatchString(val) {
  1228  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters and spaces", k))
  1229  	}
  1230  
  1231  	return
  1232  }
  1233  
  1234  func validateCognitoProviderDeveloperName(v interface{}, k string) (ws []string, errors []error) {
  1235  	value := v.(string)
  1236  	if len(value) > 100 {
  1237  		errors = append(errors, fmt.Errorf("%q cannot be longer than 100 caracters", k))
  1238  	}
  1239  
  1240  	if !regexp.MustCompile("^[\\w._-]+$").MatchString(value) {
  1241  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, underscores and hyphens", k))
  1242  	}
  1243  
  1244  	return
  1245  }
  1246  
  1247  func validateCognitoSupportedLoginProviders(v interface{}, k string) (ws []string, errors []error) {
  1248  	value := v.(string)
  1249  	if len(value) < 1 {
  1250  		errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k))
  1251  	}
  1252  
  1253  	if len(value) > 128 {
  1254  		errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k))
  1255  	}
  1256  
  1257  	if !regexp.MustCompile("^[\\w.;_/-]+$").MatchString(value) {
  1258  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, semicolons, underscores, slashes and hyphens", k))
  1259  	}
  1260  
  1261  	return
  1262  }
  1263  
  1264  func validateCognitoIdentityProvidersClientId(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 and underscores", k))
  1276  	}
  1277  
  1278  	return
  1279  }
  1280  
  1281  func validateCognitoIdentityProvidersProviderName(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, dots, underscores, colons, slashes and hyphens", k))
  1293  	}
  1294  
  1295  	return
  1296  }
  1297  
  1298  func validateWafMetricName(v interface{}, k string) (ws []string, errors []error) {
  1299  	value := v.(string)
  1300  	if !regexp.MustCompile(`^[0-9A-Za-z]+$`).MatchString(value) {
  1301  		errors = append(errors, fmt.Errorf(
  1302  			"Only alphanumeric characters allowed in %q: %q",
  1303  			k, value))
  1304  	}
  1305  	return
  1306  }
  1307  
  1308  func validateIamRoleDescription(v interface{}, k string) (ws []string, errors []error) {
  1309  	value := v.(string)
  1310  
  1311  	if len(value) > 1000 {
  1312  		errors = append(errors, fmt.Errorf("%q cannot be longer than 1000 caracters", k))
  1313  	}
  1314  
  1315  	if !regexp.MustCompile(`[\p{L}\p{M}\p{Z}\p{S}\p{N}\p{P}]*`).MatchString(value) {
  1316  		errors = append(errors, fmt.Errorf(
  1317  			"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}]*)",
  1318  			k, value))
  1319  	}
  1320  	return
  1321  }