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