github.com/recobe182/terraform@v0.8.5-0.20170117231232-49ab22a935b7/builtin/providers/aws/validators.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"regexp"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/aws/aws-sdk-go/service/s3"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  func validateRdsId(v interface{}, k string) (ws []string, errors []error) {
    15  	value := v.(string)
    16  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
    17  		errors = append(errors, fmt.Errorf(
    18  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
    19  	}
    20  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
    21  		errors = append(errors, fmt.Errorf(
    22  			"first character of %q must be a letter", k))
    23  	}
    24  	if regexp.MustCompile(`--`).MatchString(value) {
    25  		errors = append(errors, fmt.Errorf(
    26  			"%q cannot contain two consecutive hyphens", k))
    27  	}
    28  	if regexp.MustCompile(`-$`).MatchString(value) {
    29  		errors = append(errors, fmt.Errorf(
    30  			"%q cannot end with a hyphen", k))
    31  	}
    32  	return
    33  }
    34  
    35  func validateElastiCacheClusterId(v interface{}, k string) (ws []string, errors []error) {
    36  	value := v.(string)
    37  	if (len(value) < 1) || (len(value) > 20) {
    38  		errors = append(errors, fmt.Errorf(
    39  			"%q must contain from 1 to 20 alphanumeric characters or hyphens", k))
    40  	}
    41  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
    42  		errors = append(errors, fmt.Errorf(
    43  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
    44  	}
    45  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
    46  		errors = append(errors, fmt.Errorf(
    47  			"first character of %q must be a letter", k))
    48  	}
    49  	if regexp.MustCompile(`--`).MatchString(value) {
    50  		errors = append(errors, fmt.Errorf(
    51  			"%q cannot contain two consecutive hyphens", k))
    52  	}
    53  	if regexp.MustCompile(`-$`).MatchString(value) {
    54  		errors = append(errors, fmt.Errorf(
    55  			"%q cannot end with a hyphen", k))
    56  	}
    57  	return
    58  }
    59  
    60  func validateASGScheduleTimestamp(v interface{}, k string) (ws []string, errors []error) {
    61  	value := v.(string)
    62  	_, err := time.Parse(awsAutoscalingScheduleTimeLayout, value)
    63  	if err != nil {
    64  		errors = append(errors, fmt.Errorf(
    65  			"%q cannot be parsed as iso8601 Timestamp Format", value))
    66  	}
    67  
    68  	return
    69  }
    70  
    71  // validateTagFilters confirms the "value" component of a tag filter is one of
    72  // AWS's three allowed types.
    73  func validateTagFilters(v interface{}, k string) (ws []string, errors []error) {
    74  	value := v.(string)
    75  	if value != "KEY_ONLY" && value != "VALUE_ONLY" && value != "KEY_AND_VALUE" {
    76  		errors = append(errors, fmt.Errorf(
    77  			"%q must be one of \"KEY_ONLY\", \"VALUE_ONLY\", or \"KEY_AND_VALUE\"", k))
    78  	}
    79  	return
    80  }
    81  
    82  func validateDbParamGroupName(v interface{}, k string) (ws []string, errors []error) {
    83  	value := v.(string)
    84  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
    85  		errors = append(errors, fmt.Errorf(
    86  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
    87  	}
    88  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
    89  		errors = append(errors, fmt.Errorf(
    90  			"first character of %q must be a letter", k))
    91  	}
    92  	if regexp.MustCompile(`--`).MatchString(value) {
    93  		errors = append(errors, fmt.Errorf(
    94  			"%q cannot contain two consecutive hyphens", k))
    95  	}
    96  	if regexp.MustCompile(`-$`).MatchString(value) {
    97  		errors = append(errors, fmt.Errorf(
    98  			"%q cannot end with a hyphen", k))
    99  	}
   100  	if len(value) > 255 {
   101  		errors = append(errors, fmt.Errorf(
   102  			"%q cannot be greater than 255 characters", k))
   103  	}
   104  	return
   105  
   106  }
   107  
   108  func validateStreamViewType(v interface{}, k string) (ws []string, errors []error) {
   109  	value := v.(string)
   110  	viewTypes := map[string]bool{
   111  		"KEYS_ONLY":          true,
   112  		"NEW_IMAGE":          true,
   113  		"OLD_IMAGE":          true,
   114  		"NEW_AND_OLD_IMAGES": true,
   115  	}
   116  
   117  	if !viewTypes[value] {
   118  		errors = append(errors, fmt.Errorf("%q be a valid DynamoDB StreamViewType", k))
   119  	}
   120  	return
   121  }
   122  
   123  func validateElbName(v interface{}, k string) (ws []string, errors []error) {
   124  	value := v.(string)
   125  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   126  		errors = append(errors, fmt.Errorf(
   127  			"only alphanumeric characters and hyphens allowed in %q: %q",
   128  			k, value))
   129  	}
   130  	if len(value) > 32 {
   131  		errors = append(errors, fmt.Errorf(
   132  			"%q cannot be longer than 32 characters: %q", k, value))
   133  	}
   134  	if regexp.MustCompile(`^-`).MatchString(value) {
   135  		errors = append(errors, fmt.Errorf(
   136  			"%q cannot begin with a hyphen: %q", k, value))
   137  	}
   138  	if regexp.MustCompile(`-$`).MatchString(value) {
   139  		errors = append(errors, fmt.Errorf(
   140  			"%q cannot end with a hyphen: %q", k, value))
   141  	}
   142  	return
   143  
   144  }
   145  
   146  func validateEcrRepositoryName(v interface{}, k string) (ws []string, errors []error) {
   147  	value := v.(string)
   148  	if len(value) < 2 {
   149  		errors = append(errors, fmt.Errorf(
   150  			"%q must be at least 2 characters long: %q", k, value))
   151  	}
   152  	if len(value) > 256 {
   153  		errors = append(errors, fmt.Errorf(
   154  			"%q cannot be longer than 256 characters: %q", k, value))
   155  	}
   156  
   157  	// http://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_CreateRepository.html
   158  	pattern := `^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)*[a-z0-9]+(?:[._-][a-z0-9]+)*$`
   159  	if !regexp.MustCompile(pattern).MatchString(value) {
   160  		errors = append(errors, fmt.Errorf(
   161  			"%q doesn't comply with restrictions (%q): %q",
   162  			k, pattern, value))
   163  	}
   164  
   165  	return
   166  }
   167  
   168  func validateCloudWatchEventRuleName(v interface{}, k string) (ws []string, errors []error) {
   169  	value := v.(string)
   170  	if len(value) > 64 {
   171  		errors = append(errors, fmt.Errorf(
   172  			"%q cannot be longer than 64 characters: %q", k, value))
   173  	}
   174  
   175  	// http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_PutRule.html
   176  	pattern := `^[\.\-_A-Za-z0-9]+$`
   177  	if !regexp.MustCompile(pattern).MatchString(value) {
   178  		errors = append(errors, fmt.Errorf(
   179  			"%q doesn't comply with restrictions (%q): %q",
   180  			k, pattern, value))
   181  	}
   182  
   183  	return
   184  }
   185  
   186  func validateMaxLength(length int) schema.SchemaValidateFunc {
   187  	return func(v interface{}, k string) (ws []string, errors []error) {
   188  		value := v.(string)
   189  		if len(value) > length {
   190  			errors = append(errors, fmt.Errorf(
   191  				"%q cannot be longer than %d characters: %q", k, length, value))
   192  		}
   193  		return
   194  	}
   195  }
   196  
   197  func validateIntegerInRange(min, max int) schema.SchemaValidateFunc {
   198  	return func(v interface{}, k string) (ws []string, errors []error) {
   199  		value := v.(int)
   200  		if value < min {
   201  			errors = append(errors, fmt.Errorf(
   202  				"%q cannot be lower than %d: %d", k, min, value))
   203  		}
   204  		if value > max {
   205  			errors = append(errors, fmt.Errorf(
   206  				"%q cannot be higher than %d: %d", k, max, value))
   207  		}
   208  		return
   209  	}
   210  }
   211  
   212  func validateCloudWatchEventTargetId(v interface{}, k string) (ws []string, errors []error) {
   213  	value := v.(string)
   214  	if len(value) > 64 {
   215  		errors = append(errors, fmt.Errorf(
   216  			"%q cannot be longer than 64 characters: %q", k, value))
   217  	}
   218  
   219  	// http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_Target.html
   220  	pattern := `^[\.\-_A-Za-z0-9]+$`
   221  	if !regexp.MustCompile(pattern).MatchString(value) {
   222  		errors = append(errors, fmt.Errorf(
   223  			"%q doesn't comply with restrictions (%q): %q",
   224  			k, pattern, value))
   225  	}
   226  
   227  	return
   228  }
   229  
   230  func validateLambdaFunctionName(v interface{}, k string) (ws []string, errors []error) {
   231  	value := v.(string)
   232  	if len(value) > 140 {
   233  		errors = append(errors, fmt.Errorf(
   234  			"%q cannot be longer than 140 characters: %q", k, value))
   235  	}
   236  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   237  	pattern := `^(arn:aws:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?$`
   238  	if !regexp.MustCompile(pattern).MatchString(value) {
   239  		errors = append(errors, fmt.Errorf(
   240  			"%q doesn't comply with restrictions (%q): %q",
   241  			k, pattern, value))
   242  	}
   243  
   244  	return
   245  }
   246  
   247  func validateLambdaQualifier(v interface{}, k string) (ws []string, errors []error) {
   248  	value := v.(string)
   249  	if len(value) > 128 {
   250  		errors = append(errors, fmt.Errorf(
   251  			"%q cannot be longer than 128 characters: %q", k, value))
   252  	}
   253  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   254  	pattern := `^[a-zA-Z0-9$_]+$`
   255  	if !regexp.MustCompile(pattern).MatchString(value) {
   256  		errors = append(errors, fmt.Errorf(
   257  			"%q doesn't comply with restrictions (%q): %q",
   258  			k, pattern, value))
   259  	}
   260  
   261  	return
   262  }
   263  
   264  func validateLambdaPermissionAction(v interface{}, k string) (ws []string, errors []error) {
   265  	value := v.(string)
   266  
   267  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   268  	pattern := `^(lambda:[*]|lambda:[a-zA-Z]+|[*])$`
   269  	if !regexp.MustCompile(pattern).MatchString(value) {
   270  		errors = append(errors, fmt.Errorf(
   271  			"%q doesn't comply with restrictions (%q): %q",
   272  			k, pattern, value))
   273  	}
   274  
   275  	return
   276  }
   277  
   278  func validateAwsAccountId(v interface{}, k string) (ws []string, errors []error) {
   279  	value := v.(string)
   280  
   281  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   282  	pattern := `^\d{12}$`
   283  	if !regexp.MustCompile(pattern).MatchString(value) {
   284  		errors = append(errors, fmt.Errorf(
   285  			"%q doesn't look like AWS Account ID (exactly 12 digits): %q",
   286  			k, value))
   287  	}
   288  
   289  	return
   290  }
   291  
   292  func validateArn(v interface{}, k string) (ws []string, errors []error) {
   293  	value := v.(string)
   294  
   295  	if value == "" {
   296  		return
   297  	}
   298  
   299  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   300  	pattern := `^arn:aws:([a-zA-Z0-9\-])+:([a-z]{2}-[a-z]+-\d{1})?:(\d{12})?:(.*)$`
   301  	if !regexp.MustCompile(pattern).MatchString(value) {
   302  		errors = append(errors, fmt.Errorf(
   303  			"%q doesn't look like a valid ARN (%q): %q",
   304  			k, pattern, value))
   305  	}
   306  
   307  	return
   308  }
   309  
   310  func validatePolicyStatementId(v interface{}, k string) (ws []string, errors []error) {
   311  	value := v.(string)
   312  
   313  	if len(value) > 100 {
   314  		errors = append(errors, fmt.Errorf(
   315  			"%q cannot be longer than 100 characters: %q", k, value))
   316  	}
   317  
   318  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   319  	pattern := `^[a-zA-Z0-9-_]+$`
   320  	if !regexp.MustCompile(pattern).MatchString(value) {
   321  		errors = append(errors, fmt.Errorf(
   322  			"%q doesn't look like a valid statement ID (%q): %q",
   323  			k, pattern, value))
   324  	}
   325  
   326  	return
   327  }
   328  
   329  // validateCIDRNetworkAddress ensures that the string value is a valid CIDR that
   330  // represents a network address - it adds an error otherwise
   331  func validateCIDRNetworkAddress(v interface{}, k string) (ws []string, errors []error) {
   332  	value := v.(string)
   333  	_, ipnet, err := net.ParseCIDR(value)
   334  	if err != nil {
   335  		errors = append(errors, fmt.Errorf(
   336  			"%q must contain a valid CIDR, got error parsing: %s", k, err))
   337  		return
   338  	}
   339  
   340  	if ipnet == nil || value != ipnet.String() {
   341  		errors = append(errors, fmt.Errorf(
   342  			"%q must contain a valid network CIDR, expected %q, got %q",
   343  			k, ipnet, value))
   344  	}
   345  
   346  	return
   347  }
   348  
   349  func validateHTTPMethod(v interface{}, k string) (ws []string, errors []error) {
   350  	value := v.(string)
   351  
   352  	validMethods := map[string]bool{
   353  		"ANY":     true,
   354  		"DELETE":  true,
   355  		"GET":     true,
   356  		"HEAD":    true,
   357  		"OPTIONS": true,
   358  		"PATCH":   true,
   359  		"POST":    true,
   360  		"PUT":     true,
   361  	}
   362  
   363  	if _, ok := validMethods[value]; !ok {
   364  		errors = append(errors, fmt.Errorf(
   365  			"%q contains an invalid method %q. Valid methods are either %q, %q, %q, %q, %q, %q, %q, or %q.",
   366  			k, value, "ANY", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"))
   367  	}
   368  	return
   369  }
   370  
   371  func validateLogMetricFilterName(v interface{}, k string) (ws []string, errors []error) {
   372  	value := v.(string)
   373  
   374  	if len(value) > 512 {
   375  		errors = append(errors, fmt.Errorf(
   376  			"%q cannot be longer than 512 characters: %q", k, value))
   377  	}
   378  
   379  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutMetricFilter.html
   380  	pattern := `^[^:*]+$`
   381  	if !regexp.MustCompile(pattern).MatchString(value) {
   382  		errors = append(errors, fmt.Errorf(
   383  			"%q isn't a valid log metric name (must not contain colon nor asterisk): %q",
   384  			k, value))
   385  	}
   386  
   387  	return
   388  }
   389  
   390  func validateLogMetricFilterTransformationName(v interface{}, k string) (ws []string, errors []error) {
   391  	value := v.(string)
   392  
   393  	if len(value) > 255 {
   394  		errors = append(errors, fmt.Errorf(
   395  			"%q cannot be longer than 255 characters: %q", k, value))
   396  	}
   397  
   398  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_MetricTransformation.html
   399  	pattern := `^[^:*$]*$`
   400  	if !regexp.MustCompile(pattern).MatchString(value) {
   401  		errors = append(errors, fmt.Errorf(
   402  			"%q isn't a valid log metric transformation name (must not contain"+
   403  				" colon, asterisk nor dollar sign): %q",
   404  			k, value))
   405  	}
   406  
   407  	return
   408  }
   409  
   410  func validateLogGroupName(v interface{}, k string) (ws []string, errors []error) {
   411  	value := v.(string)
   412  
   413  	if len(value) > 512 {
   414  		errors = append(errors, fmt.Errorf(
   415  			"%q cannot be longer than 512 characters: %q", k, value))
   416  	}
   417  
   418  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html
   419  	pattern := `^[\.\-_/#A-Za-z0-9]+$`
   420  	if !regexp.MustCompile(pattern).MatchString(value) {
   421  		errors = append(errors, fmt.Errorf(
   422  			"%q isn't a valid log group name (alphanumeric characters, underscores,"+
   423  				" hyphens, slashes, hash signs and dots are allowed): %q",
   424  			k, value))
   425  	}
   426  
   427  	return
   428  }
   429  
   430  func validateS3BucketLifecycleTimestamp(v interface{}, k string) (ws []string, errors []error) {
   431  	value := v.(string)
   432  	_, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", value))
   433  	if err != nil {
   434  		errors = append(errors, fmt.Errorf(
   435  			"%q cannot be parsed as RFC3339 Timestamp Format", value))
   436  	}
   437  
   438  	return
   439  }
   440  
   441  func validateS3BucketLifecycleStorageClass(v interface{}, k string) (ws []string, errors []error) {
   442  	value := v.(string)
   443  	if value != s3.TransitionStorageClassStandardIa && value != s3.TransitionStorageClassGlacier {
   444  		errors = append(errors, fmt.Errorf(
   445  			"%q must be one of '%q', '%q'", k, s3.TransitionStorageClassStandardIa, s3.TransitionStorageClassGlacier))
   446  	}
   447  
   448  	return
   449  }
   450  
   451  func validateS3BucketReplicationRuleId(v interface{}, k string) (ws []string, errors []error) {
   452  	value := v.(string)
   453  	if len(value) > 255 {
   454  		errors = append(errors, fmt.Errorf(
   455  			"%q cannot be longer than 255 characters: %q", k, value))
   456  	}
   457  
   458  	return
   459  }
   460  
   461  func validateS3BucketReplicationRulePrefix(v interface{}, k string) (ws []string, errors []error) {
   462  	value := v.(string)
   463  	if len(value) > 1024 {
   464  		errors = append(errors, fmt.Errorf(
   465  			"%q cannot be longer than 1024 characters: %q", k, value))
   466  	}
   467  
   468  	return
   469  }
   470  
   471  func validateS3BucketReplicationDestinationStorageClass(v interface{}, k string) (ws []string, errors []error) {
   472  	value := v.(string)
   473  	if value != s3.StorageClassStandard && value != s3.StorageClassStandardIa && value != s3.StorageClassReducedRedundancy {
   474  		errors = append(errors, fmt.Errorf(
   475  			"%q must be one of '%q', '%q' or '%q'", k, s3.StorageClassStandard, s3.StorageClassStandardIa, s3.StorageClassReducedRedundancy))
   476  	}
   477  
   478  	return
   479  }
   480  
   481  func validateS3BucketReplicationRuleStatus(v interface{}, k string) (ws []string, errors []error) {
   482  	value := v.(string)
   483  	if value != s3.ReplicationRuleStatusEnabled && value != s3.ReplicationRuleStatusDisabled {
   484  		errors = append(errors, fmt.Errorf(
   485  			"%q must be one of '%q' or '%q'", k, s3.ReplicationRuleStatusEnabled, s3.ReplicationRuleStatusDisabled))
   486  	}
   487  
   488  	return
   489  }
   490  
   491  func validateS3BucketLifecycleRuleId(v interface{}, k string) (ws []string, errors []error) {
   492  	value := v.(string)
   493  	if len(value) > 255 {
   494  		errors = append(errors, fmt.Errorf(
   495  			"%q cannot exceed 255 characters", k))
   496  	}
   497  	return
   498  }
   499  
   500  func validateDbEventSubscriptionName(v interface{}, k string) (ws []string, errors []error) {
   501  	value := v.(string)
   502  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   503  		errors = append(errors, fmt.Errorf(
   504  			"only alphanumeric characters and hyphens allowed in %q", k))
   505  	}
   506  	if len(value) > 255 {
   507  		errors = append(errors, fmt.Errorf(
   508  			"%q cannot be longer than 255 characters", k))
   509  	}
   510  	return
   511  }
   512  
   513  func validateApiGatewayIntegrationPassthroughBehavior(v interface{}, k string) (ws []string, errors []error) {
   514  	value := v.(string)
   515  	if value != "WHEN_NO_MATCH" && value != "WHEN_NO_TEMPLATES" && value != "NEVER" {
   516  		errors = append(errors, fmt.Errorf(
   517  			"%q must be one of 'WHEN_NO_MATCH', 'WHEN_NO_TEMPLATES', 'NEVER'", k))
   518  	}
   519  	return
   520  }
   521  
   522  func validateJsonString(v interface{}, k string) (ws []string, errors []error) {
   523  	if _, err := normalizeJsonString(v); err != nil {
   524  		errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
   525  	}
   526  	return
   527  }
   528  
   529  func validateApiGatewayIntegrationType(v interface{}, k string) (ws []string, errors []error) {
   530  	value := v.(string)
   531  
   532  	validTypes := map[string]bool{
   533  		"AWS":        true,
   534  		"AWS_PROXY":  true,
   535  		"HTTP":       true,
   536  		"HTTP_PROXY": true,
   537  		"MOCK":       true,
   538  	}
   539  
   540  	if _, ok := validTypes[value]; !ok {
   541  		errors = append(errors, fmt.Errorf(
   542  			"%q contains an invalid integration type %q. Valid types are either %q, %q, %q, %q, or %q.",
   543  			k, value, "AWS", "AWS_PROXY", "HTTP", "HTTP_PROXY", "MOCK"))
   544  	}
   545  	return
   546  }
   547  
   548  func validateApiGatewayIntegrationContentHandling(v interface{}, k string) (ws []string, errors []error) {
   549  	value := v.(string)
   550  
   551  	validTypes := map[string]bool{
   552  		"CONVERT_TO_BINARY": true,
   553  		"CONVERT_TO_TEXT":   true,
   554  	}
   555  
   556  	if _, ok := validTypes[value]; !ok {
   557  		errors = append(errors, fmt.Errorf(
   558  			"%q contains an invalid integration type %q. Valid types are either %q or %q.",
   559  			k, value, "CONVERT_TO_BINARY", "CONVERT_TO_TEXT"))
   560  	}
   561  	return
   562  }
   563  
   564  func validateSQSQueueName(v interface{}, k string) (errors []error) {
   565  	value := v.(string)
   566  	if len(value) > 80 {
   567  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   568  	}
   569  
   570  	if !regexp.MustCompile(`^[0-9A-Za-z-_]+$`).MatchString(value) {
   571  		errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k))
   572  	}
   573  	return
   574  }
   575  
   576  func validateSQSFifoQueueName(v interface{}, k string) (errors []error) {
   577  	value := v.(string)
   578  
   579  	if len(value) > 80 {
   580  		errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
   581  	}
   582  
   583  	if !regexp.MustCompile(`^[0-9A-Za-z-_.]+$`).MatchString(value) {
   584  		errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k))
   585  	}
   586  
   587  	if regexp.MustCompile(`^[^a-zA-Z0-9-_]`).MatchString(value) {
   588  		errors = append(errors, fmt.Errorf("FIFO queue name must start with one of these characters [a-zA-Z0-9-_]: %v", value))
   589  	}
   590  
   591  	if !regexp.MustCompile(`\.fifo$`).MatchString(value) {
   592  		errors = append(errors, fmt.Errorf("FIFO queue name should ends with \".fifo\": %v", value))
   593  	}
   594  
   595  	return
   596  }
   597  
   598  func validateSNSSubscriptionProtocol(v interface{}, k string) (ws []string, errors []error) {
   599  	value := strings.ToLower(v.(string))
   600  	forbidden := []string{"email", "sms"}
   601  	for _, f := range forbidden {
   602  		if strings.Contains(value, f) {
   603  			errors = append(
   604  				errors,
   605  				fmt.Errorf("Unsupported protocol (%s) for SNS Topic", value),
   606  			)
   607  		}
   608  	}
   609  	return
   610  }
   611  
   612  func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) {
   613  	value := strings.ToLower(v.(string))
   614  
   615  	validTypes := map[string]bool{
   616  		"ingress": true,
   617  		"egress":  true,
   618  	}
   619  
   620  	if _, ok := validTypes[value]; !ok {
   621  		errors = append(errors, fmt.Errorf(
   622  			"%q contains an invalid Security Group Rule type %q. Valid types are either %q or %q.",
   623  			k, value, "ingress", "egress"))
   624  	}
   625  	return
   626  }
   627  
   628  func validateOnceAWeekWindowFormat(v interface{}, k string) (ws []string, errors []error) {
   629  	// valid time format is "ddd:hh24:mi"
   630  	validTimeFormat := "(sun|mon|tue|wed|thu|fri|sat):([0-1][0-9]|2[0-3]):([0-5][0-9])"
   631  
   632  	value := strings.ToLower(v.(string))
   633  	if !regexp.MustCompile(validTimeFormat + "-" + validTimeFormat).MatchString(value) {
   634  		errors = append(errors, fmt.Errorf(
   635  			"%q must satisfy the format of \"ddd:hh24:mi-ddd:hh24:mi\".", k))
   636  	}
   637  	return
   638  }
   639  
   640  func validateOnceADayWindowFormat(v interface{}, k string) (ws []string, errors []error) {
   641  	// valid time format is "hh24:mi"
   642  	validTimeFormat := "([0-1][0-9]|2[0-3]):([0-5][0-9])"
   643  
   644  	value := v.(string)
   645  	if !regexp.MustCompile(validTimeFormat + "-" + validTimeFormat).MatchString(value) {
   646  		errors = append(errors, fmt.Errorf(
   647  			"%q must satisfy the format of \"hh24:mi-hh24:mi\".", k))
   648  	}
   649  	return
   650  }
   651  
   652  func validateRoute53RecordType(v interface{}, k string) (ws []string, errors []error) {
   653  	// Valid Record types
   654  	// SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA
   655  	validTypes := map[string]struct{}{
   656  		"SOA":   {},
   657  		"A":     {},
   658  		"TXT":   {},
   659  		"NS":    {},
   660  		"CNAME": {},
   661  		"MX":    {},
   662  		"NAPTR": {},
   663  		"PTR":   {},
   664  		"SRV":   {},
   665  		"SPF":   {},
   666  		"AAAA":  {},
   667  	}
   668  
   669  	value := v.(string)
   670  	if _, ok := validTypes[value]; !ok {
   671  		errors = append(errors, fmt.Errorf(
   672  			"%q must be one of [SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA]", k))
   673  	}
   674  	return
   675  }