diff --git a/builtin/providers/aws/resource_aws_cloudwatch_log_group.go b/builtin/providers/aws/resource_aws_cloudwatch_log_group.go index e4f7236b2de7..66416b7df186 100644 --- a/builtin/providers/aws/resource_aws_cloudwatch_log_group.go +++ b/builtin/providers/aws/resource_aws_cloudwatch_log_group.go @@ -19,9 +19,10 @@ func resourceAwsCloudWatchLogGroup() *schema.Resource { Schema: map[string]*schema.Schema{ "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateLogGroupName, }, "retention_in_days": &schema.Schema{ diff --git a/builtin/providers/aws/resource_aws_cloudwatch_log_metric_filter.go b/builtin/providers/aws/resource_aws_cloudwatch_log_metric_filter.go index 24e485518709..943472f85ecf 100644 --- a/builtin/providers/aws/resource_aws_cloudwatch_log_metric_filter.go +++ b/builtin/providers/aws/resource_aws_cloudwatch_log_metric_filter.go @@ -22,14 +22,16 @@ func resourceAwsCloudWatchLogMetricFilter() *schema.Resource { Schema: map[string]*schema.Schema{ "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateLogMetricFilterName, }, "pattern": &schema.Schema{ - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validateMaxLength(512), StateFunc: func(v interface{}) string { s, ok := v.(string) if !ok { @@ -40,9 +42,10 @@ func resourceAwsCloudWatchLogMetricFilter() *schema.Resource { }, "log_group_name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateLogGroupName, }, "metric_transformation": &schema.Schema{ @@ -52,16 +55,19 @@ func resourceAwsCloudWatchLogMetricFilter() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validateLogMetricFilterTransformationName, }, "namespace": &schema.Schema{ - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validateLogMetricFilterTransformationName, }, "value": &schema.Schema{ - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validateMaxLength(100), }, }, }, diff --git a/builtin/providers/aws/validators.go b/builtin/providers/aws/validators.go index 4dc60bfded7f..be19c483bb62 100644 --- a/builtin/providers/aws/validators.go +++ b/builtin/providers/aws/validators.go @@ -308,3 +308,62 @@ func validateHTTPMethod(v interface{}, k string) (ws []string, errors []error) { } return } + +func validateLogMetricFilterName(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + + if len(value) > 512 { + errors = append(errors, fmt.Errorf( + "%q cannot be longer than 512 characters: %q", k, value)) + } + + // http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutMetricFilter.html + pattern := `^[^:*]+$` + if !regexp.MustCompile(pattern).MatchString(value) { + errors = append(errors, fmt.Errorf( + "%q isn't a valid log metric name (must not contain colon nor asterisk): %q", + k, value)) + } + + return +} + +func validateLogMetricFilterTransformationName(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + + if len(value) > 255 { + errors = append(errors, fmt.Errorf( + "%q cannot be longer than 255 characters: %q", k, value)) + } + + // http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_MetricTransformation.html + pattern := `^[^:*$]*$` + if !regexp.MustCompile(pattern).MatchString(value) { + errors = append(errors, fmt.Errorf( + "%q isn't a valid log metric transformation name (must not contain"+ + " colon, asterisk nor dollar sign): %q", + k, value)) + } + + return +} + +func validateLogGroupName(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + + if len(value) > 512 { + errors = append(errors, fmt.Errorf( + "%q cannot be longer than 512 characters: %q", k, value)) + } + + // http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html + pattern := `^[\.\-_/#A-Za-z0-9]+$` + if !regexp.MustCompile(pattern).MatchString(value) { + errors = append(errors, fmt.Errorf( + "%q isn't a valid log group name (alphanumeric characters, underscores,"+ + " hyphens, slashes, hash signs and dots are allowed): %q", + k, value)) + } + + return +} diff --git a/builtin/providers/aws/validators_test.go b/builtin/providers/aws/validators_test.go index 2d4028fd56bb..972a9cbf2a55 100644 --- a/builtin/providers/aws/validators_test.go +++ b/builtin/providers/aws/validators_test.go @@ -285,3 +285,100 @@ func TestValidateHTTPMethod(t *testing.T) { } } } + +func TestValidateLogMetricFilterName(t *testing.T) { + validNames := []string{ + "YadaHereAndThere", + "Valid-5Metric_Name", + "This . is also %% valid@!)+(", + "1234", + strings.Repeat("W", 512), + } + for _, v := range validNames { + _, errors := validateLogMetricFilterName(v, "name") + if len(errors) != 0 { + t.Fatalf("%q should be a valid Log Metric Filter Name: %q", v, errors) + } + } + + invalidNames := []string{ + "Here is a name with: colon", + "and here is another * invalid name", + "*", + // length > 512 + strings.Repeat("W", 513), + } + for _, v := range invalidNames { + _, errors := validateLogMetricFilterName(v, "name") + if len(errors) == 0 { + t.Fatalf("%q should be an invalid Log Metric Filter Name", v) + } + } +} + +func TestValidateLogMetricTransformationName(t *testing.T) { + validNames := []string{ + "YadaHereAndThere", + "Valid-5Metric_Name", + "This . is also %% valid@!)+(", + "1234", + "", + strings.Repeat("W", 255), + } + for _, v := range validNames { + _, errors := validateLogMetricFilterTransformationName(v, "name") + if len(errors) != 0 { + t.Fatalf("%q should be a valid Log Metric Filter Transformation Name: %q", v, errors) + } + } + + invalidNames := []string{ + "Here is a name with: colon", + "and here is another * invalid name", + "also $ invalid", + "*", + // length > 255 + strings.Repeat("W", 256), + } + for _, v := range invalidNames { + _, errors := validateLogMetricFilterTransformationName(v, "name") + if len(errors) == 0 { + t.Fatalf("%q should be an invalid Log Metric Filter Transformation Name", v) + } + } +} + +func TestValidateLogGroupName(t *testing.T) { + validNames := []string{ + "ValidLogGroupName", + "ValidLogGroup.Name", + "valid/Log-group", + "1234", + "YadaValid#0123", + "Also_valid-name", + strings.Repeat("W", 512), + } + for _, v := range validNames { + _, errors := validateLogGroupName(v, "name") + if len(errors) != 0 { + t.Fatalf("%q should be a valid Log Metric Filter Transformation Name: %q", v, errors) + } + } + + invalidNames := []string{ + "Here is a name with: colon", + "and here is another * invalid name", + "also $ invalid", + "This . is also %% invalid@!)+(", + "*", + "", + // length > 512 + strings.Repeat("W", 513), + } + for _, v := range invalidNames { + _, errors := validateLogGroupName(v, "name") + if len(errors) == 0 { + t.Fatalf("%q should be an invalid Log Metric Filter Transformation Name", v) + } + } +}