diff --git a/builtin/providers/aws/resource_aws_cloudwatch_event_rule.go b/builtin/providers/aws/resource_aws_cloudwatch_event_rule.go index 3181b8480..0aff703f7 100644 --- a/builtin/providers/aws/resource_aws_cloudwatch_event_rule.go +++ b/builtin/providers/aws/resource_aws_cloudwatch_event_rule.go @@ -39,8 +39,11 @@ func resourceAwsCloudWatchEventRule() *schema.Resource { "event_pattern": &schema.Schema{ Type: schema.TypeString, Optional: true, - ValidateFunc: validateMaxLength(2048), - StateFunc: normalizeJson, + ValidateFunc: validateEventPatternValue(2048), + StateFunc: func(v interface{}) string { + json, _ := normalizeJsonString(v) + return json + }, }, "description": &schema.Schema{ Type: schema.TypeString, @@ -123,7 +126,8 @@ func resourceAwsCloudWatchEventRuleRead(d *schema.ResourceData, meta interface{} d.Set("arn", out.Arn) d.Set("description", out.Description) if out.EventPattern != nil { - d.Set("event_pattern", normalizeJson(*out.EventPattern)) + pattern, _ := normalizeJsonString(*out.EventPattern) + d.Set("event_pattern", pattern) } d.Set("name", out.Name) d.Set("role_arn", out.RoleArn) @@ -214,7 +218,8 @@ func buildPutRuleInputStruct(d *schema.ResourceData) *events.PutRuleInput { input.Description = aws.String(v.(string)) } if v, ok := d.GetOk("event_pattern"); ok { - input.EventPattern = aws.String(normalizeJson(v.(string))) + pattern, _ := normalizeJsonString(v.(string)) + input.EventPattern = aws.String(pattern) } if v, ok := d.GetOk("role_arn"); ok { input.RoleArn = aws.String(v.(string)) @@ -247,3 +252,24 @@ func getStringStateFromBoolean(isEnabled bool) string { } return "DISABLED" } + +func validateEventPatternValue(length int) schema.SchemaValidateFunc { + return func(v interface{}, k string) (ws []string, errors []error) { + json, err := normalizeJsonString(v) + if err != nil { + errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err)) + + // Invalid JSON? Return immediately, + // there is no need to collect other + // errors. + return + } + + // Check whether the normalized JSON is within the given length. + if len(json) > length { + errors = append(errors, fmt.Errorf( + "%q cannot be longer than %d characters: %q", k, length, json)) + } + return + } +} diff --git a/builtin/providers/aws/resource_aws_cloudwatch_event_rule_test.go b/builtin/providers/aws/resource_aws_cloudwatch_event_rule_test.go index 5bedff782..e69489777 100644 --- a/builtin/providers/aws/resource_aws_cloudwatch_event_rule_test.go +++ b/builtin/providers/aws/resource_aws_cloudwatch_event_rule_test.go @@ -6,6 +6,7 @@ import ( "github.com/aws/aws-sdk-go/aws" events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" ) @@ -165,6 +166,64 @@ func testAccCheckAWSCloudWatchEventRuleDestroy(s *terraform.State) error { return nil } +func TestResourceAWSCloudWatchEventRule_validateEventPatternValue(t *testing.T) { + type testCases struct { + Length int + Value string + ErrCount int + } + + invalidCases := []testCases{ + { + Length: 8, + Value: acctest.RandString(16), + ErrCount: 1, + }, + { + Length: 123, + Value: `{"abc":}`, + ErrCount: 1, + }, + { + Length: 1, + Value: `{"abc":["1","2"]}`, + ErrCount: 1, + }, + } + + for _, tc := range invalidCases { + _, errors := validateEventPatternValue(tc.Length)(tc.Value, "event_pattern") + if len(errors) != tc.ErrCount { + t.Fatalf("Expected %q to trigger a validation error.", tc.Value) + } + } + + validCases := []testCases{ + { + Length: 0, + Value: ``, + ErrCount: 0, + }, + { + Length: 2, + Value: `{}`, + ErrCount: 0, + }, + { + Length: 18, + Value: `{"abc":["1","2"]}`, + ErrCount: 0, + }, + } + + for _, tc := range validCases { + _, errors := validateEventPatternValue(tc.Length)(tc.Value, "event_pattern") + if len(errors) != tc.ErrCount { + t.Fatalf("Expected %q not to trigger a validation error.", tc.Value) + } + } +} + var testAccAWSCloudWatchEventRuleConfig = ` resource "aws_cloudwatch_event_rule" "foo" { name = "tf-acc-cw-event-rule"