github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/builtin/providers/aws/validators.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"regexp"
     7  	"time"
     8  
     9  	"github.com/aws/aws-sdk-go/service/s3"
    10  	"github.com/hashicorp/terraform/helper/schema"
    11  )
    12  
    13  func validateRdsId(v interface{}, k string) (ws []string, errors []error) {
    14  	value := v.(string)
    15  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
    16  		errors = append(errors, fmt.Errorf(
    17  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
    18  	}
    19  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
    20  		errors = append(errors, fmt.Errorf(
    21  			"first character of %q must be a letter", k))
    22  	}
    23  	if regexp.MustCompile(`--`).MatchString(value) {
    24  		errors = append(errors, fmt.Errorf(
    25  			"%q cannot contain two consecutive hyphens", k))
    26  	}
    27  	if regexp.MustCompile(`-$`).MatchString(value) {
    28  		errors = append(errors, fmt.Errorf(
    29  			"%q cannot end with a hyphen", k))
    30  	}
    31  	return
    32  }
    33  
    34  func validateElastiCacheClusterId(v interface{}, k string) (ws []string, errors []error) {
    35  	value := v.(string)
    36  	if (len(value) < 1) || (len(value) > 20) {
    37  		errors = append(errors, fmt.Errorf(
    38  			"%q must contain from 1 to 20 alphanumeric characters or hyphens", k))
    39  	}
    40  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
    41  		errors = append(errors, fmt.Errorf(
    42  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
    43  	}
    44  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
    45  		errors = append(errors, fmt.Errorf(
    46  			"first character of %q must be a letter", k))
    47  	}
    48  	if regexp.MustCompile(`--`).MatchString(value) {
    49  		errors = append(errors, fmt.Errorf(
    50  			"%q cannot contain two consecutive hyphens", k))
    51  	}
    52  	if regexp.MustCompile(`-$`).MatchString(value) {
    53  		errors = append(errors, fmt.Errorf(
    54  			"%q cannot end with a hyphen", k))
    55  	}
    56  	return
    57  }
    58  
    59  func validateASGScheduleTimestamp(v interface{}, k string) (ws []string, errors []error) {
    60  	value := v.(string)
    61  	_, err := time.Parse(awsAutoscalingScheduleTimeLayout, value)
    62  	if err != nil {
    63  		errors = append(errors, fmt.Errorf(
    64  			"%q cannot be parsed as iso8601 Timestamp Format", value))
    65  	}
    66  
    67  	return
    68  }
    69  
    70  // validateTagFilters confirms the "value" component of a tag filter is one of
    71  // AWS's three allowed types.
    72  func validateTagFilters(v interface{}, k string) (ws []string, errors []error) {
    73  	value := v.(string)
    74  	if value != "KEY_ONLY" && value != "VALUE_ONLY" && value != "KEY_AND_VALUE" {
    75  		errors = append(errors, fmt.Errorf(
    76  			"%q must be one of \"KEY_ONLY\", \"VALUE_ONLY\", or \"KEY_AND_VALUE\"", k))
    77  	}
    78  	return
    79  }
    80  
    81  func validateDbParamGroupName(v interface{}, k string) (ws []string, errors []error) {
    82  	value := v.(string)
    83  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
    84  		errors = append(errors, fmt.Errorf(
    85  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
    86  	}
    87  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
    88  		errors = append(errors, fmt.Errorf(
    89  			"first character of %q must be a letter", k))
    90  	}
    91  	if regexp.MustCompile(`--`).MatchString(value) {
    92  		errors = append(errors, fmt.Errorf(
    93  			"%q cannot contain two consecutive hyphens", k))
    94  	}
    95  	if regexp.MustCompile(`-$`).MatchString(value) {
    96  		errors = append(errors, fmt.Errorf(
    97  			"%q cannot end with a hyphen", k))
    98  	}
    99  	if len(value) > 255 {
   100  		errors = append(errors, fmt.Errorf(
   101  			"%q cannot be greater than 255 characters", k))
   102  	}
   103  	return
   104  
   105  }
   106  
   107  func validateStreamViewType(v interface{}, k string) (ws []string, errors []error) {
   108  	value := v.(string)
   109  	viewTypes := map[string]bool{
   110  		"KEYS_ONLY":          true,
   111  		"NEW_IMAGE":          true,
   112  		"OLD_IMAGE":          true,
   113  		"NEW_AND_OLD_IMAGES": true,
   114  	}
   115  
   116  	if !viewTypes[value] {
   117  		errors = append(errors, fmt.Errorf("%q be a valid DynamoDB StreamViewType", k))
   118  	}
   119  	return
   120  }
   121  
   122  func validateElbName(v interface{}, k string) (ws []string, errors []error) {
   123  	value := v.(string)
   124  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   125  		errors = append(errors, fmt.Errorf(
   126  			"only alphanumeric characters and hyphens allowed in %q: %q",
   127  			k, value))
   128  	}
   129  	if len(value) > 32 {
   130  		errors = append(errors, fmt.Errorf(
   131  			"%q cannot be longer than 32 characters: %q", k, value))
   132  	}
   133  	if regexp.MustCompile(`^-`).MatchString(value) {
   134  		errors = append(errors, fmt.Errorf(
   135  			"%q cannot begin with a hyphen: %q", k, value))
   136  	}
   137  	if regexp.MustCompile(`-$`).MatchString(value) {
   138  		errors = append(errors, fmt.Errorf(
   139  			"%q cannot end with a hyphen: %q", k, value))
   140  	}
   141  	return
   142  
   143  }
   144  
   145  func validateEcrRepositoryName(v interface{}, k string) (ws []string, errors []error) {
   146  	value := v.(string)
   147  	if len(value) < 2 {
   148  		errors = append(errors, fmt.Errorf(
   149  			"%q must be at least 2 characters long: %q", k, value))
   150  	}
   151  	if len(value) > 256 {
   152  		errors = append(errors, fmt.Errorf(
   153  			"%q cannot be longer than 256 characters: %q", k, value))
   154  	}
   155  
   156  	// http://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_CreateRepository.html
   157  	pattern := `^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)*[a-z0-9]+(?:[._-][a-z0-9]+)*$`
   158  	if !regexp.MustCompile(pattern).MatchString(value) {
   159  		errors = append(errors, fmt.Errorf(
   160  			"%q doesn't comply with restrictions (%q): %q",
   161  			k, pattern, value))
   162  	}
   163  
   164  	return
   165  }
   166  
   167  func validateCloudWatchEventRuleName(v interface{}, k string) (ws []string, errors []error) {
   168  	value := v.(string)
   169  	if len(value) > 64 {
   170  		errors = append(errors, fmt.Errorf(
   171  			"%q cannot be longer than 64 characters: %q", k, value))
   172  	}
   173  
   174  	// http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_PutRule.html
   175  	pattern := `^[\.\-_A-Za-z0-9]+$`
   176  	if !regexp.MustCompile(pattern).MatchString(value) {
   177  		errors = append(errors, fmt.Errorf(
   178  			"%q doesn't comply with restrictions (%q): %q",
   179  			k, pattern, value))
   180  	}
   181  
   182  	return
   183  }
   184  
   185  func validateMaxLength(length int) schema.SchemaValidateFunc {
   186  	return func(v interface{}, k string) (ws []string, errors []error) {
   187  		value := v.(string)
   188  		if len(value) > length {
   189  			errors = append(errors, fmt.Errorf(
   190  				"%q cannot be longer than %d characters: %q", k, length, value))
   191  		}
   192  		return
   193  	}
   194  }
   195  
   196  func validateIntegerInRange(min, max int) schema.SchemaValidateFunc {
   197  	return func(v interface{}, k string) (ws []string, errors []error) {
   198  		value := v.(int)
   199  		if value < min {
   200  			errors = append(errors, fmt.Errorf(
   201  				"%q cannot be lower than %d: %d", k, min, value))
   202  		}
   203  		if value > max {
   204  			errors = append(errors, fmt.Errorf(
   205  				"%q cannot be higher than %d: %d", k, max, value))
   206  		}
   207  		return
   208  	}
   209  }
   210  
   211  func validateCloudWatchEventTargetId(v interface{}, k string) (ws []string, errors []error) {
   212  	value := v.(string)
   213  	if len(value) > 64 {
   214  		errors = append(errors, fmt.Errorf(
   215  			"%q cannot be longer than 64 characters: %q", k, value))
   216  	}
   217  
   218  	// http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_Target.html
   219  	pattern := `^[\.\-_A-Za-z0-9]+$`
   220  	if !regexp.MustCompile(pattern).MatchString(value) {
   221  		errors = append(errors, fmt.Errorf(
   222  			"%q doesn't comply with restrictions (%q): %q",
   223  			k, pattern, value))
   224  	}
   225  
   226  	return
   227  }
   228  
   229  func validateLambdaFunctionName(v interface{}, k string) (ws []string, errors []error) {
   230  	value := v.(string)
   231  	if len(value) > 140 {
   232  		errors = append(errors, fmt.Errorf(
   233  			"%q cannot be longer than 140 characters: %q", k, value))
   234  	}
   235  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   236  	pattern := `^(arn:aws:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?$`
   237  	if !regexp.MustCompile(pattern).MatchString(value) {
   238  		errors = append(errors, fmt.Errorf(
   239  			"%q doesn't comply with restrictions (%q): %q",
   240  			k, pattern, value))
   241  	}
   242  
   243  	return
   244  }
   245  
   246  func validateLambdaQualifier(v interface{}, k string) (ws []string, errors []error) {
   247  	value := v.(string)
   248  	if len(value) > 128 {
   249  		errors = append(errors, fmt.Errorf(
   250  			"%q cannot be longer than 128 characters: %q", k, value))
   251  	}
   252  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   253  	pattern := `^[a-zA-Z0-9$_]+$`
   254  	if !regexp.MustCompile(pattern).MatchString(value) {
   255  		errors = append(errors, fmt.Errorf(
   256  			"%q doesn't comply with restrictions (%q): %q",
   257  			k, pattern, value))
   258  	}
   259  
   260  	return
   261  }
   262  
   263  func validateLambdaPermissionAction(v interface{}, k string) (ws []string, errors []error) {
   264  	value := v.(string)
   265  
   266  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   267  	pattern := `^(lambda:[*]|lambda:[a-zA-Z]+|[*])$`
   268  	if !regexp.MustCompile(pattern).MatchString(value) {
   269  		errors = append(errors, fmt.Errorf(
   270  			"%q doesn't comply with restrictions (%q): %q",
   271  			k, pattern, value))
   272  	}
   273  
   274  	return
   275  }
   276  
   277  func validateAwsAccountId(v interface{}, k string) (ws []string, errors []error) {
   278  	value := v.(string)
   279  
   280  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   281  	pattern := `^\d{12}$`
   282  	if !regexp.MustCompile(pattern).MatchString(value) {
   283  		errors = append(errors, fmt.Errorf(
   284  			"%q doesn't look like AWS Account ID (exactly 12 digits): %q",
   285  			k, value))
   286  	}
   287  
   288  	return
   289  }
   290  
   291  func validateArn(v interface{}, k string) (ws []string, errors []error) {
   292  	value := v.(string)
   293  
   294  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   295  	pattern := `^arn:aws:([a-zA-Z0-9\-])+:([a-z]{2}-[a-z]+-\d{1})?:(\d{12})?:(.*)$`
   296  	if !regexp.MustCompile(pattern).MatchString(value) {
   297  		errors = append(errors, fmt.Errorf(
   298  			"%q doesn't look like a valid ARN (%q): %q",
   299  			k, pattern, value))
   300  	}
   301  
   302  	return
   303  }
   304  
   305  func validatePolicyStatementId(v interface{}, k string) (ws []string, errors []error) {
   306  	value := v.(string)
   307  
   308  	if len(value) > 100 {
   309  		errors = append(errors, fmt.Errorf(
   310  			"%q cannot be longer than 100 characters: %q", k, value))
   311  	}
   312  
   313  	// http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
   314  	pattern := `^[a-zA-Z0-9-_]+$`
   315  	if !regexp.MustCompile(pattern).MatchString(value) {
   316  		errors = append(errors, fmt.Errorf(
   317  			"%q doesn't look like a valid statement ID (%q): %q",
   318  			k, pattern, value))
   319  	}
   320  
   321  	return
   322  }
   323  
   324  // validateCIDRNetworkAddress ensures that the string value is a valid CIDR that
   325  // represents a network address - it adds an error otherwise
   326  func validateCIDRNetworkAddress(v interface{}, k string) (ws []string, errors []error) {
   327  	value := v.(string)
   328  	_, ipnet, err := net.ParseCIDR(value)
   329  	if err != nil {
   330  		errors = append(errors, fmt.Errorf(
   331  			"%q must contain a valid CIDR, got error parsing: %s", k, err))
   332  		return
   333  	}
   334  
   335  	if ipnet == nil || value != ipnet.String() {
   336  		errors = append(errors, fmt.Errorf(
   337  			"%q must contain a valid network CIDR, expected %q, got %q",
   338  			k, ipnet, value))
   339  	}
   340  
   341  	return
   342  }
   343  
   344  func validateHTTPMethod(v interface{}, k string) (ws []string, errors []error) {
   345  	value := v.(string)
   346  
   347  	validMethods := map[string]bool{
   348  		"ANY":     true,
   349  		"DELETE":  true,
   350  		"GET":     true,
   351  		"HEAD":    true,
   352  		"OPTIONS": true,
   353  		"PATCH":   true,
   354  		"POST":    true,
   355  		"PUT":     true,
   356  	}
   357  
   358  	if _, ok := validMethods[value]; !ok {
   359  		errors = append(errors, fmt.Errorf(
   360  			"%q contains an invalid method %q. Valid methods are either %q, %q, %q, %q, %q, %q, %q, or %q.",
   361  			k, value, "ANY", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"))
   362  	}
   363  	return
   364  }
   365  
   366  func validateLogMetricFilterName(v interface{}, k string) (ws []string, errors []error) {
   367  	value := v.(string)
   368  
   369  	if len(value) > 512 {
   370  		errors = append(errors, fmt.Errorf(
   371  			"%q cannot be longer than 512 characters: %q", k, value))
   372  	}
   373  
   374  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutMetricFilter.html
   375  	pattern := `^[^:*]+$`
   376  	if !regexp.MustCompile(pattern).MatchString(value) {
   377  		errors = append(errors, fmt.Errorf(
   378  			"%q isn't a valid log metric name (must not contain colon nor asterisk): %q",
   379  			k, value))
   380  	}
   381  
   382  	return
   383  }
   384  
   385  func validateLogMetricFilterTransformationName(v interface{}, k string) (ws []string, errors []error) {
   386  	value := v.(string)
   387  
   388  	if len(value) > 255 {
   389  		errors = append(errors, fmt.Errorf(
   390  			"%q cannot be longer than 255 characters: %q", k, value))
   391  	}
   392  
   393  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_MetricTransformation.html
   394  	pattern := `^[^:*$]*$`
   395  	if !regexp.MustCompile(pattern).MatchString(value) {
   396  		errors = append(errors, fmt.Errorf(
   397  			"%q isn't a valid log metric transformation name (must not contain"+
   398  				" colon, asterisk nor dollar sign): %q",
   399  			k, value))
   400  	}
   401  
   402  	return
   403  }
   404  
   405  func validateLogGroupName(v interface{}, k string) (ws []string, errors []error) {
   406  	value := v.(string)
   407  
   408  	if len(value) > 512 {
   409  		errors = append(errors, fmt.Errorf(
   410  			"%q cannot be longer than 512 characters: %q", k, value))
   411  	}
   412  
   413  	// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html
   414  	pattern := `^[\.\-_/#A-Za-z0-9]+$`
   415  	if !regexp.MustCompile(pattern).MatchString(value) {
   416  		errors = append(errors, fmt.Errorf(
   417  			"%q isn't a valid log group name (alphanumeric characters, underscores,"+
   418  				" hyphens, slashes, hash signs and dots are allowed): %q",
   419  			k, value))
   420  	}
   421  
   422  	return
   423  }
   424  
   425  func validateS3BucketLifecycleTimestamp(v interface{}, k string) (ws []string, errors []error) {
   426  	value := v.(string)
   427  	_, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", value))
   428  	if err != nil {
   429  		errors = append(errors, fmt.Errorf(
   430  			"%q cannot be parsed as RFC3339 Timestamp Format", value))
   431  	}
   432  
   433  	return
   434  }
   435  
   436  func validateS3BucketLifecycleStorageClass(v interface{}, k string) (ws []string, errors []error) {
   437  	value := v.(string)
   438  	if value != s3.TransitionStorageClassStandardIa && value != s3.TransitionStorageClassGlacier {
   439  		errors = append(errors, fmt.Errorf(
   440  			"%q must be one of '%q', '%q'", k, s3.TransitionStorageClassStandardIa, s3.TransitionStorageClassGlacier))
   441  	}
   442  
   443  	return
   444  }
   445  
   446  func validateS3BucketLifecycleRuleId(v interface{}, k string) (ws []string, errors []error) {
   447  	value := v.(string)
   448  	if len(value) > 255 {
   449  		errors = append(errors, fmt.Errorf(
   450  			"%q cannot exceed 255 characters", k))
   451  	}
   452  	return
   453  }
   454  
   455  func validateDbEventSubscriptionName(v interface{}, k string) (ws []string, errors []error) {
   456  	value := v.(string)
   457  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   458  		errors = append(errors, fmt.Errorf(
   459  			"only alphanumeric characters and hyphens allowed in %q", k))
   460  	}
   461  	if len(value) > 255 {
   462  		errors = append(errors, fmt.Errorf(
   463  			"%q cannot be longer than 255 characters", k))
   464  	}
   465  	return
   466  }
   467  
   468  func validateApiGatewayIntegrationPassthroughBehavior(v interface{}, k string) (ws []string, errors []error) {
   469  	value := v.(string)
   470  	if value != "WHEN_NO_MATCH" && value != "WHEN_NO_TEMPLATES" && value != "NEVER" {
   471  		errors = append(errors, fmt.Errorf(
   472  			"%q must be one of 'WHEN_NO_MATCH', 'WHEN_NO_TEMPLATES', 'NEVER'", k))
   473  	}
   474  	return
   475  }
   476  
   477  func validateJsonString(v interface{}, k string) (ws []string, errors []error) {
   478  	if _, err := normalizeJsonString(v); err != nil {
   479  		errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
   480  	}
   481  	return
   482  }
   483  
   484  func validateApiGatewayIntegrationType(v interface{}, k string) (ws []string, errors []error) {
   485  	value := v.(string)
   486  
   487  	validTypes := map[string]bool{
   488  		"AWS":        true,
   489  		"AWS_PROXY":  true,
   490  		"HTTP":       true,
   491  		"HTTP_PROXY": true,
   492  		"MOCK":       true,
   493  	}
   494  
   495  	if _, ok := validTypes[value]; !ok {
   496  		errors = append(errors, fmt.Errorf(
   497  			"%q contains an invalid integration type %q. Valid types are either %q, %q, %q, %q, or %q.",
   498  			k, value, "AWS", "AWS_PROXY", "HTTP", "HTTP_PROXY", "MOCK"))
   499  	}
   500  	return
   501  }