Merge pull request #5444 from TimeIncOSS/f-aws-logs-metric-filter
provider/aws: Add support for CloudWatch Log Metric Filter
This commit is contained in:
commit
f946695187
|
@ -133,6 +133,7 @@ func Provider() terraform.ResourceProvider {
|
||||||
"aws_cloudwatch_event_rule": resourceAwsCloudWatchEventRule(),
|
"aws_cloudwatch_event_rule": resourceAwsCloudWatchEventRule(),
|
||||||
"aws_cloudwatch_event_target": resourceAwsCloudWatchEventTarget(),
|
"aws_cloudwatch_event_target": resourceAwsCloudWatchEventTarget(),
|
||||||
"aws_cloudwatch_log_group": resourceAwsCloudWatchLogGroup(),
|
"aws_cloudwatch_log_group": resourceAwsCloudWatchLogGroup(),
|
||||||
|
"aws_cloudwatch_log_metric_filter": resourceAwsCloudWatchLogMetricFilter(),
|
||||||
"aws_autoscaling_lifecycle_hook": resourceAwsAutoscalingLifecycleHook(),
|
"aws_autoscaling_lifecycle_hook": resourceAwsAutoscalingLifecycleHook(),
|
||||||
"aws_cloudwatch_metric_alarm": resourceAwsCloudWatchMetricAlarm(),
|
"aws_cloudwatch_metric_alarm": resourceAwsCloudWatchMetricAlarm(),
|
||||||
"aws_codedeploy_app": resourceAwsCodeDeployApp(),
|
"aws_codedeploy_app": resourceAwsCodeDeployApp(),
|
||||||
|
|
|
@ -22,6 +22,7 @@ func resourceAwsCloudWatchLogGroup() *schema.Resource {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
|
ValidateFunc: validateLogGroupName,
|
||||||
},
|
},
|
||||||
|
|
||||||
"retention_in_days": &schema.Schema{
|
"retention_in_days": &schema.Schema{
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceAwsCloudWatchLogMetricFilter() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceAwsCloudWatchLogMetricFilterUpdate,
|
||||||
|
Read: resourceAwsCloudWatchLogMetricFilterRead,
|
||||||
|
Update: resourceAwsCloudWatchLogMetricFilterUpdate,
|
||||||
|
Delete: resourceAwsCloudWatchLogMetricFilterDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
ValidateFunc: validateLogMetricFilterName,
|
||||||
|
},
|
||||||
|
|
||||||
|
"pattern": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validateMaxLength(512),
|
||||||
|
StateFunc: func(v interface{}) string {
|
||||||
|
s, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(s)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"log_group_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
ValidateFunc: validateLogGroupName,
|
||||||
|
},
|
||||||
|
|
||||||
|
"metric_transformation": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Required: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validateLogMetricFilterTransformationName,
|
||||||
|
},
|
||||||
|
"namespace": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validateLogMetricFilterTransformationName,
|
||||||
|
},
|
||||||
|
"value": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validateMaxLength(100),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsCloudWatchLogMetricFilterUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).cloudwatchlogsconn
|
||||||
|
|
||||||
|
input := cloudwatchlogs.PutMetricFilterInput{
|
||||||
|
FilterName: aws.String(d.Get("name").(string)),
|
||||||
|
FilterPattern: aws.String(strings.TrimSpace(d.Get("pattern").(string))),
|
||||||
|
LogGroupName: aws.String(d.Get("log_group_name").(string)),
|
||||||
|
}
|
||||||
|
|
||||||
|
transformations := d.Get("metric_transformation").([]interface{})
|
||||||
|
o := transformations[0].(map[string]interface{})
|
||||||
|
input.MetricTransformations = expandCloudWachLogMetricTransformations(o)
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Creating/Updating CloudWatch Log Metric Filter: %s", input)
|
||||||
|
_, err := conn.PutMetricFilter(&input)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Creating/Updating CloudWatch Log Metric Filter failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(d.Get("name").(string))
|
||||||
|
|
||||||
|
log.Println("[INFO] CloudWatch Log Metric Filter created/updated")
|
||||||
|
|
||||||
|
return resourceAwsCloudWatchLogMetricFilterRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsCloudWatchLogMetricFilterRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).cloudwatchlogsconn
|
||||||
|
|
||||||
|
mf, err := lookupCloudWatchLogMetricFilter(conn, d.Get("name").(string),
|
||||||
|
d.Get("log_group_name").(string), nil)
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(*resource.NotFoundError); ok {
|
||||||
|
log.Printf("[WARN] Removing CloudWatch Log Metric Filter as it is gone")
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Failed reading CloudWatch Log Metric Filter: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Found CloudWatch Log Metric Filter: %s", mf)
|
||||||
|
|
||||||
|
d.Set("name", mf.FilterName)
|
||||||
|
d.Set("pattern", mf.FilterPattern)
|
||||||
|
d.Set("metric_transformation", flattenCloudWachLogMetricTransformations(mf.MetricTransformations))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupCloudWatchLogMetricFilter(conn *cloudwatchlogs.CloudWatchLogs,
|
||||||
|
name, logGroupName string, nextToken *string) (*cloudwatchlogs.MetricFilter, error) {
|
||||||
|
|
||||||
|
input := cloudwatchlogs.DescribeMetricFiltersInput{
|
||||||
|
FilterNamePrefix: aws.String(name),
|
||||||
|
LogGroupName: aws.String(logGroupName),
|
||||||
|
NextToken: nextToken,
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG] Reading CloudWatch Log Metric Filter: %s", input)
|
||||||
|
resp, err := conn.DescribeMetricFilters(&input)
|
||||||
|
if err != nil {
|
||||||
|
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceNotFoundException" {
|
||||||
|
return nil, &resource.NotFoundError{
|
||||||
|
Message: fmt.Sprintf("CloudWatch Log Metric Filter %q / %q not found via"+
|
||||||
|
" initial DescribeMetricFilters call", name, logGroupName),
|
||||||
|
LastError: err,
|
||||||
|
LastRequest: input,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("Failed describing CloudWatch Log Metric Filter: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, mf := range resp.MetricFilters {
|
||||||
|
if *mf.FilterName == name {
|
||||||
|
return mf, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.NextToken != nil {
|
||||||
|
return lookupCloudWatchLogMetricFilter(conn, name, logGroupName, resp.NextToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, &resource.NotFoundError{
|
||||||
|
Message: fmt.Sprintf("CloudWatch Log Metric Filter %q / %q not found "+
|
||||||
|
"in given results from DescribeMetricFilters", name, logGroupName),
|
||||||
|
LastResponse: resp,
|
||||||
|
LastRequest: input,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsCloudWatchLogMetricFilterDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).cloudwatchlogsconn
|
||||||
|
|
||||||
|
input := cloudwatchlogs.DeleteMetricFilterInput{
|
||||||
|
FilterName: aws.String(d.Get("name").(string)),
|
||||||
|
LogGroupName: aws.String(d.Get("log_group_name").(string)),
|
||||||
|
}
|
||||||
|
log.Printf("[INFO] Deleting CloudWatch Log Metric Filter: %s", d.Id())
|
||||||
|
_, err := conn.DeleteMetricFilter(&input)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleting CloudWatch Log Metric Filter: %s", err)
|
||||||
|
}
|
||||||
|
log.Println("[INFO] CloudWatch Log Metric Filter deleted")
|
||||||
|
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,185 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccAWSCloudWatchLogMetricFilter_basic(t *testing.T) {
|
||||||
|
var mf cloudwatchlogs.MetricFilter
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSCloudWatchLogMetricFilterDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSCloudWatchLogMetricFilterConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckCloudWatchLogMetricFilterExists("aws_cloudwatch_log_metric_filter.foobar", &mf),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "name", "MyAppAccessCount"),
|
||||||
|
testAccCheckCloudWatchLogMetricFilterName(&mf, "MyAppAccessCount"),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "pattern", ""),
|
||||||
|
testAccCheckCloudWatchLogMetricFilterPattern(&mf, ""),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "log_group_name", "MyApp/access.log"),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.name", "EventCount"),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.namespace", "YourNamespace"),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.value", "1"),
|
||||||
|
testAccCheckCloudWatchLogMetricFilterTransformation(&mf, &cloudwatchlogs.MetricTransformation{
|
||||||
|
MetricName: aws.String("EventCount"),
|
||||||
|
MetricNamespace: aws.String("YourNamespace"),
|
||||||
|
MetricValue: aws.String("1"),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSCloudWatchLogMetricFilterConfigModified,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckCloudWatchLogMetricFilterExists("aws_cloudwatch_log_metric_filter.foobar", &mf),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "name", "MyAppAccessCount"),
|
||||||
|
testAccCheckCloudWatchLogMetricFilterName(&mf, "MyAppAccessCount"),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "pattern", "{ $.errorCode = \"AccessDenied\" }"),
|
||||||
|
testAccCheckCloudWatchLogMetricFilterPattern(&mf, "{ $.errorCode = \"AccessDenied\" }"),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "log_group_name", "MyApp/access.log"),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.name", "AccessDeniedCount"),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.namespace", "MyNamespace"),
|
||||||
|
resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.value", "2"),
|
||||||
|
testAccCheckCloudWatchLogMetricFilterTransformation(&mf, &cloudwatchlogs.MetricTransformation{
|
||||||
|
MetricName: aws.String("AccessDeniedCount"),
|
||||||
|
MetricNamespace: aws.String("MyNamespace"),
|
||||||
|
MetricValue: aws.String("2"),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckCloudWatchLogMetricFilterName(mf *cloudwatchlogs.MetricFilter, name string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
if name != *mf.FilterName {
|
||||||
|
return fmt.Errorf("Expected filter name: %q, given: %q", name, *mf.FilterName)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckCloudWatchLogMetricFilterPattern(mf *cloudwatchlogs.MetricFilter, pattern string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
if mf.FilterPattern == nil {
|
||||||
|
if pattern != "" {
|
||||||
|
return fmt.Errorf("Received empty filter pattern, expected: %q", pattern)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if pattern != *mf.FilterPattern {
|
||||||
|
return fmt.Errorf("Expected filter pattern: %q, given: %q", pattern, *mf.FilterPattern)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckCloudWatchLogMetricFilterTransformation(mf *cloudwatchlogs.MetricFilter,
|
||||||
|
t *cloudwatchlogs.MetricTransformation) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
given := mf.MetricTransformations[0]
|
||||||
|
expected := t
|
||||||
|
|
||||||
|
if *given.MetricName != *expected.MetricName {
|
||||||
|
return fmt.Errorf("Expected metric name: %q, received: %q",
|
||||||
|
*expected.MetricName, *given.MetricName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *given.MetricNamespace != *expected.MetricNamespace {
|
||||||
|
return fmt.Errorf("Expected metric namespace: %q, received: %q",
|
||||||
|
*expected.MetricNamespace, *given.MetricNamespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *given.MetricValue != *expected.MetricValue {
|
||||||
|
return fmt.Errorf("Expected metric value: %q, received: %q",
|
||||||
|
*expected.MetricValue, *given.MetricValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckCloudWatchLogMetricFilterExists(n string, mf *cloudwatchlogs.MetricFilter) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).cloudwatchlogsconn
|
||||||
|
metricFilter, err := lookupCloudWatchLogMetricFilter(conn, rs.Primary.ID, rs.Primary.Attributes["log_group_name"], nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*mf = *metricFilter
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSCloudWatchLogMetricFilterDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).cloudwatchlogsconn
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "aws_cloudwatch_log_metric_filter" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := lookupCloudWatchLogMetricFilter(conn, rs.Primary.ID, rs.Primary.Attributes["log_group_name"], nil)
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("MetricFilter Still Exists: %s", rs.Primary.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var testAccAWSCloudWatchLogMetricFilterConfig = `
|
||||||
|
resource "aws_cloudwatch_log_metric_filter" "foobar" {
|
||||||
|
name = "MyAppAccessCount"
|
||||||
|
pattern = ""
|
||||||
|
log_group_name = "${aws_cloudwatch_log_group.dada.name}"
|
||||||
|
|
||||||
|
metric_transformation {
|
||||||
|
name = "EventCount"
|
||||||
|
namespace = "YourNamespace"
|
||||||
|
value = "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_log_group" "dada" {
|
||||||
|
name = "MyApp/access.log"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
var testAccAWSCloudWatchLogMetricFilterConfigModified = `
|
||||||
|
resource "aws_cloudwatch_log_metric_filter" "foobar" {
|
||||||
|
name = "MyAppAccessCount"
|
||||||
|
pattern = <<PATTERN
|
||||||
|
{ $.errorCode = "AccessDenied" }
|
||||||
|
PATTERN
|
||||||
|
log_group_name = "${aws_cloudwatch_log_group.dada.name}"
|
||||||
|
|
||||||
|
metric_transformation {
|
||||||
|
name = "AccessDeniedCount"
|
||||||
|
namespace = "MyNamespace"
|
||||||
|
value = "2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_log_group" "dada" {
|
||||||
|
name = "MyApp/access.log"
|
||||||
|
}
|
||||||
|
`
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/service/apigateway"
|
"github.com/aws/aws-sdk-go/service/apigateway"
|
||||||
"github.com/aws/aws-sdk-go/service/autoscaling"
|
"github.com/aws/aws-sdk-go/service/autoscaling"
|
||||||
"github.com/aws/aws-sdk-go/service/cloudformation"
|
"github.com/aws/aws-sdk-go/service/cloudformation"
|
||||||
|
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
|
||||||
"github.com/aws/aws-sdk-go/service/directoryservice"
|
"github.com/aws/aws-sdk-go/service/directoryservice"
|
||||||
"github.com/aws/aws-sdk-go/service/ec2"
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
"github.com/aws/aws-sdk-go/service/ecs"
|
"github.com/aws/aws-sdk-go/service/ecs"
|
||||||
|
@ -924,3 +925,23 @@ func expandApiGatewayStageKeyOperations(d *schema.ResourceData) []*apigateway.Pa
|
||||||
|
|
||||||
return operations
|
return operations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func expandCloudWachLogMetricTransformations(m map[string]interface{}) []*cloudwatchlogs.MetricTransformation {
|
||||||
|
transformation := cloudwatchlogs.MetricTransformation{
|
||||||
|
MetricName: aws.String(m["name"].(string)),
|
||||||
|
MetricNamespace: aws.String(m["namespace"].(string)),
|
||||||
|
MetricValue: aws.String(m["value"].(string)),
|
||||||
|
}
|
||||||
|
|
||||||
|
return []*cloudwatchlogs.MetricTransformation{&transformation}
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenCloudWachLogMetricTransformations(ts []*cloudwatchlogs.MetricTransformation) map[string]string {
|
||||||
|
m := make(map[string]string, 0)
|
||||||
|
|
||||||
|
m["name"] = *ts[0].MetricName
|
||||||
|
m["namespace"] = *ts[0].MetricNamespace
|
||||||
|
m["value"] = *ts[0].MetricValue
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
|
@ -308,3 +308,62 @@ func validateHTTPMethod(v interface{}, k string) (ws []string, errors []error) {
|
||||||
}
|
}
|
||||||
return
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package resource
|
||||||
|
|
||||||
|
type NotFoundError struct {
|
||||||
|
LastError error
|
||||||
|
LastRequest interface{}
|
||||||
|
LastResponse interface{}
|
||||||
|
Message string
|
||||||
|
Retries int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *NotFoundError) Error() string {
|
||||||
|
if e.Message != "" {
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
return "couldn't find resource"
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNotFoundError(err string) *NotFoundError {
|
||||||
|
return &NotFoundError{Message: err}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: aws_cloudwatch_log_metric_filter"
|
||||||
|
sidebar_current: "docs-aws-resource-cloudwatch-log-metric-filter"
|
||||||
|
description: |-
|
||||||
|
Provides a CloudWatch Log Metric Filter resource.
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_cloudwatch\_log\_metric\_filter
|
||||||
|
|
||||||
|
Provides a CloudWatch Log Metric Filter resource.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_cloudwatch_log_metric_filter" "yada" {
|
||||||
|
name = "MyAppAccessCount"
|
||||||
|
pattern = ""
|
||||||
|
log_group_name = "${aws_cloudwatch_log_group.dada.name}"
|
||||||
|
|
||||||
|
metric_transformation {
|
||||||
|
name = "EventCount"
|
||||||
|
namespace = "YourNamespace"
|
||||||
|
value = "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_log_group" "dada" {
|
||||||
|
name = "MyApp/access.log"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) A name for the metric filter.
|
||||||
|
* `pattern` - (Required) A valid [CloudWatch Logs filter pattern](https://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/FilterAndPatternSyntax.html)
|
||||||
|
for extracting metric data out of ingested log events.
|
||||||
|
* `log_group_name` - (Required) The name of the log group to associate the metric filter with.
|
||||||
|
* `metric_transformation` - (Required) A block defining collection of information
|
||||||
|
needed to define how metric data gets emitted. See below.
|
||||||
|
|
||||||
|
The `metric_transformation` block supports the following arguments:
|
||||||
|
|
||||||
|
* `name` - (Required) The name of the CloudWatch metric to which the monitored log information should be published (e.g. `ErrorCount`)
|
||||||
|
* `namespace` - (Required) The destination namespace of the CloudWatch metric.
|
||||||
|
* `value` - (Required) What to publish to the metric. For example, if you're counting the occurrences of a particular term like "Error", the value will be "1" for each occurrence. If you're counting the bytes transferred the published value will be the value in the log event.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `id` - The name of the metric filter.
|
|
@ -76,6 +76,10 @@
|
||||||
<a href="/docs/providers/aws/r/cloudwatch_log_group.html">aws_cloudwatch_log_group</a>
|
<a href="/docs/providers/aws/r/cloudwatch_log_group.html">aws_cloudwatch_log_group</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-cloudwatch-log-metric-filter") %>>
|
||||||
|
<a href="/docs/providers/aws/r/cloudwatch_log_metric_filter.html">aws_cloudwatch_log_metric_filter</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-aws-resource-cloudwatch-metric-alarm") %>>
|
<li<%= sidebar_current("docs-aws-resource-cloudwatch-metric-alarm") %>>
|
||||||
<a href="/docs/providers/aws/r/cloudwatch_metric_alarm.html">aws_cloudwatch_metric_alarm</a>
|
<a href="/docs/providers/aws/r/cloudwatch_metric_alarm.html">aws_cloudwatch_metric_alarm</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Reference in New Issue