diff --git a/aws/resource_aws_cloudwatch_event_target.go b/aws/resource_aws_cloudwatch_event_target.go index be45a0fd083..18bdff07c4b 100644 --- a/aws/resource_aws_cloudwatch_event_target.go +++ b/aws/resource_aws_cloudwatch_event_target.go @@ -216,6 +216,10 @@ func resourceAwsCloudWatchEventTarget() *schema.Resource { Type: schema.TypeMap, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, + ValidateFunc: validation.All( + MapMaxItems(10), + MapKeysDoNotMatch(regexp.MustCompile(`^AWS.*$`), "input_path must not start with \"AWS\""), + ), }, "input_template": { Type: schema.TypeString, diff --git a/aws/resource_aws_cloudwatch_event_target_test.go b/aws/resource_aws_cloudwatch_event_target_test.go index 130364b761d..e0b13a8a990 100644 --- a/aws/resource_aws_cloudwatch_event_target_test.go +++ b/aws/resource_aws_cloudwatch_event_target_test.go @@ -3,6 +3,8 @@ package aws import ( "fmt" "log" + "regexp" + "strings" "testing" "github.com/aws/aws-sdk-go/aws" @@ -359,7 +361,11 @@ func TestAccAWSCloudWatchEventTarget_input_transformer(t *testing.T) { CheckDestroy: testAccCheckAWSCloudWatchEventTargetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudWatchEventTargetConfigInputTransformer(rName), + Config: testAccAWSCloudWatchEventTargetConfigInputTransformer(rName, 11), + ExpectError: regexp.MustCompile(`.*expected number of items in.* to be lesser than or equal to.*`), + }, + { + Config: testAccAWSCloudWatchEventTargetConfigInputTransformer(rName, 10), Check: resource.ComposeTestCheckFunc( testAccCheckCloudWatchEventTargetExists("aws_cloudwatch_event_target.test", &target), ), @@ -1074,7 +1080,35 @@ resource "aws_sqs_queue" "sqs_queue" { `, rName) } -func testAccAWSCloudWatchEventTargetConfigInputTransformer(rName string) string { +func testAccAWSCloudWatchEventTargetConfigInputTransformer(rName string, inputPathCount int) string { + sampleInputPaths := [...]string{ + "account", + "count", + "eventFirstSeen", + "eventLastSeen", + "Finding_ID", + "Finding_Type", + "instanceId", + "port", + "region", + "severity", + "time", + } + var inputPaths strings.Builder + var inputTemplates strings.Builder + + if len(sampleInputPaths) < inputPathCount { + inputPathCount = len(sampleInputPaths) + } + + for i := 0; i < inputPathCount; i++ { + fmt.Fprintf(&inputPaths, ` + %s = "$.%s"`, sampleInputPaths[i], sampleInputPaths[i]) + + fmt.Fprintf(&inputTemplates, ` + "%s": <%s>,`, sampleInputPaths[i], sampleInputPaths[i]) + } + return fmt.Sprintf(` data "aws_partition" "current" {} @@ -1120,20 +1154,18 @@ resource "aws_cloudwatch_event_target" "test" { input_transformer { input_paths = { - time = "$.time" + %s } input_template = <, - "region": "eu-west-1", + "source": "aws.events",%s "detail": {} } EOF } } -`, rName) +`, rName, inputPaths.String(), inputTemplates.String()) } diff --git a/aws/validators.go b/aws/validators.go index 56d64a184b2..3d65d37f5bb 100644 --- a/aws/validators.go +++ b/aws/validators.go @@ -2483,3 +2483,37 @@ func validateNestedExactlyOneOf(m map[string]interface{}, valid []string) error } return nil } + +func MapMaxItems(max int) schema.SchemaValidateFunc { + return func(i interface{}, k string) (warnings []string, errors []error) { + m, ok := i.(map[string]interface{}) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be map", k)) + return warnings, errors + } + + if len(m) > max { + errors = append(errors, fmt.Errorf("expected number of items in %s to be lesser than or equal to %d, got %d", k, max, len(m))) + } + + return warnings, errors + } +} + +func MapKeysDoNotMatch(r *regexp.Regexp, message string) schema.SchemaValidateFunc { + return func(i interface{}, k string) (warnings []string, errors []error) { + m, ok := i.(map[string]interface{}) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be map", k)) + return warnings, errors + } + + for key := range m { + if ok := r.MatchString(key); ok { + errors = append(errors, fmt.Errorf("%s: %s: %s", k, message, key)) + } + } + + return warnings, errors + } +} diff --git a/website/docs/r/cloudwatch_event_target.html.markdown b/website/docs/r/cloudwatch_event_target.html.markdown index 13f961ec1cb..ace05ce23fe 100644 --- a/website/docs/r/cloudwatch_event_target.html.markdown +++ b/website/docs/r/cloudwatch_event_target.html.markdown @@ -301,6 +301,10 @@ For more information, see [Task Networking](https://docs.aws.amazon.com/AmazonEC `input_transformer` support the following: * `input_paths` - (Optional) Key value pairs specified in the form of JSONPath (for example, time = $.time) + * You can have as many as 10 key-value pairs. + * You must use JSON dot notation, not bracket notation. + * The keys can't start with "AWS". + * `input_template` - (Required) Structure containing the template body. ## Import