github.com/skyscape-cloud-services/terraform@v0.9.2-0.20170609144644-7ece028a1747/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, got %q", k, value))
   402  	}
   403  
   404  	return
   405  }
   406  
   407  func validateHTTPMethod(v interface{}, k string) (ws []string, errors []error) {
   408  	value := v.(string)
   409  
   410  	validMethods := map[string]bool{
   411  		"ANY":     true,
   412  		"DELETE":  true,
   413  		"GET":     true,
   414  		"HEAD":    true,
   415  		"OPTIONS": true,
   416  		"PATCH":   true,
   417  		"POST":    true,
   418  		"PUT":     true,
   419  	}
   420  
   421  	if _, ok := validMethods[value]; !ok {
   422  		errors = append(errors, fmt.Errorf(
   423  			"%q contains an invalid method %q. Valid methods are either %q, %q, %q, %q, %q, %q, %q, or %q.",
   424  			k, value, "ANY", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"))
   425  	}
   426  	return
   427  }
   428  
   429  func validateLogMetricFilterName(v interface{}, k string) (ws []string, errors []error) {
   430  	value := v.(string)
   431  
   432  	if len(value) > 512 {
   433  		errors = append(errors, fmt.Errorf(
   434  			"%q cannot be longer than 512 characters: %q", k, value))
   435  	}
   436  
   437  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutMetricFilter.html
   438  	pattern := `^[^:*]+$`
   439  	if !regexp.MustCompile(pattern).MatchString(value) {
   440  		errors = append(errors, fmt.Errorf(
   441  			"%q isn't a valid log metric name (must not contain colon nor asterisk): %q",
   442  			k, value))
   443  	}
   444  
   445  	return
   446  }
   447  
   448  func validateLogMetricFilterTransformationName(v interface{}, k string) (ws []string, errors []error) {
   449  	value := v.(string)
   450  
   451  	if len(value) > 255 {
   452  		errors = append(errors, fmt.Errorf(
   453  			"%q cannot be longer than 255 characters: %q", k, value))
   454  	}
   455  
   456  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_MetricTransformation.html
   457  	pattern := `^[^:*$]*$`
   458  	if !regexp.MustCompile(pattern).MatchString(value) {
   459  		errors = append(errors, fmt.Errorf(
   460  			"%q isn't a valid log metric transformation name (must not contain"+
   461  				" colon, asterisk nor dollar sign): %q",
   462  			k, value))
   463  	}
   464  
   465  	return
   466  }
   467  
   468  func validateLogGroupName(v interface{}, k string) (ws []string, errors []error) {
   469  	value := v.(string)
   470  
   471  	if len(value) > 512 {
   472  		errors = append(errors, fmt.Errorf(
   473  			"%q cannot be longer than 512 characters: %q", k, value))
   474  	}
   475  
   476  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html
   477  	pattern := `^[\.\-_/#A-Za-z0-9]+$`
   478  	if !regexp.MustCompile(pattern).MatchString(value) {
   479  		errors = append(errors, fmt.Errorf(
   480  			"%q isn't a valid log group name (alphanumeric characters, underscores,"+
   481  				" hyphens, slashes, hash signs and dots are allowed): %q",
   482  			k, value))
   483  	}
   484  
   485  	return
   486  }
   487  
   488  func validateLogGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
   489  	value := v.(string)
   490  
   491  	if len(value) > 483 {
   492  		errors = append(errors, fmt.Errorf(
   493  			"%q cannot be longer than 483 characters: %q", k, value))
   494  	}
   495  
   496  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html
   497  	pattern := `^[\.\-_/#A-Za-z0-9]+$`
   498  	if !regexp.MustCompile(pattern).MatchString(value) {
   499  		errors = append(errors, fmt.Errorf(
   500  			"%q isn't a valid log group name (alphanumeric characters, underscores,"+
   501  				" hyphens, slashes, hash signs and dots are allowed): %q",
   502  			k, value))
   503  	}
   504  
   505  	return
   506  }
   507  
   508  func validateS3BucketLifecycleTimestamp(v interface{}, k string) (ws []string, errors []error) {
   509  	value := v.(string)
   510  	_, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", value))
   511  	if err != nil {
   512  		errors = append(errors, fmt.Errorf(
   513  			"%q cannot be parsed as RFC3339 Timestamp Format", value))
   514  	}
   515  
   516  	return
   517  }
   518  
   519  func validateS3BucketLifecycleStorageClass(v interface{}, k string) (ws []string, errors []error) {
   520  	value := v.(string)
   521  	if value != s3.TransitionStorageClassStandardIa && value != s3.TransitionStorageClassGlacier {
   522  		errors = append(errors, fmt.Errorf(
   523  			"%q must be one of '%q', '%q'", k, s3.TransitionStorageClassStandardIa, s3.TransitionStorageClassGlacier))
   524  	}
   525  
   526  	return
   527  }
   528  
   529  func validateS3BucketReplicationRuleId(v interface{}, k string) (ws []string, errors []error) {
   530  	value := v.(string)
   531  	if len(value) > 255 {
   532  		errors = append(errors, fmt.Errorf(
   533  			"%q cannot be longer than 255 characters: %q", k, value))
   534  	}
   535  
   536  	return
   537  }
   538  
   539  func validateS3BucketReplicationRulePrefix(v interface{}, k string) (ws []string, errors []error) {
   540  	value := v.(string)
   541  	if len(value) > 1024 {
   542  		errors = append(errors, fmt.Errorf(
   543  			"%q cannot be longer than 1024 characters: %q", k, value))
   544  	}
   545  
   546  	return
   547  }
   548  
   549  func validateS3BucketReplicationDestinationStorageClass(v interface{}, k string) (ws []string, errors []error) {
   550  	value := v.(string)
   551  	if value != s3.StorageClassStandard && value != s3.StorageClassStandardIa && value != s3.StorageClassReducedRedundancy {
   552  		errors = append(errors, fmt.Errorf(
   553  			"%q must be one of '%q', '%q' or '%q'", k, s3.StorageClassStandard, s3.StorageClassStandardIa, s3.StorageClassReducedRedundancy))
   554  	}
   555  
   556  	return
   557  }
   558  
   559  func validateS3BucketReplicationRuleStatus(v interface{}, k string) (ws []string, errors []error) {
   560  	value := v.(string)
   561  	if value != s3.ReplicationRuleStatusEnabled && value != s3.ReplicationRuleStatusDisabled {
   562  		errors = append(errors, fmt.Errorf(
   563  			"%q must be one of '%q' or '%q'", k, s3.ReplicationRuleStatusEnabled, s3.ReplicationRuleStatusDisabled))
   564  	}
   565  
   566  	return
   567  }
   568  
   569  func validateS3BucketLifecycleRuleId(v interface{}, k string) (ws []string, errors []error) {
   570  	value := v.(string)
   571  	if len(value) > 255 {
   572  		errors = append(errors, fmt.Errorf(
   573  			"%q cannot exceed 255 characters", k))
   574  	}
   575  	return
   576  }
   577  
   578  func validateDbEventSubscriptionName(v interface{}, k string) (ws []string, errors []error) {
   579  	value := v.(string)
   580  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   581  		errors = append(errors, fmt.Errorf(
   582  			"only alphanumeric characters and hyphens allowed in %q", k))
   583  	}
   584  	if len(value) > 255 {
   585  		errors = append(errors, fmt.Errorf(
   586  			"%q cannot be longer than 255 characters", k))
   587  	}
   588  	return
   589  }
   590  
   591  func validateApiGatewayIntegrationPassthroughBehavior(v interface{}, k string) (ws []string, errors []error) {
   592  	value := v.(string)
   593  	if value != "WHEN_NO_MATCH" && value != "WHEN_NO_TEMPLATES" && value != "NEVER" {
   594  		errors = append(errors, fmt.Errorf(
   595  			"%q must be one of 'WHEN_NO_MATCH', 'WHEN_NO_TEMPLATES', 'NEVER'", k))
   596  	}
   597  	return
   598  }
   599  
   600  func validateJsonString(v interface{}, k string) (ws []string, errors []error) {
   601  	if _, err := normalizeJsonString(v); err != nil {
   602  		errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
   603  	}
   604  	return
   605  }
   606  
   607  func validateIAMPolicyJson(v interface{}, k string) (ws []string, errors []error) {
   608  	// IAM Policy documents need to be valid JSON, and pass legacy parsing
   609  	value := v.(string)
   610  	if len(value) < 1 {
   611  		errors = append(errors, fmt.Errorf("%q contains an invalid JSON policy", k))
   612  		return
   613  	}
   614  	if value[:1] != "{" {
   615  		errors = append(errors, fmt.Errorf("%q contains an invalid JSON policy", k))
   616  		return
   617  	}
   618  	if _, err := normalizeJsonString(v); err != nil {
   619  		errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
   620  	}
   621  	return
   622  }
   623  
   624  func validateCloudFormationTemplate(v interface{}, k string) (ws []string, errors []error) {
   625  	if looksLikeJsonString(v) {
   626  		if _, err := normalizeJsonString(v); err != nil {
   627  			errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
   628  		}
   629  	} else {
   630  		if _, err := checkYamlString(v); err != nil {
   631  			errors = append(errors, fmt.Errorf("%q contains an invalid YAML: %s", k, err))
   632  		}
   633  	}
   634  	return
   635  }
   636  
   637  func validateApiGatewayIntegrationType(v interface{}, k string) (ws []string, errors []error) {
   638  	value := v.(string)
   639  
   640  	validTypes := map[string]bool{
   641  		"AWS":        true,
   642  		"AWS_PROXY":  true,
   643  		"HTTP":       true,
   644  		"HTTP_PROXY": true,
   645  		"MOCK":       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, %q, %q, %q, or %q.",
   651  			k, value, "AWS", "AWS_PROXY", "HTTP", "HTTP_PROXY", "MOCK"))
   652  	}
   653  	return
   654  }
   655  
   656  func validateApiGatewayIntegrationContentHandling(v interface{}, k string) (ws []string, errors []error) {
   657  	value := v.(string)
   658  
   659  	validTypes := map[string]bool{
   660  		"CONVERT_TO_BINARY": true,
   661  		"CONVERT_TO_TEXT":   true,
   662  	}
   663  
   664  	if _, ok := validTypes[value]; !ok {
   665  		errors = append(errors, fmt.Errorf(
   666  			"%q contains an invalid integration type %q. Valid types are either %q or %q.",
   667  			k, value, "CONVERT_TO_BINARY", "CONVERT_TO_TEXT"))
   668  	}
   669  	return
   670  }
   671  
   672  func validateSQSQueueName(v interface{}, k string) (errors []error) {
   673  	value := v.(string)
   674  	if len(value) > 80 {
   675  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   676  	}
   677  
   678  	if !regexp.MustCompile(`^[0-9A-Za-z-_]+$`).MatchString(value) {
   679  		errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k))
   680  	}
   681  	return
   682  }
   683  
   684  func validateSQSFifoQueueName(v interface{}, k string) (errors []error) {
   685  	value := v.(string)
   686  
   687  	if len(value) > 80 {
   688  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   689  	}
   690  
   691  	if !regexp.MustCompile(`^[0-9A-Za-z-_.]+$`).MatchString(value) {
   692  		errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k))
   693  	}
   694  
   695  	if regexp.MustCompile(`^[^a-zA-Z0-9-_]`).MatchString(value) {
   696  		errors = append(errors, fmt.Errorf("FIFO queue name must start with one of these characters [a-zA-Z0-9-_]: %v", value))
   697  	}
   698  
   699  	if !regexp.MustCompile(`\.fifo$`).MatchString(value) {
   700  		errors = append(errors, fmt.Errorf("FIFO queue name should ends with \".fifo\": %v", value))
   701  	}
   702  
   703  	return
   704  }
   705  
   706  func validateSNSSubscriptionProtocol(v interface{}, k string) (ws []string, errors []error) {
   707  	value := strings.ToLower(v.(string))
   708  	forbidden := []string{"email", "sms"}
   709  	for _, f := range forbidden {
   710  		if strings.Contains(value, f) {
   711  			errors = append(
   712  				errors,
   713  				fmt.Errorf("Unsupported protocol (%s) for SNS Topic", value),
   714  			)
   715  		}
   716  	}
   717  	return
   718  }
   719  
   720  func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) {
   721  	value := strings.ToLower(v.(string))
   722  
   723  	validTypes := map[string]bool{
   724  		"ingress": true,
   725  		"egress":  true,
   726  	}
   727  
   728  	if _, ok := validTypes[value]; !ok {
   729  		errors = append(errors, fmt.Errorf(
   730  			"%q contains an invalid Security Group Rule type %q. Valid types are either %q or %q.",
   731  			k, value, "ingress", "egress"))
   732  	}
   733  	return
   734  }
   735  
   736  func validateOnceAWeekWindowFormat(v interface{}, k string) (ws []string, errors []error) {
   737  	// valid time format is "ddd:hh24:mi"
   738  	validTimeFormat := "(sun|mon|tue|wed|thu|fri|sat):([0-1][0-9]|2[0-3]):([0-5][0-9])"
   739  	validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$"
   740  
   741  	value := strings.ToLower(v.(string))
   742  	if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) {
   743  		errors = append(errors, fmt.Errorf(
   744  			"%q must satisfy the format of \"ddd:hh24:mi-ddd:hh24:mi\".", k))
   745  	}
   746  	return
   747  }
   748  
   749  func validateOnceADayWindowFormat(v interface{}, k string) (ws []string, errors []error) {
   750  	// valid time format is "hh24:mi"
   751  	validTimeFormat := "([0-1][0-9]|2[0-3]):([0-5][0-9])"
   752  	validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$"
   753  
   754  	value := v.(string)
   755  	if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) {
   756  		errors = append(errors, fmt.Errorf(
   757  			"%q must satisfy the format of \"hh24:mi-hh24:mi\".", k))
   758  	}
   759  	return
   760  }
   761  
   762  func validateRoute53RecordType(v interface{}, k string) (ws []string, errors []error) {
   763  	// Valid Record types
   764  	// SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA
   765  	validTypes := map[string]struct{}{
   766  		"SOA":   {},
   767  		"A":     {},
   768  		"TXT":   {},
   769  		"NS":    {},
   770  		"CNAME": {},
   771  		"MX":    {},
   772  		"NAPTR": {},
   773  		"PTR":   {},
   774  		"SRV":   {},
   775  		"SPF":   {},
   776  		"AAAA":  {},
   777  	}
   778  
   779  	value := v.(string)
   780  	if _, ok := validTypes[value]; !ok {
   781  		errors = append(errors, fmt.Errorf(
   782  			"%q must be one of [SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA]", k))
   783  	}
   784  	return
   785  }
   786  
   787  // Validates that ECS Placement Constraints are set correctly
   788  // Takes type, and expression as strings
   789  func validateAwsEcsPlacementConstraint(constType, constExpr string) error {
   790  	switch constType {
   791  	case "distinctInstance":
   792  		// Expression can be nil for distinctInstance
   793  		return nil
   794  	case "memberOf":
   795  		if constExpr == "" {
   796  			return fmt.Errorf("Expression cannot be nil for 'memberOf' type")
   797  		}
   798  	default:
   799  		return fmt.Errorf("Unknown type provided: %q", constType)
   800  	}
   801  	return nil
   802  }
   803  
   804  // Validates that an Ecs placement strategy is set correctly
   805  // Takes type, and field as strings
   806  func validateAwsEcsPlacementStrategy(stratType, stratField string) error {
   807  	switch stratType {
   808  	case "random":
   809  		// random does not need the field attribute set, could error, but it isn't read at the API level
   810  		return nil
   811  	case "spread":
   812  		//  For the spread placement strategy, valid values are instanceId
   813  		// (or host, which has the same effect), or any platform or custom attribute
   814  		// that is applied to a container instance
   815  		// stratField is already cased to a string
   816  		return nil
   817  	case "binpack":
   818  		if stratField != "cpu" && stratField != "memory" {
   819  			return fmt.Errorf("Binpack type requires the field attribute to be either 'cpu' or 'memory'. Got: %s",
   820  				stratField)
   821  		}
   822  	default:
   823  		return fmt.Errorf("Unknown type %s. Must be one of 'random', 'spread', or 'binpack'.", stratType)
   824  	}
   825  	return nil
   826  }
   827  
   828  func validateAwsEmrEbsVolumeType(v interface{}, k string) (ws []string, errors []error) {
   829  	validTypes := map[string]struct{}{
   830  		"gp2":      {},
   831  		"io1":      {},
   832  		"standard": {},
   833  	}
   834  
   835  	value := v.(string)
   836  
   837  	if _, ok := validTypes[value]; !ok {
   838  		errors = append(errors, fmt.Errorf(
   839  			"%q must be one of ['gp2', 'io1', 'standard']", k))
   840  	}
   841  	return
   842  }
   843  
   844  func validateSfnActivityName(v interface{}, k string) (ws []string, errors []error) {
   845  	value := v.(string)
   846  	if len(value) > 80 {
   847  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   848  	}
   849  
   850  	return
   851  }
   852  
   853  func validateSfnStateMachineDefinition(v interface{}, k string) (ws []string, errors []error) {
   854  	value := v.(string)
   855  	if len(value) > 1048576 {
   856  		errors = append(errors, fmt.Errorf("%q cannot be longer than 1048576 characters", k))
   857  	}
   858  	return
   859  }
   860  
   861  func validateSfnStateMachineName(v interface{}, k string) (ws []string, errors []error) {
   862  	value := v.(string)
   863  	if len(value) > 80 {
   864  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   865  	}
   866  
   867  	if !regexp.MustCompile(`^[a-zA-Z0-9-_]+$`).MatchString(value) {
   868  		errors = append(errors, fmt.Errorf(
   869  			"%q must be composed with only these characters [a-zA-Z0-9-_]: %v", k, value))
   870  	}
   871  	return
   872  }
   873  
   874  func validateDmsCertificateId(v interface{}, k string) (ws []string, es []error) {
   875  	val := v.(string)
   876  
   877  	if len(val) > 255 {
   878  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   879  	}
   880  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   881  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   882  	}
   883  	if strings.Contains(val, "--") {
   884  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   885  	}
   886  	if strings.HasSuffix(val, "-") {
   887  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   888  	}
   889  
   890  	return
   891  }
   892  
   893  func validateDmsEndpointId(v interface{}, k string) (ws []string, es []error) {
   894  	val := v.(string)
   895  
   896  	if len(val) > 255 {
   897  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   898  	}
   899  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   900  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   901  	}
   902  	if strings.Contains(val, "--") {
   903  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   904  	}
   905  	if strings.HasSuffix(val, "-") {
   906  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   907  	}
   908  
   909  	return
   910  }
   911  
   912  func validateDmsReplicationInstanceId(v interface{}, k string) (ws []string, es []error) {
   913  	val := v.(string)
   914  
   915  	if len(val) > 63 {
   916  		es = append(es, fmt.Errorf("%q must not be longer than 63 characters", k))
   917  	}
   918  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   919  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   920  	}
   921  	if strings.Contains(val, "--") {
   922  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   923  	}
   924  	if strings.HasSuffix(val, "-") {
   925  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   926  	}
   927  
   928  	return
   929  }
   930  
   931  func validateDmsReplicationSubnetGroupId(v interface{}, k string) (ws []string, es []error) {
   932  	val := v.(string)
   933  
   934  	if val == "default" {
   935  		es = append(es, fmt.Errorf("%q must not be default", k))
   936  	}
   937  	if len(val) > 255 {
   938  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   939  	}
   940  	if !regexp.MustCompile(`^[a-zA-Z0-9. _-]+$`).MatchString(val) {
   941  		es = append(es, fmt.Errorf("%q must only contain alphanumeric characters, periods, spaces, underscores and hyphens", k))
   942  	}
   943  
   944  	return
   945  }
   946  
   947  func validateDmsReplicationTaskId(v interface{}, k string) (ws []string, es []error) {
   948  	val := v.(string)
   949  
   950  	if len(val) > 255 {
   951  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   952  	}
   953  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   954  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   955  	}
   956  	if strings.Contains(val, "--") {
   957  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   958  	}
   959  	if strings.HasSuffix(val, "-") {
   960  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   961  	}
   962  
   963  	return
   964  }
   965  
   966  func validateAppautoscalingScalableDimension(v interface{}, k string) (ws []string, errors []error) {
   967  	value := v.(string)
   968  	dimensions := map[string]bool{
   969  		"ecs:service:DesiredCount":                     true,
   970  		"ec2:spot-fleet-request:TargetCapacity":        true,
   971  		"elasticmapreduce:instancegroup:InstanceCount": true,
   972  	}
   973  
   974  	if !dimensions[value] {
   975  		errors = append(errors, fmt.Errorf("%q must be a valid scalable dimension value: %q", k, value))
   976  	}
   977  	return
   978  }
   979  
   980  func validateAppautoscalingServiceNamespace(v interface{}, k string) (ws []string, errors []error) {
   981  	value := v.(string)
   982  	namespaces := map[string]bool{
   983  		"ecs":              true,
   984  		"ec2":              true,
   985  		"elasticmapreduce": true,
   986  	}
   987  
   988  	if !namespaces[value] {
   989  		errors = append(errors, fmt.Errorf("%q must be a valid service namespace value: %q", k, value))
   990  	}
   991  	return
   992  }
   993  
   994  func validateConfigRuleSourceOwner(v interface{}, k string) (ws []string, errors []error) {
   995  	validOwners := []string{
   996  		"CUSTOM_LAMBDA",
   997  		"AWS",
   998  	}
   999  	owner := v.(string)
  1000  	for _, o := range validOwners {
  1001  		if owner == o {
  1002  			return
  1003  		}
  1004  	}
  1005  	errors = append(errors, fmt.Errorf(
  1006  		"%q contains an invalid owner %q. Valid owners are %q.",
  1007  		k, owner, validOwners))
  1008  	return
  1009  }
  1010  
  1011  func validateConfigExecutionFrequency(v interface{}, k string) (ws []string, errors []error) {
  1012  	validFrequencies := []string{
  1013  		"One_Hour",
  1014  		"Three_Hours",
  1015  		"Six_Hours",
  1016  		"Twelve_Hours",
  1017  		"TwentyFour_Hours",
  1018  	}
  1019  	frequency := v.(string)
  1020  	for _, f := range validFrequencies {
  1021  		if frequency == f {
  1022  			return
  1023  		}
  1024  	}
  1025  	errors = append(errors, fmt.Errorf(
  1026  		"%q contains an invalid frequency %q. Valid frequencies are %q.",
  1027  		k, frequency, validFrequencies))
  1028  	return
  1029  }
  1030  
  1031  func validateAccountAlias(v interface{}, k string) (ws []string, es []error) {
  1032  	val := v.(string)
  1033  
  1034  	if (len(val) < 3) || (len(val) > 63) {
  1035  		es = append(es, fmt.Errorf("%q must contain from 3 to 63 alphanumeric characters or hyphens", k))
  1036  	}
  1037  	if !regexp.MustCompile("^[a-z0-9][a-z0-9-]+$").MatchString(val) {
  1038  		es = append(es, fmt.Errorf("%q must start with an alphanumeric character and only contain lowercase alphanumeric characters and hyphens", k))
  1039  	}
  1040  	if strings.Contains(val, "--") {
  1041  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
  1042  	}
  1043  	if strings.HasSuffix(val, "-") {
  1044  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
  1045  	}
  1046  	return
  1047  }
  1048  
  1049  func validateApiGatewayApiKeyValue(v interface{}, k string) (ws []string, errors []error) {
  1050  	value := v.(string)
  1051  	if len(value) < 30 {
  1052  		errors = append(errors, fmt.Errorf(
  1053  			"%q must be at least 30 characters long", k))
  1054  	}
  1055  	if len(value) > 128 {
  1056  		errors = append(errors, fmt.Errorf(
  1057  			"%q cannot be longer than 128 characters", k))
  1058  	}
  1059  	return
  1060  }
  1061  
  1062  func validateIamRolePolicyName(v interface{}, k string) (ws []string, errors []error) {
  1063  	// https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8291-L8296
  1064  	value := v.(string)
  1065  	if len(value) > 128 {
  1066  		errors = append(errors, fmt.Errorf(
  1067  			"%q cannot be longer than 128 characters", k))
  1068  	}
  1069  	if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
  1070  		errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k))
  1071  	}
  1072  	return
  1073  }
  1074  
  1075  func validateIamRolePolicyNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1076  	value := v.(string)
  1077  	if len(value) > 100 {
  1078  		errors = append(errors, fmt.Errorf(
  1079  			"%q cannot be longer than 100 characters", k))
  1080  	}
  1081  	if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
  1082  		errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k))
  1083  	}
  1084  	return
  1085  }
  1086  
  1087  func validateApiGatewayUsagePlanQuotaSettingsPeriod(v interface{}, k string) (ws []string, errors []error) {
  1088  	validPeriods := []string{
  1089  		apigateway.QuotaPeriodTypeDay,
  1090  		apigateway.QuotaPeriodTypeWeek,
  1091  		apigateway.QuotaPeriodTypeMonth,
  1092  	}
  1093  	period := v.(string)
  1094  	for _, f := range validPeriods {
  1095  		if period == f {
  1096  			return
  1097  		}
  1098  	}
  1099  	errors = append(errors, fmt.Errorf(
  1100  		"%q contains an invalid period %q. Valid period are %q.",
  1101  		k, period, validPeriods))
  1102  	return
  1103  }
  1104  
  1105  func validateApiGatewayUsagePlanQuotaSettings(v map[string]interface{}) (errors []error) {
  1106  	period := v["period"].(string)
  1107  	offset := v["offset"].(int)
  1108  
  1109  	if period == apigateway.QuotaPeriodTypeDay && offset != 0 {
  1110  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be zero in the DAY period"))
  1111  	}
  1112  
  1113  	if period == apigateway.QuotaPeriodTypeWeek && (offset < 0 || offset > 6) {
  1114  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 6 inclusive in the WEEK period"))
  1115  	}
  1116  
  1117  	if period == apigateway.QuotaPeriodTypeMonth && (offset < 0 || offset > 27) {
  1118  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 27 inclusive in the MONTH period"))
  1119  	}
  1120  
  1121  	return
  1122  }
  1123  
  1124  func validateDbSubnetGroupName(v interface{}, k string) (ws []string, errors []error) {
  1125  	value := v.(string)
  1126  	if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
  1127  		errors = append(errors, fmt.Errorf(
  1128  			"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
  1129  	}
  1130  	if len(value) > 255 {
  1131  		errors = append(errors, fmt.Errorf(
  1132  			"%q cannot be longer than 255 characters", k))
  1133  	}
  1134  	if regexp.MustCompile(`(?i)^default$`).MatchString(value) {
  1135  		errors = append(errors, fmt.Errorf(
  1136  			"%q is not allowed as %q", "Default", k))
  1137  	}
  1138  	return
  1139  }
  1140  
  1141  func validateDbSubnetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1142  	value := v.(string)
  1143  	if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
  1144  		errors = append(errors, fmt.Errorf(
  1145  			"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
  1146  	}
  1147  	if len(value) > 229 {
  1148  		errors = append(errors, fmt.Errorf(
  1149  			"%q cannot be longer than 229 characters", k))
  1150  	}
  1151  	return
  1152  }
  1153  
  1154  func validateDbOptionGroupName(v interface{}, k string) (ws []string, errors []error) {
  1155  	value := v.(string)
  1156  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
  1157  		errors = append(errors, fmt.Errorf(
  1158  			"first character of %q must be a letter", k))
  1159  	}
  1160  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
  1161  		errors = append(errors, fmt.Errorf(
  1162  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
  1163  	}
  1164  	if regexp.MustCompile(`--`).MatchString(value) {
  1165  		errors = append(errors, fmt.Errorf(
  1166  			"%q cannot contain two consecutive hyphens", k))
  1167  	}
  1168  	if regexp.MustCompile(`-$`).MatchString(value) {
  1169  		errors = append(errors, fmt.Errorf(
  1170  			"%q cannot end with a hyphen", k))
  1171  	}
  1172  	if len(value) > 255 {
  1173  		errors = append(errors, fmt.Errorf(
  1174  			"%q cannot be greater than 255 characters", k))
  1175  	}
  1176  	return
  1177  }
  1178  
  1179  func validateDbOptionGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1180  	value := v.(string)
  1181  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
  1182  		errors = append(errors, fmt.Errorf(
  1183  			"first character of %q must be a letter", k))
  1184  	}
  1185  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
  1186  		errors = append(errors, fmt.Errorf(
  1187  			"only alphanumeric characters and hyphens allowed in %q", k))
  1188  	}
  1189  	if regexp.MustCompile(`--`).MatchString(value) {
  1190  		errors = append(errors, fmt.Errorf(
  1191  			"%q cannot contain two consecutive hyphens", k))
  1192  	}
  1193  	if len(value) > 229 {
  1194  		errors = append(errors, fmt.Errorf(
  1195  			"%q cannot be greater than 229 characters", k))
  1196  	}
  1197  	return
  1198  }
  1199  
  1200  func validateAwsAlbTargetGroupName(v interface{}, k string) (ws []string, errors []error) {
  1201  	name := v.(string)
  1202  	if len(name) > 32 {
  1203  		errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '32' characters", k, name))
  1204  	}
  1205  	return
  1206  }
  1207  
  1208  func validateAwsAlbTargetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1209  	name := v.(string)
  1210  	if len(name) > 32 {
  1211  		errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '6' characters", k, name))
  1212  	}
  1213  	return
  1214  }
  1215  
  1216  func validateOpenIdURL(v interface{}, k string) (ws []string, errors []error) {
  1217  	value := v.(string)
  1218  	u, err := url.Parse(value)
  1219  	if err != nil {
  1220  		errors = append(errors, fmt.Errorf("%q has to be a valid URL", k))
  1221  		return
  1222  	}
  1223  	if u.Scheme != "https" {
  1224  		errors = append(errors, fmt.Errorf("%q has to use HTTPS scheme (i.e. begin with https://)", k))
  1225  	}
  1226  	if len(u.Query()) > 0 {
  1227  		errors = append(errors, fmt.Errorf("%q cannot contain query parameters per the OIDC standard", k))
  1228  	}
  1229  	return
  1230  }
  1231  
  1232  func validateAwsKmsName(v interface{}, k string) (ws []string, es []error) {
  1233  	value := v.(string)
  1234  	if !regexp.MustCompile(`^(alias\/)[a-zA-Z0-9:/_-]+$`).MatchString(value) {
  1235  		es = append(es, fmt.Errorf(
  1236  			"%q must begin with 'alias/' and be comprised of only [a-zA-Z0-9:/_-]", k))
  1237  	}
  1238  	return
  1239  }
  1240  
  1241  func validateCognitoIdentityPoolName(v interface{}, k string) (ws []string, errors []error) {
  1242  	val := v.(string)
  1243  	if !regexp.MustCompile("^[\\w _]+$").MatchString(val) {
  1244  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters and spaces", k))
  1245  	}
  1246  
  1247  	return
  1248  }
  1249  
  1250  func validateCognitoProviderDeveloperName(v interface{}, k string) (ws []string, errors []error) {
  1251  	value := v.(string)
  1252  	if len(value) > 100 {
  1253  		errors = append(errors, fmt.Errorf("%q cannot be longer than 100 caracters", k))
  1254  	}
  1255  
  1256  	if !regexp.MustCompile("^[\\w._-]+$").MatchString(value) {
  1257  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, underscores and hyphens", k))
  1258  	}
  1259  
  1260  	return
  1261  }
  1262  
  1263  func validateCognitoSupportedLoginProviders(v interface{}, k string) (ws []string, errors []error) {
  1264  	value := v.(string)
  1265  	if len(value) < 1 {
  1266  		errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k))
  1267  	}
  1268  
  1269  	if len(value) > 128 {
  1270  		errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k))
  1271  	}
  1272  
  1273  	if !regexp.MustCompile("^[\\w.;_/-]+$").MatchString(value) {
  1274  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, semicolons, underscores, slashes and hyphens", k))
  1275  	}
  1276  
  1277  	return
  1278  }
  1279  
  1280  func validateCognitoIdentityProvidersClientId(v interface{}, k string) (ws []string, errors []error) {
  1281  	value := v.(string)
  1282  	if len(value) < 1 {
  1283  		errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k))
  1284  	}
  1285  
  1286  	if len(value) > 128 {
  1287  		errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k))
  1288  	}
  1289  
  1290  	if !regexp.MustCompile("^[\\w_]+$").MatchString(value) {
  1291  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters and underscores", k))
  1292  	}
  1293  
  1294  	return
  1295  }
  1296  
  1297  func validateCognitoIdentityProvidersProviderName(v interface{}, k string) (ws []string, errors []error) {
  1298  	value := v.(string)
  1299  	if len(value) < 1 {
  1300  		errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k))
  1301  	}
  1302  
  1303  	if len(value) > 128 {
  1304  		errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k))
  1305  	}
  1306  
  1307  	if !regexp.MustCompile("^[\\w._:/-]+$").MatchString(value) {
  1308  		errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, underscores, colons, slashes and hyphens", k))
  1309  	}
  1310  
  1311  	return
  1312  }
  1313  
  1314  func validateWafMetricName(v interface{}, k string) (ws []string, errors []error) {
  1315  	value := v.(string)
  1316  	if !regexp.MustCompile(`^[0-9A-Za-z]+$`).MatchString(value) {
  1317  		errors = append(errors, fmt.Errorf(
  1318  			"Only alphanumeric characters allowed in %q: %q",
  1319  			k, value))
  1320  	}
  1321  	return
  1322  }
  1323  
  1324  func validateIamRoleDescription(v interface{}, k string) (ws []string, errors []error) {
  1325  	value := v.(string)
  1326  
  1327  	if len(value) > 1000 {
  1328  		errors = append(errors, fmt.Errorf("%q cannot be longer than 1000 caracters", k))
  1329  	}
  1330  
  1331  	if !regexp.MustCompile(`[\p{L}\p{M}\p{Z}\p{S}\p{N}\p{P}]*`).MatchString(value) {
  1332  		errors = append(errors, fmt.Errorf(
  1333  			"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}]*)",
  1334  			k, value))
  1335  	}
  1336  	return
  1337  }
  1338  
  1339  func validateSsmParameterType(v interface{}, k string) (ws []string, errors []error) {
  1340  	value := v.(string)
  1341  	types := map[string]bool{
  1342  		"String":       true,
  1343  		"StringList":   true,
  1344  		"SecureString": true,
  1345  	}
  1346  
  1347  	if !types[value] {
  1348  		errors = append(errors, fmt.Errorf("Parameter type %s is invalid. Valid types are String, StringList or SecureString", value))
  1349  	}
  1350  	return
  1351  }