-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add cloudwatch_logs_subscription_filter provider
- Loading branch information
Showing
5 changed files
with
370 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
builtin/providers/aws/resource_aws_cloudwatch_log_subscription_filter.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package aws | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/aws/awserr" | ||
"github.com/aws/aws-sdk-go/service/cloudwatchlogs" | ||
"github.com/hashicorp/terraform/helper/hashcode" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
) | ||
|
||
func resourceAwsCloudwatchLogSubscriptionFilter() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceAwsCloudwatchLogSubscriptionFilterCreate, | ||
Read: resourceAwsCloudwatchLogSubscriptionFilterRead, | ||
Update: resourceAwsCloudwatchLogSubscriptionFilterUpdate, | ||
Delete: resourceAwsCloudwatchLogSubscriptionFilterDelete, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"name": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"destination_arn": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"filter_pattern": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: false, | ||
}, | ||
"log_group_name": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"role_arn": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Computed: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceAwsCloudwatchLogSubscriptionFilterCreate(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).cloudwatchlogsconn | ||
params := getAwsCloudWatchLogsSubscriptionFilterInput(d) | ||
log.Printf("[DEBUG] Creating SubscriptionFilter %#v", params) | ||
|
||
return resource.Retry(30*time.Second, func() *resource.RetryError { | ||
_, err := conn.PutSubscriptionFilter(¶ms) | ||
|
||
if err == nil { | ||
d.SetId(cloudwatchLogsSubscriptionFilterId(d.Get("log_group_name").(string))) | ||
log.Printf("[DEBUG] Cloudwatch logs subscription %q created", d.Id()) | ||
} | ||
|
||
awsErr, ok := err.(awserr.Error) | ||
if !ok { | ||
return resource.RetryableError(err) | ||
} | ||
|
||
if awsErr.Code() == "InvalidParameterException" { | ||
log.Printf("[DEBUG] Caught message: %q, code: %q: Retrying", awsErr.Message(), awsErr.Code()) | ||
resource.NonRetryableError(err) | ||
} | ||
|
||
return resource.NonRetryableError(err) | ||
}) | ||
} | ||
|
||
func resourceAwsCloudwatchLogSubscriptionFilterUpdate(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).cloudwatchlogsconn | ||
|
||
params := getAwsCloudWatchLogsSubscriptionFilterInput(d) | ||
|
||
log.Printf("[DEBUG] Update SubscriptionFilter %#v", params) | ||
_, err := conn.PutSubscriptionFilter(¶ms) | ||
if err != nil { | ||
if awsErr, ok := err.(awserr.Error); ok { | ||
return fmt.Errorf("[WARN] Error updating SubscriptionFilter (%s) for LogGroup (%s), message: \"%s\", code: \"%s\"", | ||
d.Get("name").(string), d.Get("log_group_name").(string), awsErr.Message(), awsErr.Code()) | ||
} | ||
return err | ||
} | ||
|
||
d.SetId(cloudwatchLogsSubscriptionFilterId(d.Get("log_group_name").(string))) | ||
return resourceAwsCloudwatchLogSubscriptionFilterRead(d, meta) | ||
} | ||
|
||
func getAwsCloudWatchLogsSubscriptionFilterInput(d *schema.ResourceData) cloudwatchlogs.PutSubscriptionFilterInput { | ||
name := d.Get("name").(string) | ||
destination_arn := d.Get("destination_arn").(string) | ||
filter_pattern := d.Get("filter_pattern").(string) | ||
log_group_name := d.Get("log_group_name").(string) | ||
|
||
params := cloudwatchlogs.PutSubscriptionFilterInput{ | ||
FilterName: aws.String(name), | ||
DestinationArn: aws.String(destination_arn), | ||
FilterPattern: aws.String(filter_pattern), | ||
LogGroupName: aws.String(log_group_name), | ||
} | ||
|
||
if _, ok := d.GetOk("role_arn"); ok { | ||
params.RoleArn = aws.String(d.Get("role_arn").(string)) | ||
} | ||
|
||
return params | ||
} | ||
|
||
func resourceAwsCloudwatchLogSubscriptionFilterRead(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).cloudwatchlogsconn | ||
|
||
log_group_name := d.Get("log_group_name").(string) | ||
name := d.Get("name").(string) // "name" is a required field in the schema | ||
|
||
req := &cloudwatchlogs.DescribeSubscriptionFiltersInput{ | ||
LogGroupName: aws.String(log_group_name), | ||
FilterNamePrefix: aws.String(name), | ||
} | ||
|
||
resp, err := conn.DescribeSubscriptionFilters(req) | ||
if err != nil { | ||
return fmt.Errorf("Error reading SubscriptionFilters for log group %s with name prefix %s: %#v", log_group_name, d.Get("name").(string), err) | ||
} | ||
|
||
for _, subscriptionFilter := range resp.SubscriptionFilters { | ||
if *subscriptionFilter.LogGroupName == log_group_name { | ||
d.SetId(cloudwatchLogsSubscriptionFilterId(log_group_name)) | ||
return nil // OK, matching subscription filter found | ||
} | ||
} | ||
|
||
return fmt.Errorf("Subscription filter for log group %s with name prefix %s not found!", log_group_name, d.Get("name").(string)) | ||
} | ||
|
||
func resourceAwsCloudwatchLogSubscriptionFilterDelete(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).cloudwatchlogsconn | ||
log.Printf("[INFO] Deleting CloudWatch Log Group Subscription: %s", d.Id()) | ||
log_group_name := d.Get("log_group_name").(string) | ||
name := d.Get("name").(string) | ||
|
||
params := &cloudwatchlogs.DeleteSubscriptionFilterInput{ | ||
FilterName: aws.String(name), // Required | ||
LogGroupName: aws.String(log_group_name), // Required | ||
} | ||
_, err := conn.DeleteSubscriptionFilter(params) | ||
if err != nil { | ||
return fmt.Errorf( | ||
"Error deleting Subscription Filter from log group: %s with name filter name %s", log_group_name, name) | ||
} | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
func cloudwatchLogsSubscriptionFilterId(log_group_name string) string { | ||
var buf bytes.Buffer | ||
|
||
buf.WriteString(fmt.Sprintf("%s-", log_group_name)) // only one filter allowed per log_group_name at the moment | ||
|
||
return fmt.Sprintf("cwlsf-%d", hashcode.String(buf.String())) | ||
} |
155 changes: 155 additions & 0 deletions
155
builtin/providers/aws/resource_aws_cloudwatch_log_subscription_filter_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/lambda" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccAWSCloudwatchLogSubscriptionFilter_basic(t *testing.T) { | ||
var conf lambda.GetFunctionOutput | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckCloudwatchLogSubscriptionFilterDestroy, | ||
Steps: []resource.TestStep{ | ||
resource.TestStep{ | ||
Config: testAccAWSCloudwatchLogSubscriptionFilterConfig, | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAwsCloudwatchLogSubscriptionFilterExists("aws_cloudwatch_log_subscription_filter.test_lambdafunction_logfilter", &conf), | ||
testAccCheckAWSCloudwatchLogSubscriptionFilterAttributes(&conf), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckCloudwatchLogSubscriptionFilterDestroy(s *terraform.State) error { | ||
conn := testAccProvider.Meta().(*AWSClient).lambdaconn | ||
|
||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "aws_cloudwatch_log_subscription_filter" { | ||
continue | ||
} | ||
|
||
_, err := conn.GetFunction(&lambda.GetFunctionInput{ | ||
FunctionName: aws.String(rs.Primary.ID), | ||
}) | ||
|
||
if err == nil { | ||
return fmt.Errorf("Lambda Function still exists") | ||
} | ||
|
||
} | ||
|
||
return nil | ||
|
||
} | ||
|
||
func testAccCheckAwsCloudwatchLogSubscriptionFilterExists(n string, function *lambda.GetFunctionOutput) resource.TestCheckFunc { | ||
// Wait for IAM role | ||
return func(s *terraform.State) error { | ||
rs, ok := s.RootModule().Resources[n] | ||
if !ok { | ||
return fmt.Errorf("Lambda function not found: %s", n) | ||
} | ||
|
||
if rs.Primary.ID == "" { | ||
return fmt.Errorf("Lambda function ID not set") | ||
} | ||
|
||
conn := testAccProvider.Meta().(*AWSClient).lambdaconn | ||
|
||
params := &lambda.GetFunctionInput{ | ||
FunctionName: aws.String("example_lambda_name"), | ||
} | ||
|
||
getFunction, err := conn.GetFunction(params) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
*function = *getFunction | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func testAccCheckAWSCloudwatchLogSubscriptionFilterAttributes(function *lambda.GetFunctionOutput) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
c := function.Configuration | ||
const expectedName = "example_lambda_name" | ||
if *c.FunctionName != expectedName { | ||
return fmt.Errorf("Expected function name %s, got %s", expectedName, *c.FunctionName) | ||
} | ||
|
||
if *c.FunctionArn == "" { | ||
return fmt.Errorf("Could not read Lambda Function's ARN") | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
const testAccAWSCloudwatchLogSubscriptionFilterConfig = ` | ||
resource "aws_cloudwatch_log_subscription_filter" "test_lambdafunction_logfilter" { | ||
name = "test_lambdafunction_logfilter" | ||
role_arn = "${aws_iam_role.iam_for_lambda.arn}" | ||
log_group_name = "/aws/lambda/example_lambda_name" | ||
filter_pattern = "logtype test" | ||
destination_arn = "${aws_kinesis_stream.test_logstream.arn}" | ||
} | ||
resource "aws_lambda_function" "test_lambdafunction" { | ||
filename = "test-fixtures/lambdatest.zip" | ||
function_name = "example_lambda_name" | ||
handler = "exports.example" | ||
} | ||
resource "aws_kinesis_stream" "test_logstream" { | ||
name = "test_logstream" | ||
shard_count = 1 | ||
} | ||
resource "aws_iam_role" "iam_for_lambda" { | ||
name = "test_lambdafuntion_iam_role" | ||
assume_role_policy = <<EOF | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Action": "sts:AssumeRole", | ||
"Principal": { | ||
"Service": "lambda.amazonaws.com" | ||
}, | ||
"Effect": "Allow", | ||
"Sid": "" | ||
} | ||
] | ||
} | ||
EOF | ||
} | ||
resource "aws_iam_role_policy" "test_lambdafunction_iam_policy" { | ||
name = "test_lambdafunction_iam_policy" | ||
role = "${aws_iam_role.iam_for_lambda.id}" | ||
policy = <<EOF | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Sid": "Stmt1441111030000", | ||
"Effect": "Allow", | ||
"Action": [ | ||
"dynamodb:*" | ||
], | ||
"Resource": [ | ||
"*" | ||
] | ||
} | ||
] | ||
} | ||
EOF | ||
} | ||
` |
39 changes: 39 additions & 0 deletions
39
...te/source/docs/providers/aws/r/cloudwatch_log_subscription_filter.html.markdown
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
--- | ||
layout: "aws" | ||
page_title: "AWS: aws_cloudwatch_log_subscription_filter" | ||
sidebar_current: "docs-aws-resource-cloudwatch-log-subscription-filter" | ||
description: |- | ||
Provides a CloudWatch Logs subscription filter. | ||
--- | ||
|
||
# aws\_cloudwatch\_logs\_subscription\_filter | ||
|
||
Provides a CloudWatch Logs subscription filter resource. | ||
|
||
## Example Usage | ||
|
||
``` | ||
resource "aws_cloudwatch_log_subscription_filter" "test_lambdafunction_logfilter" { | ||
name = "test_lambdafunction_logfilter" | ||
role_arn = "${aws_iam_role.iam_for_lambda.arn}" | ||
log_group_name = "/aws/lambda/example_lambda_name" | ||
filter_pattern = "logtype test" | ||
destination_arn = "${aws_kinesis_stream.test_logstream.arn}" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `name` - (Required) A name for the subscription filter | ||
* `destination_arn` - (Required) The ARN of the destination to deliver matching log events to. Currently only Kinesis stream / a logical destination | ||
* `filter_pattern` - (Required) A valid CloudWatch Logs filter pattern for subscribing to a filtered stream of log events. | ||
* `log_group_name` - (Required) The name of the log group to associate the subscription filter with | ||
* `role_arn` - (Optional) The ARN of an IAM role that grants Amazon CloudWatch Logs permissions to deliver ingested log events to the destination stream | ||
|
||
## Attributes Reference | ||
|
||
The following attributes are exported: | ||
|
||
* `arn` - The Amazon Resource Name (ARN) specifying the log subscription filter. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters