github.com/cbroglie/terraform@v0.7.0-rc3.0.20170410193827-735dfc416d46/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 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}-[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 validateS3BucketLifecycleTimestamp(v interface{}, k string) (ws []string, errors []error) {
   487  	value := v.(string)
   488  	_, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", value))
   489  	if err != nil {
   490  		errors = append(errors, fmt.Errorf(
   491  			"%q cannot be parsed as RFC3339 Timestamp Format", value))
   492  	}
   493  
   494  	return
   495  }
   496  
   497  func validateS3BucketLifecycleStorageClass(v interface{}, k string) (ws []string, errors []error) {
   498  	value := v.(string)
   499  	if value != s3.TransitionStorageClassStandardIa && value != s3.TransitionStorageClassGlacier {
   500  		errors = append(errors, fmt.Errorf(
   501  			"%q must be one of '%q', '%q'", k, s3.TransitionStorageClassStandardIa, s3.TransitionStorageClassGlacier))
   502  	}
   503  
   504  	return
   505  }
   506  
   507  func validateS3BucketReplicationRuleId(v interface{}, k string) (ws []string, errors []error) {
   508  	value := v.(string)
   509  	if len(value) > 255 {
   510  		errors = append(errors, fmt.Errorf(
   511  			"%q cannot be longer than 255 characters: %q", k, value))
   512  	}
   513  
   514  	return
   515  }
   516  
   517  func validateS3BucketReplicationRulePrefix(v interface{}, k string) (ws []string, errors []error) {
   518  	value := v.(string)
   519  	if len(value) > 1024 {
   520  		errors = append(errors, fmt.Errorf(
   521  			"%q cannot be longer than 1024 characters: %q", k, value))
   522  	}
   523  
   524  	return
   525  }
   526  
   527  func validateS3BucketReplicationDestinationStorageClass(v interface{}, k string) (ws []string, errors []error) {
   528  	value := v.(string)
   529  	if value != s3.StorageClassStandard && value != s3.StorageClassStandardIa && value != s3.StorageClassReducedRedundancy {
   530  		errors = append(errors, fmt.Errorf(
   531  			"%q must be one of '%q', '%q' or '%q'", k, s3.StorageClassStandard, s3.StorageClassStandardIa, s3.StorageClassReducedRedundancy))
   532  	}
   533  
   534  	return
   535  }
   536  
   537  func validateS3BucketReplicationRuleStatus(v interface{}, k string) (ws []string, errors []error) {
   538  	value := v.(string)
   539  	if value != s3.ReplicationRuleStatusEnabled && value != s3.ReplicationRuleStatusDisabled {
   540  		errors = append(errors, fmt.Errorf(
   541  			"%q must be one of '%q' or '%q'", k, s3.ReplicationRuleStatusEnabled, s3.ReplicationRuleStatusDisabled))
   542  	}
   543  
   544  	return
   545  }
   546  
   547  func validateS3BucketLifecycleRuleId(v interface{}, k string) (ws []string, errors []error) {
   548  	value := v.(string)
   549  	if len(value) > 255 {
   550  		errors = append(errors, fmt.Errorf(
   551  			"%q cannot exceed 255 characters", k))
   552  	}
   553  	return
   554  }
   555  
   556  func validateDbEventSubscriptionName(v interface{}, k string) (ws []string, errors []error) {
   557  	value := v.(string)
   558  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   559  		errors = append(errors, fmt.Errorf(
   560  			"only alphanumeric characters and hyphens allowed in %q", k))
   561  	}
   562  	if len(value) > 255 {
   563  		errors = append(errors, fmt.Errorf(
   564  			"%q cannot be longer than 255 characters", k))
   565  	}
   566  	return
   567  }
   568  
   569  func validateApiGatewayIntegrationPassthroughBehavior(v interface{}, k string) (ws []string, errors []error) {
   570  	value := v.(string)
   571  	if value != "WHEN_NO_MATCH" && value != "WHEN_NO_TEMPLATES" && value != "NEVER" {
   572  		errors = append(errors, fmt.Errorf(
   573  			"%q must be one of 'WHEN_NO_MATCH', 'WHEN_NO_TEMPLATES', 'NEVER'", k))
   574  	}
   575  	return
   576  }
   577  
   578  func validateJsonString(v interface{}, k string) (ws []string, errors []error) {
   579  	if _, err := normalizeJsonString(v); err != nil {
   580  		errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
   581  	}
   582  	return
   583  }
   584  
   585  func validateCloudFormationTemplate(v interface{}, k string) (ws []string, errors []error) {
   586  	if looksLikeJsonString(v) {
   587  		if _, err := normalizeJsonString(v); err != nil {
   588  			errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
   589  		}
   590  	} else {
   591  		if _, err := checkYamlString(v); err != nil {
   592  			errors = append(errors, fmt.Errorf("%q contains an invalid YAML: %s", k, err))
   593  		}
   594  	}
   595  	return
   596  }
   597  
   598  func validateApiGatewayIntegrationType(v interface{}, k string) (ws []string, errors []error) {
   599  	value := v.(string)
   600  
   601  	validTypes := map[string]bool{
   602  		"AWS":        true,
   603  		"AWS_PROXY":  true,
   604  		"HTTP":       true,
   605  		"HTTP_PROXY": true,
   606  		"MOCK":       true,
   607  	}
   608  
   609  	if _, ok := validTypes[value]; !ok {
   610  		errors = append(errors, fmt.Errorf(
   611  			"%q contains an invalid integration type %q. Valid types are either %q, %q, %q, %q, or %q.",
   612  			k, value, "AWS", "AWS_PROXY", "HTTP", "HTTP_PROXY", "MOCK"))
   613  	}
   614  	return
   615  }
   616  
   617  func validateApiGatewayIntegrationContentHandling(v interface{}, k string) (ws []string, errors []error) {
   618  	value := v.(string)
   619  
   620  	validTypes := map[string]bool{
   621  		"CONVERT_TO_BINARY": true,
   622  		"CONVERT_TO_TEXT":   true,
   623  	}
   624  
   625  	if _, ok := validTypes[value]; !ok {
   626  		errors = append(errors, fmt.Errorf(
   627  			"%q contains an invalid integration type %q. Valid types are either %q or %q.",
   628  			k, value, "CONVERT_TO_BINARY", "CONVERT_TO_TEXT"))
   629  	}
   630  	return
   631  }
   632  
   633  func validateSQSQueueName(v interface{}, k string) (errors []error) {
   634  	value := v.(string)
   635  	if len(value) > 80 {
   636  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   637  	}
   638  
   639  	if !regexp.MustCompile(`^[0-9A-Za-z-_]+$`).MatchString(value) {
   640  		errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k))
   641  	}
   642  	return
   643  }
   644  
   645  func validateSQSFifoQueueName(v interface{}, k string) (errors []error) {
   646  	value := v.(string)
   647  
   648  	if len(value) > 80 {
   649  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   650  	}
   651  
   652  	if !regexp.MustCompile(`^[0-9A-Za-z-_.]+$`).MatchString(value) {
   653  		errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k))
   654  	}
   655  
   656  	if regexp.MustCompile(`^[^a-zA-Z0-9-_]`).MatchString(value) {
   657  		errors = append(errors, fmt.Errorf("FIFO queue name must start with one of these characters [a-zA-Z0-9-_]: %v", value))
   658  	}
   659  
   660  	if !regexp.MustCompile(`\.fifo$`).MatchString(value) {
   661  		errors = append(errors, fmt.Errorf("FIFO queue name should ends with \".fifo\": %v", value))
   662  	}
   663  
   664  	return
   665  }
   666  
   667  func validateSNSSubscriptionProtocol(v interface{}, k string) (ws []string, errors []error) {
   668  	value := strings.ToLower(v.(string))
   669  	forbidden := []string{"email", "sms"}
   670  	for _, f := range forbidden {
   671  		if strings.Contains(value, f) {
   672  			errors = append(
   673  				errors,
   674  				fmt.Errorf("Unsupported protocol (%s) for SNS Topic", value),
   675  			)
   676  		}
   677  	}
   678  	return
   679  }
   680  
   681  func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) {
   682  	value := strings.ToLower(v.(string))
   683  
   684  	validTypes := map[string]bool{
   685  		"ingress": true,
   686  		"egress":  true,
   687  	}
   688  
   689  	if _, ok := validTypes[value]; !ok {
   690  		errors = append(errors, fmt.Errorf(
   691  			"%q contains an invalid Security Group Rule type %q. Valid types are either %q or %q.",
   692  			k, value, "ingress", "egress"))
   693  	}
   694  	return
   695  }
   696  
   697  func validateOnceAWeekWindowFormat(v interface{}, k string) (ws []string, errors []error) {
   698  	// valid time format is "ddd:hh24:mi"
   699  	validTimeFormat := "(sun|mon|tue|wed|thu|fri|sat):([0-1][0-9]|2[0-3]):([0-5][0-9])"
   700  	validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$"
   701  
   702  	value := strings.ToLower(v.(string))
   703  	if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) {
   704  		errors = append(errors, fmt.Errorf(
   705  			"%q must satisfy the format of \"ddd:hh24:mi-ddd:hh24:mi\".", k))
   706  	}
   707  	return
   708  }
   709  
   710  func validateOnceADayWindowFormat(v interface{}, k string) (ws []string, errors []error) {
   711  	// valid time format is "hh24:mi"
   712  	validTimeFormat := "([0-1][0-9]|2[0-3]):([0-5][0-9])"
   713  	validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$"
   714  
   715  	value := v.(string)
   716  	if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) {
   717  		errors = append(errors, fmt.Errorf(
   718  			"%q must satisfy the format of \"hh24:mi-hh24:mi\".", k))
   719  	}
   720  	return
   721  }
   722  
   723  func validateRoute53RecordType(v interface{}, k string) (ws []string, errors []error) {
   724  	// Valid Record types
   725  	// SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA
   726  	validTypes := map[string]struct{}{
   727  		"SOA":   {},
   728  		"A":     {},
   729  		"TXT":   {},
   730  		"NS":    {},
   731  		"CNAME": {},
   732  		"MX":    {},
   733  		"NAPTR": {},
   734  		"PTR":   {},
   735  		"SRV":   {},
   736  		"SPF":   {},
   737  		"AAAA":  {},
   738  	}
   739  
   740  	value := v.(string)
   741  	if _, ok := validTypes[value]; !ok {
   742  		errors = append(errors, fmt.Errorf(
   743  			"%q must be one of [SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA]", k))
   744  	}
   745  	return
   746  }
   747  
   748  // Validates that ECS Placement Constraints are set correctly
   749  // Takes type, and expression as strings
   750  func validateAwsEcsPlacementConstraint(constType, constExpr string) error {
   751  	switch constType {
   752  	case "distinctInstance":
   753  		// Expression can be nil for distinctInstance
   754  		return nil
   755  	case "memberOf":
   756  		if constExpr == "" {
   757  			return fmt.Errorf("Expression cannot be nil for 'memberOf' type")
   758  		}
   759  	default:
   760  		return fmt.Errorf("Unknown type provided: %q", constType)
   761  	}
   762  	return nil
   763  }
   764  
   765  // Validates that an Ecs placement strategy is set correctly
   766  // Takes type, and field as strings
   767  func validateAwsEcsPlacementStrategy(stratType, stratField string) error {
   768  	switch stratType {
   769  	case "random":
   770  		// random does not need the field attribute set, could error, but it isn't read at the API level
   771  		return nil
   772  	case "spread":
   773  		//  For the spread placement strategy, valid values are instanceId
   774  		// (or host, which has the same effect), or any platform or custom attribute
   775  		// that is applied to a container instance
   776  		// stratField is already cased to a string
   777  		return nil
   778  	case "binpack":
   779  		if stratField != "cpu" && stratField != "memory" {
   780  			return fmt.Errorf("Binpack type requires the field attribute to be either 'cpu' or 'memory'. Got: %s",
   781  				stratField)
   782  		}
   783  	default:
   784  		return fmt.Errorf("Unknown type %s. Must be one of 'random', 'spread', or 'binpack'.", stratType)
   785  	}
   786  	return nil
   787  }
   788  
   789  func validateAwsEmrEbsVolumeType(v interface{}, k string) (ws []string, errors []error) {
   790  	validTypes := map[string]struct{}{
   791  		"gp2":      {},
   792  		"io1":      {},
   793  		"standard": {},
   794  	}
   795  
   796  	value := v.(string)
   797  
   798  	if _, ok := validTypes[value]; !ok {
   799  		errors = append(errors, fmt.Errorf(
   800  			"%q must be one of ['gp2', 'io1', 'standard']", k))
   801  	}
   802  	return
   803  }
   804  
   805  func validateSfnActivityName(v interface{}, k string) (ws []string, errors []error) {
   806  	value := v.(string)
   807  	if len(value) > 80 {
   808  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   809  	}
   810  
   811  	return
   812  }
   813  
   814  func validateSfnStateMachineDefinition(v interface{}, k string) (ws []string, errors []error) {
   815  	value := v.(string)
   816  	if len(value) > 1048576 {
   817  		errors = append(errors, fmt.Errorf("%q cannot be longer than 1048576 characters", k))
   818  	}
   819  	return
   820  }
   821  
   822  func validateSfnStateMachineName(v interface{}, k string) (ws []string, errors []error) {
   823  	value := v.(string)
   824  	if len(value) > 80 {
   825  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   826  	}
   827  
   828  	if !regexp.MustCompile(`^[a-zA-Z0-9-_]+$`).MatchString(value) {
   829  		errors = append(errors, fmt.Errorf(
   830  			"%q must be composed with only these characters [a-zA-Z0-9-_]: %v", k, value))
   831  	}
   832  	return
   833  }
   834  
   835  func validateDmsCertificateId(v interface{}, k string) (ws []string, es []error) {
   836  	val := v.(string)
   837  
   838  	if len(val) > 255 {
   839  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   840  	}
   841  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   842  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   843  	}
   844  	if strings.Contains(val, "--") {
   845  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   846  	}
   847  	if strings.HasSuffix(val, "-") {
   848  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   849  	}
   850  
   851  	return
   852  }
   853  
   854  func validateDmsEndpointId(v interface{}, k string) (ws []string, es []error) {
   855  	val := v.(string)
   856  
   857  	if len(val) > 255 {
   858  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   859  	}
   860  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   861  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   862  	}
   863  	if strings.Contains(val, "--") {
   864  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   865  	}
   866  	if strings.HasSuffix(val, "-") {
   867  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   868  	}
   869  
   870  	return
   871  }
   872  
   873  func validateDmsReplicationInstanceId(v interface{}, k string) (ws []string, es []error) {
   874  	val := v.(string)
   875  
   876  	if len(val) > 63 {
   877  		es = append(es, fmt.Errorf("%q must not be longer than 63 characters", k))
   878  	}
   879  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   880  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   881  	}
   882  	if strings.Contains(val, "--") {
   883  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   884  	}
   885  	if strings.HasSuffix(val, "-") {
   886  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   887  	}
   888  
   889  	return
   890  }
   891  
   892  func validateDmsReplicationSubnetGroupId(v interface{}, k string) (ws []string, es []error) {
   893  	val := v.(string)
   894  
   895  	if val == "default" {
   896  		es = append(es, fmt.Errorf("%q must not be default", k))
   897  	}
   898  	if len(val) > 255 {
   899  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   900  	}
   901  	if !regexp.MustCompile(`^[a-zA-Z0-9. _-]+$`).MatchString(val) {
   902  		es = append(es, fmt.Errorf("%q must only contain alphanumeric characters, periods, spaces, underscores and hyphens", k))
   903  	}
   904  
   905  	return
   906  }
   907  
   908  func validateDmsReplicationTaskId(v interface{}, k string) (ws []string, es []error) {
   909  	val := v.(string)
   910  
   911  	if len(val) > 255 {
   912  		es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k))
   913  	}
   914  	if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) {
   915  		es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k))
   916  	}
   917  	if strings.Contains(val, "--") {
   918  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
   919  	}
   920  	if strings.HasSuffix(val, "-") {
   921  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
   922  	}
   923  
   924  	return
   925  }
   926  
   927  func validateAppautoscalingScalableDimension(v interface{}, k string) (ws []string, errors []error) {
   928  	value := v.(string)
   929  	dimensions := map[string]bool{
   930  		"ecs:service:DesiredCount":                     true,
   931  		"ec2:spot-fleet-request:TargetCapacity":        true,
   932  		"elasticmapreduce:instancegroup:InstanceCount": true,
   933  	}
   934  
   935  	if !dimensions[value] {
   936  		errors = append(errors, fmt.Errorf("%q must be a valid scalable dimension value: %q", k, value))
   937  	}
   938  	return
   939  }
   940  
   941  func validateAppautoscalingServiceNamespace(v interface{}, k string) (ws []string, errors []error) {
   942  	value := v.(string)
   943  	namespaces := map[string]bool{
   944  		"ecs":              true,
   945  		"ec2":              true,
   946  		"elasticmapreduce": true,
   947  	}
   948  
   949  	if !namespaces[value] {
   950  		errors = append(errors, fmt.Errorf("%q must be a valid service namespace value: %q", k, value))
   951  	}
   952  	return
   953  }
   954  
   955  func validateConfigRuleSourceOwner(v interface{}, k string) (ws []string, errors []error) {
   956  	validOwners := []string{
   957  		"CUSTOM_LAMBDA",
   958  		"AWS",
   959  	}
   960  	owner := v.(string)
   961  	for _, o := range validOwners {
   962  		if owner == o {
   963  			return
   964  		}
   965  	}
   966  	errors = append(errors, fmt.Errorf(
   967  		"%q contains an invalid owner %q. Valid owners are %q.",
   968  		k, owner, validOwners))
   969  	return
   970  }
   971  
   972  func validateConfigExecutionFrequency(v interface{}, k string) (ws []string, errors []error) {
   973  	validFrequencies := []string{
   974  		"One_Hour",
   975  		"Three_Hours",
   976  		"Six_Hours",
   977  		"Twelve_Hours",
   978  		"TwentyFour_Hours",
   979  	}
   980  	frequency := v.(string)
   981  	for _, f := range validFrequencies {
   982  		if frequency == f {
   983  			return
   984  		}
   985  	}
   986  	errors = append(errors, fmt.Errorf(
   987  		"%q contains an invalid frequency %q. Valid frequencies are %q.",
   988  		k, frequency, validFrequencies))
   989  	return
   990  }
   991  
   992  func validateAccountAlias(v interface{}, k string) (ws []string, es []error) {
   993  	val := v.(string)
   994  
   995  	if (len(val) < 3) || (len(val) > 63) {
   996  		es = append(es, fmt.Errorf("%q must contain from 3 to 63 alphanumeric characters or hyphens", k))
   997  	}
   998  	if !regexp.MustCompile("^[a-z0-9][a-z0-9-]+$").MatchString(val) {
   999  		es = append(es, fmt.Errorf("%q must start with an alphanumeric character and only contain lowercase alphanumeric characters and hyphens", k))
  1000  	}
  1001  	if strings.Contains(val, "--") {
  1002  		es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k))
  1003  	}
  1004  	if strings.HasSuffix(val, "-") {
  1005  		es = append(es, fmt.Errorf("%q must not end in a hyphen", k))
  1006  	}
  1007  	return
  1008  }
  1009  
  1010  func validateApiGatewayApiKeyValue(v interface{}, k string) (ws []string, errors []error) {
  1011  	value := v.(string)
  1012  	if len(value) < 30 {
  1013  		errors = append(errors, fmt.Errorf(
  1014  			"%q must be at least 30 characters long", k))
  1015  	}
  1016  	if len(value) > 128 {
  1017  		errors = append(errors, fmt.Errorf(
  1018  			"%q cannot be longer than 128 characters", k))
  1019  	}
  1020  	return
  1021  }
  1022  
  1023  func validateIamRolePolicyName(v interface{}, k string) (ws []string, errors []error) {
  1024  	// https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8291-L8296
  1025  	value := v.(string)
  1026  	if len(value) > 128 {
  1027  		errors = append(errors, fmt.Errorf(
  1028  			"%q cannot be longer than 128 characters", k))
  1029  	}
  1030  	if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
  1031  		errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k))
  1032  	}
  1033  	return
  1034  }
  1035  
  1036  func validateIamRolePolicyNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1037  	value := v.(string)
  1038  	if len(value) > 100 {
  1039  		errors = append(errors, fmt.Errorf(
  1040  			"%q cannot be longer than 100 characters", k))
  1041  	}
  1042  	if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
  1043  		errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k))
  1044  	}
  1045  	return
  1046  }
  1047  
  1048  func validateApiGatewayUsagePlanQuotaSettingsPeriod(v interface{}, k string) (ws []string, errors []error) {
  1049  	validPeriods := []string{
  1050  		apigateway.QuotaPeriodTypeDay,
  1051  		apigateway.QuotaPeriodTypeWeek,
  1052  		apigateway.QuotaPeriodTypeMonth,
  1053  	}
  1054  	period := v.(string)
  1055  	for _, f := range validPeriods {
  1056  		if period == f {
  1057  			return
  1058  		}
  1059  	}
  1060  	errors = append(errors, fmt.Errorf(
  1061  		"%q contains an invalid period %q. Valid period are %q.",
  1062  		k, period, validPeriods))
  1063  	return
  1064  }
  1065  
  1066  func validateApiGatewayUsagePlanQuotaSettings(v map[string]interface{}) (errors []error) {
  1067  	period := v["period"].(string)
  1068  	offset := v["offset"].(int)
  1069  
  1070  	if period == apigateway.QuotaPeriodTypeDay && offset != 0 {
  1071  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be zero in the DAY period"))
  1072  	}
  1073  
  1074  	if period == apigateway.QuotaPeriodTypeWeek && (offset < 0 || offset > 6) {
  1075  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 6 inclusive in the WEEK period"))
  1076  	}
  1077  
  1078  	if period == apigateway.QuotaPeriodTypeMonth && (offset < 0 || offset > 27) {
  1079  		errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 27 inclusive in the MONTH period"))
  1080  	}
  1081  
  1082  	return
  1083  }
  1084  
  1085  func validateDbSubnetGroupName(v interface{}, k string) (ws []string, errors []error) {
  1086  	value := v.(string)
  1087  	if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
  1088  		errors = append(errors, fmt.Errorf(
  1089  			"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
  1090  	}
  1091  	if len(value) > 255 {
  1092  		errors = append(errors, fmt.Errorf(
  1093  			"%q cannot be longer than 255 characters", k))
  1094  	}
  1095  	if regexp.MustCompile(`(?i)^default$`).MatchString(value) {
  1096  		errors = append(errors, fmt.Errorf(
  1097  			"%q is not allowed as %q", "Default", k))
  1098  	}
  1099  	return
  1100  }
  1101  
  1102  func validateDbSubnetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1103  	value := v.(string)
  1104  	if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
  1105  		errors = append(errors, fmt.Errorf(
  1106  			"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
  1107  	}
  1108  	if len(value) > 229 {
  1109  		errors = append(errors, fmt.Errorf(
  1110  			"%q cannot be longer than 229 characters", k))
  1111  	}
  1112  	return
  1113  }
  1114  
  1115  func validateDbOptionGroupName(v interface{}, k string) (ws []string, errors []error) {
  1116  	value := v.(string)
  1117  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
  1118  		errors = append(errors, fmt.Errorf(
  1119  			"first character of %q must be a letter", k))
  1120  	}
  1121  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
  1122  		errors = append(errors, fmt.Errorf(
  1123  			"only alphanumeric characters and hyphens allowed in %q", k))
  1124  	}
  1125  	if regexp.MustCompile(`--`).MatchString(value) {
  1126  		errors = append(errors, fmt.Errorf(
  1127  			"%q cannot contain two consecutive hyphens", k))
  1128  	}
  1129  	if regexp.MustCompile(`-$`).MatchString(value) {
  1130  		errors = append(errors, fmt.Errorf(
  1131  			"%q cannot end with a hyphen", k))
  1132  	}
  1133  	if len(value) > 255 {
  1134  		errors = append(errors, fmt.Errorf(
  1135  			"%q cannot be greater than 255 characters", k))
  1136  	}
  1137  	return
  1138  }
  1139  
  1140  func validateDbOptionGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1141  	value := v.(string)
  1142  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
  1143  		errors = append(errors, fmt.Errorf(
  1144  			"first character of %q must be a letter", k))
  1145  	}
  1146  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
  1147  		errors = append(errors, fmt.Errorf(
  1148  			"only alphanumeric characters and hyphens allowed in %q", k))
  1149  	}
  1150  	if regexp.MustCompile(`--`).MatchString(value) {
  1151  		errors = append(errors, fmt.Errorf(
  1152  			"%q cannot contain two consecutive hyphens", k))
  1153  	}
  1154  	if len(value) > 229 {
  1155  		errors = append(errors, fmt.Errorf(
  1156  			"%q cannot be greater than 229 characters", k))
  1157  	}
  1158  	return
  1159  }
  1160  
  1161  func validateAwsAlbTargetGroupName(v interface{}, k string) (ws []string, errors []error) {
  1162  	name := v.(string)
  1163  	if len(name) > 32 {
  1164  		errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '32' characters", k, name))
  1165  	}
  1166  	return
  1167  }
  1168  
  1169  func validateAwsAlbTargetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
  1170  	name := v.(string)
  1171  	if len(name) > 32 {
  1172  		errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '6' characters", k, name))
  1173  	}
  1174  	return
  1175  }
  1176  
  1177  func validateOpenIdURL(v interface{}, k string) (ws []string, errors []error) {
  1178  	value := v.(string)
  1179  	u, err := url.Parse(value)
  1180  	if err != nil {
  1181  		errors = append(errors, fmt.Errorf("%q has to be a valid URL", k))
  1182  		return
  1183  	}
  1184  	if u.Scheme != "https" {
  1185  		errors = append(errors, fmt.Errorf("%q has to use HTTPS scheme (i.e. begin with https://)", k))
  1186  	}
  1187  	if len(u.Query()) > 0 {
  1188  		errors = append(errors, fmt.Errorf("%q cannot contain query parameters per the OIDC standard", k))
  1189  	}
  1190  	return
  1191  }