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