Merge pull request #4986 from TimeIncOSS/f-aws-cloudwatch-events
provider/aws: Add support for CloudWatch Events
This commit is contained in:
commit
0e66f67246
|
@ -262,6 +262,11 @@
|
|||
"Comment": "v1.1.0",
|
||||
"Rev": "be2ec39e520e3c4088c0c6288055bdc8184a89ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/service/cloudwatchevents",
|
||||
"Comment": "v1.1.0",
|
||||
"Rev": "be2ec39e520e3c4088c0c6288055bdc8184a89ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/service/cloudwatchlogs",
|
||||
"Comment": "v1.1.0",
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/aws/aws-sdk-go/service/cloudformation"
|
||||
"github.com/aws/aws-sdk-go/service/cloudtrail"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatchevents"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
|
||||
"github.com/aws/aws-sdk-go/service/codecommit"
|
||||
"github.com/aws/aws-sdk-go/service/codedeploy"
|
||||
|
@ -74,6 +75,7 @@ type AWSClient struct {
|
|||
cloudtrailconn *cloudtrail.CloudTrail
|
||||
cloudwatchconn *cloudwatch.CloudWatch
|
||||
cloudwatchlogsconn *cloudwatchlogs.CloudWatchLogs
|
||||
cloudwatcheventsconn *cloudwatchevents.CloudWatchEvents
|
||||
dsconn *directoryservice.DirectoryService
|
||||
dynamodbconn *dynamodb.DynamoDB
|
||||
ec2conn *ec2.EC2
|
||||
|
@ -256,6 +258,9 @@ func (c *Config) Client() (interface{}, error) {
|
|||
log.Println("[INFO] Initializing CloudWatch SDK connection")
|
||||
client.cloudwatchconn = cloudwatch.New(sess)
|
||||
|
||||
log.Println("[INFO] Initializing CloudWatch Events connection")
|
||||
client.cloudwatcheventsconn = cloudwatchevents.New(sess)
|
||||
|
||||
log.Println("[INFO] Initializing CloudTrail connection")
|
||||
client.cloudtrailconn = cloudtrail.New(sess)
|
||||
|
||||
|
|
|
@ -121,6 +121,8 @@ func Provider() terraform.ResourceProvider {
|
|||
"aws_autoscaling_schedule": resourceAwsAutoscalingSchedule(),
|
||||
"aws_cloudformation_stack": resourceAwsCloudFormationStack(),
|
||||
"aws_cloudtrail": resourceAwsCloudTrail(),
|
||||
"aws_cloudwatch_event_rule": resourceAwsCloudWatchEventRule(),
|
||||
"aws_cloudwatch_event_target": resourceAwsCloudWatchEventTarget(),
|
||||
"aws_cloudwatch_log_group": resourceAwsCloudWatchLogGroup(),
|
||||
"aws_autoscaling_lifecycle_hook": resourceAwsAutoscalingLifecycleHook(),
|
||||
"aws_cloudwatch_metric_alarm": resourceAwsCloudWatchMetricAlarm(),
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
events "github.com/aws/aws-sdk-go/service/cloudwatchevents"
|
||||
)
|
||||
|
||||
func resourceAwsCloudWatchEventRule() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsCloudWatchEventRuleCreate,
|
||||
Read: resourceAwsCloudWatchEventRuleRead,
|
||||
Update: resourceAwsCloudWatchEventRuleUpdate,
|
||||
Delete: resourceAwsCloudWatchEventRuleDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateCloudWatchEventRuleName,
|
||||
},
|
||||
"schedule_expression": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateMaxLength(256),
|
||||
},
|
||||
"event_pattern": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateMaxLength(2048),
|
||||
StateFunc: normalizeJson,
|
||||
},
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateMaxLength(512),
|
||||
},
|
||||
"role_arn": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateMaxLength(1600),
|
||||
},
|
||||
"is_enabled": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
"arn": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchEventRuleCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).cloudwatcheventsconn
|
||||
|
||||
input := buildPutRuleInputStruct(d)
|
||||
log.Printf("[DEBUG] Creating CloudWatch Event Rule: %s", input)
|
||||
|
||||
// IAM Roles take some time to propagate
|
||||
var out *events.PutRuleOutput
|
||||
err := resource.Retry(30*time.Second, func() error {
|
||||
var err error
|
||||
out, err = conn.PutRule(input)
|
||||
pattern := regexp.MustCompile("cannot be assumed by principal '[a-z]+\\.amazonaws\\.com'\\.$")
|
||||
if err != nil {
|
||||
if awsErr, ok := err.(awserr.Error); ok {
|
||||
if awsErr.Code() == "ValidationException" && pattern.MatchString(awsErr.Message()) {
|
||||
log.Printf("[DEBUG] Retrying creation of CloudWatch Event Rule %q", *input.Name)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return &resource.RetryError{
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Creating CloudWatch Event Rule failed: %s", err)
|
||||
}
|
||||
|
||||
d.Set("arn", out.RuleArn)
|
||||
d.SetId(d.Get("name").(string))
|
||||
|
||||
log.Printf("[INFO] CloudWatch Event Rule %q created", *out.RuleArn)
|
||||
|
||||
return resourceAwsCloudWatchEventRuleUpdate(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchEventRuleRead(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).cloudwatcheventsconn
|
||||
|
||||
input := events.DescribeRuleInput{
|
||||
Name: aws.String(d.Id()),
|
||||
}
|
||||
log.Printf("[DEBUG] Reading CloudWatch Event Rule: %s", input)
|
||||
out, err := conn.DescribeRule(&input)
|
||||
if awsErr, ok := err.(awserr.Error); ok {
|
||||
if awsErr.Code() == "ResourceNotFoundException" {
|
||||
log.Printf("[WARN] Removing CloudWatch Event Rule %q because it's gone.", d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[DEBUG] Found Event Rule: %s", out)
|
||||
|
||||
d.Set("arn", out.Arn)
|
||||
d.Set("description", out.Description)
|
||||
if out.EventPattern != nil {
|
||||
d.Set("event_pattern", normalizeJson(*out.EventPattern))
|
||||
}
|
||||
d.Set("name", out.Name)
|
||||
d.Set("role_arn", out.RoleArn)
|
||||
d.Set("schedule_expression", out.ScheduleExpression)
|
||||
|
||||
boolState, err := getBooleanStateFromString(*out.State)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[DEBUG] Setting boolean state: %t", boolState)
|
||||
d.Set("is_enabled", boolState)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchEventRuleUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).cloudwatcheventsconn
|
||||
|
||||
if d.HasChange("is_enabled") && d.Get("is_enabled").(bool) {
|
||||
log.Printf("[DEBUG] Enabling CloudWatch Event Rule %q", d.Id())
|
||||
_, err := conn.EnableRule(&events.EnableRuleInput{
|
||||
Name: aws.String(d.Id()),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[DEBUG] CloudWatch Event Rule (%q) enabled", d.Id())
|
||||
}
|
||||
|
||||
input := buildPutRuleInputStruct(d)
|
||||
log.Printf("[DEBUG] Updating CloudWatch Event Rule: %s", input)
|
||||
|
||||
// IAM Roles take some time to propagate
|
||||
var out *events.PutRuleOutput
|
||||
err := resource.Retry(30*time.Second, func() error {
|
||||
var err error
|
||||
out, err = conn.PutRule(input)
|
||||
pattern := regexp.MustCompile("cannot be assumed by principal '[a-z]+\\.amazonaws\\.com'\\.$")
|
||||
if err != nil {
|
||||
if awsErr, ok := err.(awserr.Error); ok {
|
||||
if awsErr.Code() == "ValidationException" && pattern.MatchString(awsErr.Message()) {
|
||||
log.Printf("[DEBUG] Retrying update of CloudWatch Event Rule %q", *input.Name)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return &resource.RetryError{
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Updating CloudWatch Event Rule failed: %s", err)
|
||||
}
|
||||
|
||||
if d.HasChange("is_enabled") && !d.Get("is_enabled").(bool) {
|
||||
log.Printf("[DEBUG] Disabling CloudWatch Event Rule %q", d.Id())
|
||||
_, err := conn.DisableRule(&events.DisableRuleInput{
|
||||
Name: aws.String(d.Id()),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[DEBUG] CloudWatch Event Rule (%q) disabled", d.Id())
|
||||
}
|
||||
|
||||
return resourceAwsCloudWatchEventRuleRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchEventRuleDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).cloudwatcheventsconn
|
||||
|
||||
log.Printf("[INFO] Deleting CloudWatch Event Rule: %s", d.Id())
|
||||
_, err := conn.DeleteRule(&events.DeleteRuleInput{
|
||||
Name: aws.String(d.Id()),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting CloudWatch Event Rule: %s", err)
|
||||
}
|
||||
log.Println("[INFO] CloudWatch Event Rule deleted")
|
||||
|
||||
d.SetId("")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildPutRuleInputStruct(d *schema.ResourceData) *events.PutRuleInput {
|
||||
input := events.PutRuleInput{
|
||||
Name: aws.String(d.Get("name").(string)),
|
||||
}
|
||||
if v, ok := d.GetOk("description"); ok {
|
||||
input.Description = aws.String(v.(string))
|
||||
}
|
||||
if v, ok := d.GetOk("event_pattern"); ok {
|
||||
input.EventPattern = aws.String(v.(string))
|
||||
}
|
||||
if v, ok := d.GetOk("role_arn"); ok {
|
||||
input.RoleArn = aws.String(v.(string))
|
||||
}
|
||||
if v, ok := d.GetOk("schedule_expression"); ok {
|
||||
input.ScheduleExpression = aws.String(v.(string))
|
||||
}
|
||||
|
||||
input.State = aws.String(getStringStateFromBoolean(d.Get("is_enabled").(bool)))
|
||||
|
||||
return &input
|
||||
}
|
||||
|
||||
// State is represented as (ENABLED|DISABLED) in the API
|
||||
func getBooleanStateFromString(state string) (bool, error) {
|
||||
if state == "ENABLED" {
|
||||
return true, nil
|
||||
} else if state == "DISABLED" {
|
||||
return false, nil
|
||||
}
|
||||
// We don't just blindly trust AWS as they tend to return
|
||||
// unexpected values in similar cases (different casing etc.)
|
||||
return false, fmt.Errorf("Failed converting state %q into boolean", state)
|
||||
}
|
||||
|
||||
// State is represented as (ENABLED|DISABLED) in the API
|
||||
func getStringStateFromBoolean(isEnabled bool) string {
|
||||
if isEnabled {
|
||||
return "ENABLED"
|
||||
}
|
||||
return "DISABLED"
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
events "github.com/aws/aws-sdk-go/service/cloudwatchevents"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAWSCloudWatchEventRule_basic(t *testing.T) {
|
||||
var rule events.DescribeRuleOutput
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudWatchEventRuleDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSCloudWatchEventRuleConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudWatchEventRuleExists("aws_cloudwatch_event_rule.foo", &rule),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_rule.foo", "name", "tf-acc-cw-event-rule"),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: testAccAWSCloudWatchEventRuleConfigModified,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudWatchEventRuleExists("aws_cloudwatch_event_rule.foo", &rule),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_rule.foo", "name", "tf-acc-cw-event-rule-mod"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSCloudWatchEventRule_full(t *testing.T) {
|
||||
var rule events.DescribeRuleOutput
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudWatchEventRuleDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSCloudWatchEventRuleConfig_full,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudWatchEventRuleExists("aws_cloudwatch_event_rule.moobar", &rule),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_rule.moobar", "name", "tf-acc-cw-event-rule-full"),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_rule.moobar", "schedule_expression", "rate(5 minutes)"),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_rule.moobar", "event_pattern", "{\"source\":[\"aws.ec2\"]}"),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_rule.moobar", "description", "He's not dead, he's just resting!"),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_rule.moobar", "role_arn", ""),
|
||||
testAccCheckCloudWatchEventRuleEnabled("aws_cloudwatch_event_rule.moobar", "DISABLED", &rule),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSCloudWatchEventRule_enable(t *testing.T) {
|
||||
var rule events.DescribeRuleOutput
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudWatchEventRuleDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSCloudWatchEventRuleConfigEnabled,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudWatchEventRuleExists("aws_cloudwatch_event_rule.moo", &rule),
|
||||
testAccCheckCloudWatchEventRuleEnabled("aws_cloudwatch_event_rule.moo", "ENABLED", &rule),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: testAccAWSCloudWatchEventRuleConfigDisabled,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudWatchEventRuleExists("aws_cloudwatch_event_rule.moo", &rule),
|
||||
testAccCheckCloudWatchEventRuleEnabled("aws_cloudwatch_event_rule.moo", "DISABLED", &rule),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: testAccAWSCloudWatchEventRuleConfigEnabled,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudWatchEventRuleExists("aws_cloudwatch_event_rule.moo", &rule),
|
||||
testAccCheckCloudWatchEventRuleEnabled("aws_cloudwatch_event_rule.moo", "ENABLED", &rule),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckCloudWatchEventRuleExists(n string, rule *events.DescribeRuleOutput) 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).cloudwatcheventsconn
|
||||
params := events.DescribeRuleInput{
|
||||
Name: aws.String(rs.Primary.ID),
|
||||
}
|
||||
resp, err := conn.DescribeRule(¶ms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp == nil {
|
||||
return fmt.Errorf("Rule not found")
|
||||
}
|
||||
|
||||
*rule = *resp
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckCloudWatchEventRuleEnabled(n string, desired string, rule *events.DescribeRuleOutput) 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).cloudwatcheventsconn
|
||||
params := events.DescribeRuleInput{
|
||||
Name: aws.String(rs.Primary.ID),
|
||||
}
|
||||
resp, err := conn.DescribeRule(¶ms)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *resp.State != desired {
|
||||
return fmt.Errorf("Expected state %q, given %q", desired, *resp.State)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSCloudWatchEventRuleDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_cloudwatch_event_rule" {
|
||||
continue
|
||||
}
|
||||
|
||||
params := events.DescribeRuleInput{
|
||||
Name: aws.String(rs.Primary.ID),
|
||||
}
|
||||
|
||||
resp, err := conn.DescribeRule(¶ms)
|
||||
|
||||
if err == nil {
|
||||
return fmt.Errorf("CloudWatch Event Rule %q still exists: %s",
|
||||
rs.Primary.ID, resp)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccAWSCloudWatchEventRuleConfig = `
|
||||
resource "aws_cloudwatch_event_rule" "foo" {
|
||||
name = "tf-acc-cw-event-rule"
|
||||
schedule_expression = "rate(1 hour)"
|
||||
}
|
||||
`
|
||||
|
||||
var testAccAWSCloudWatchEventRuleConfigEnabled = `
|
||||
resource "aws_cloudwatch_event_rule" "moo" {
|
||||
name = "tf-acc-cw-event-rule-state"
|
||||
schedule_expression = "rate(1 hour)"
|
||||
}
|
||||
`
|
||||
var testAccAWSCloudWatchEventRuleConfigDisabled = `
|
||||
resource "aws_cloudwatch_event_rule" "moo" {
|
||||
name = "tf-acc-cw-event-rule-state"
|
||||
schedule_expression = "rate(1 hour)"
|
||||
is_enabled = false
|
||||
}
|
||||
`
|
||||
|
||||
var testAccAWSCloudWatchEventRuleConfigModified = `
|
||||
resource "aws_cloudwatch_event_rule" "foo" {
|
||||
name = "tf-acc-cw-event-rule-mod"
|
||||
schedule_expression = "rate(1 hour)"
|
||||
}
|
||||
`
|
||||
|
||||
var testAccAWSCloudWatchEventRuleConfig_full = `
|
||||
resource "aws_cloudwatch_event_rule" "moobar" {
|
||||
name = "tf-acc-cw-event-rule-full"
|
||||
schedule_expression = "rate(5 minutes)"
|
||||
event_pattern = <<PATTERN
|
||||
{ "source": ["aws.ec2"] }
|
||||
PATTERN
|
||||
description = "He's not dead, he's just resting!"
|
||||
is_enabled = false
|
||||
}
|
||||
`
|
||||
|
||||
// TODO: Figure out example with IAM Role
|
|
@ -0,0 +1,186 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
events "github.com/aws/aws-sdk-go/service/cloudwatchevents"
|
||||
)
|
||||
|
||||
func resourceAwsCloudWatchEventTarget() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsCloudWatchEventTargetCreate,
|
||||
Read: resourceAwsCloudWatchEventTargetRead,
|
||||
Update: resourceAwsCloudWatchEventTargetUpdate,
|
||||
Delete: resourceAwsCloudWatchEventTargetDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"rule": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateCloudWatchEventRuleName,
|
||||
},
|
||||
|
||||
"target_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateCloudWatchEventTargetId,
|
||||
},
|
||||
|
||||
"arn": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"input": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"input_path"},
|
||||
// We could be normalizing the JSON here,
|
||||
// but for built-in targets input may not be JSON
|
||||
},
|
||||
|
||||
"input_path": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"input"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchEventTargetCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).cloudwatcheventsconn
|
||||
|
||||
rule := d.Get("rule").(string)
|
||||
targetId := d.Get("target_id").(string)
|
||||
|
||||
id := rule + "-" + targetId
|
||||
d.SetId(id)
|
||||
|
||||
input := buildPutTargetInputStruct(d)
|
||||
log.Printf("[DEBUG] Creating CloudWatch Event Target: %s", input)
|
||||
out, err := conn.PutTargets(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Creating CloudWatch Event Target failed: %s", err)
|
||||
}
|
||||
|
||||
if len(out.FailedEntries) > 0 {
|
||||
return fmt.Errorf("Creating CloudWatch Event Target failed: %s",
|
||||
out.FailedEntries)
|
||||
}
|
||||
|
||||
log.Printf("[INFO] CloudWatch Event Target %q created", d.Id())
|
||||
|
||||
return resourceAwsCloudWatchEventTargetRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchEventTargetRead(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).cloudwatcheventsconn
|
||||
|
||||
t, err := findEventTargetById(
|
||||
d.Get("target_id").(string),
|
||||
d.Get("rule").(string),
|
||||
nil, conn)
|
||||
if err != nil {
|
||||
if regexp.MustCompile(" not found$").MatchString(err.Error()) {
|
||||
log.Printf("[WARN] Removing CloudWatch Event Target %q because it's gone.", d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
log.Printf("[DEBUG] Found Event Target: %s", t)
|
||||
|
||||
d.Set("arn", t.Arn)
|
||||
d.Set("target_id", t.Id)
|
||||
d.Set("input", t.Input)
|
||||
d.Set("input_path", t.InputPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func findEventTargetById(id, rule string, nextToken *string, conn *events.CloudWatchEvents) (
|
||||
*events.Target, error) {
|
||||
input := events.ListTargetsByRuleInput{
|
||||
Rule: aws.String(rule),
|
||||
NextToken: nextToken,
|
||||
Limit: aws.Int64(100), // Set limit to allowed maximum to prevent API throttling
|
||||
}
|
||||
log.Printf("[DEBUG] Reading CloudWatch Event Target: %s", input)
|
||||
out, err := conn.ListTargetsByRule(&input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, t := range out.Targets {
|
||||
if *t.Id == id {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
|
||||
if out.NextToken != nil {
|
||||
return findEventTargetById(id, rule, nextToken, conn)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("CloudWatch Event Target %q (%q) not found", id, rule)
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchEventTargetUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).cloudwatcheventsconn
|
||||
|
||||
input := buildPutTargetInputStruct(d)
|
||||
log.Printf("[DEBUG] Updating CloudWatch Event Target: %s", input)
|
||||
_, err := conn.PutTargets(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Updating CloudWatch Event Target failed: %s", err)
|
||||
}
|
||||
|
||||
return resourceAwsCloudWatchEventTargetRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchEventTargetDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).cloudwatcheventsconn
|
||||
|
||||
input := events.RemoveTargetsInput{
|
||||
Ids: []*string{aws.String(d.Get("target_id").(string))},
|
||||
Rule: aws.String(d.Get("rule").(string)),
|
||||
}
|
||||
log.Printf("[INFO] Deleting CloudWatch Event Target: %s", input)
|
||||
_, err := conn.RemoveTargets(&input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting CloudWatch Event Target: %s", err)
|
||||
}
|
||||
log.Println("[INFO] CloudWatch Event Target deleted")
|
||||
|
||||
d.SetId("")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildPutTargetInputStruct(d *schema.ResourceData) *events.PutTargetsInput {
|
||||
e := &events.Target{
|
||||
Arn: aws.String(d.Get("arn").(string)),
|
||||
Id: aws.String(d.Get("target_id").(string)),
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("input"); ok {
|
||||
e.Input = aws.String(v.(string))
|
||||
}
|
||||
if v, ok := d.GetOk("input_path"); ok {
|
||||
e.InputPath = aws.String(v.(string))
|
||||
}
|
||||
|
||||
input := events.PutTargetsInput{
|
||||
Rule: aws.String(d.Get("rule").(string)),
|
||||
Targets: []*events.Target{e},
|
||||
}
|
||||
|
||||
return &input
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
events "github.com/aws/aws-sdk-go/service/cloudwatchevents"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAWSCloudWatchEventTarget_basic(t *testing.T) {
|
||||
var target events.Target
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudWatchEventTargetDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSCloudWatchEventTargetConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudWatchEventTargetExists("aws_cloudwatch_event_target.moobar", &target),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_target.moobar", "rule", "tf-acc-cw-event-rule-basic"),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_target.moobar", "target_id", "tf-acc-cw-target-basic"),
|
||||
resource.TestMatchResourceAttr("aws_cloudwatch_event_target.moobar", "arn",
|
||||
regexp.MustCompile(":tf-acc-moon$")),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: testAccAWSCloudWatchEventTargetConfigModified,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudWatchEventTargetExists("aws_cloudwatch_event_target.moobar", &target),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_target.moobar", "rule", "tf-acc-cw-event-rule-basic"),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_target.moobar", "target_id", "tf-acc-cw-target-modified"),
|
||||
resource.TestMatchResourceAttr("aws_cloudwatch_event_target.moobar", "arn",
|
||||
regexp.MustCompile(":tf-acc-sun$")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSCloudWatchEventTarget_full(t *testing.T) {
|
||||
var target events.Target
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudWatchEventTargetDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSCloudWatchEventTargetConfig_full,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudWatchEventTargetExists("aws_cloudwatch_event_target.foobar", &target),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_target.foobar", "rule", "tf-acc-cw-event-rule-full"),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_target.foobar", "target_id", "tf-acc-cw-target-full"),
|
||||
resource.TestMatchResourceAttr("aws_cloudwatch_event_target.foobar", "arn",
|
||||
regexp.MustCompile("^arn:aws:kinesis:.*:stream/terraform-kinesis-test$")),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_target.foobar", "input", "{ \"source\": [\"aws.cloudtrail\"] }\n"),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_event_target.foobar", "input_path", ""),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckCloudWatchEventTargetExists(n string, rule *events.Target) 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).cloudwatcheventsconn
|
||||
t, err := findEventTargetById(rs.Primary.Attributes["target_id"],
|
||||
rs.Primary.Attributes["rule"], nil, conn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Event Target not found: %s", err)
|
||||
}
|
||||
|
||||
*rule = *t
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSCloudWatchEventTargetDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_cloudwatch_event_target" {
|
||||
continue
|
||||
}
|
||||
|
||||
t, err := findEventTargetById(rs.Primary.Attributes["target_id"],
|
||||
rs.Primary.Attributes["rule"], nil, conn)
|
||||
if err == nil {
|
||||
return fmt.Errorf("CloudWatch Event Target %q still exists: %s",
|
||||
rs.Primary.ID, t)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccAWSCloudWatchEventTargetConfig = `
|
||||
resource "aws_cloudwatch_event_rule" "foo" {
|
||||
name = "tf-acc-cw-event-rule-basic"
|
||||
schedule_expression = "rate(1 hour)"
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_target" "moobar" {
|
||||
rule = "${aws_cloudwatch_event_rule.foo.name}"
|
||||
target_id = "tf-acc-cw-target-basic"
|
||||
arn = "${aws_sns_topic.moon.arn}"
|
||||
}
|
||||
|
||||
resource "aws_sns_topic" "moon" {
|
||||
name = "tf-acc-moon"
|
||||
}
|
||||
`
|
||||
|
||||
var testAccAWSCloudWatchEventTargetConfigModified = `
|
||||
resource "aws_cloudwatch_event_rule" "foo" {
|
||||
name = "tf-acc-cw-event-rule-basic"
|
||||
schedule_expression = "rate(1 hour)"
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_target" "moobar" {
|
||||
rule = "${aws_cloudwatch_event_rule.foo.name}"
|
||||
target_id = "tf-acc-cw-target-modified"
|
||||
arn = "${aws_sns_topic.sun.arn}"
|
||||
}
|
||||
|
||||
resource "aws_sns_topic" "sun" {
|
||||
name = "tf-acc-sun"
|
||||
}
|
||||
`
|
||||
|
||||
var testAccAWSCloudWatchEventTargetConfig_full = `
|
||||
resource "aws_cloudwatch_event_rule" "foo" {
|
||||
name = "tf-acc-cw-event-rule-full"
|
||||
schedule_expression = "rate(1 hour)"
|
||||
role_arn = "${aws_iam_role.role.arn}"
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "role" {
|
||||
name = "test_role"
|
||||
assume_role_policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": "sts:AssumeRole",
|
||||
"Principal": {
|
||||
"Service": "events.amazonaws.com"
|
||||
},
|
||||
"Effect": "Allow",
|
||||
"Sid": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "test_policy" {
|
||||
name = "test_policy"
|
||||
role = "${aws_iam_role.role.id}"
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"kinesis:PutRecord",
|
||||
"kinesis:PutRecords"
|
||||
],
|
||||
"Resource": [
|
||||
"*"
|
||||
],
|
||||
"Effect": "Allow"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_target" "foobar" {
|
||||
rule = "${aws_cloudwatch_event_rule.foo.name}"
|
||||
target_id = "tf-acc-cw-target-full"
|
||||
input = <<INPUT
|
||||
{ "source": ["aws.cloudtrail"] }
|
||||
INPUT
|
||||
arn = "${aws_kinesis_stream.test_stream.arn}"
|
||||
}
|
||||
|
||||
resource "aws_kinesis_stream" "test_stream" {
|
||||
name = "terraform-kinesis-test"
|
||||
shard_count = 1
|
||||
}
|
||||
`
|
|
@ -4,6 +4,8 @@ import (
|
|||
"fmt"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func validateRdsId(v interface{}, k string) (ws []string, errors []error) {
|
||||
|
@ -134,3 +136,50 @@ func validateEcrRepositoryName(v interface{}, k string) (ws []string, errors []e
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
func validateCloudWatchEventRuleName(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if len(value) > 64 {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot be longer than 64 characters: %q", k, value))
|
||||
}
|
||||
|
||||
// http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_PutRule.html
|
||||
pattern := `^[\.\-_A-Za-z0-9]+$`
|
||||
if !regexp.MustCompile(pattern).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q doesn't comply with restrictions (%q): %q",
|
||||
k, pattern, value))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func validateMaxLength(length int) schema.SchemaValidateFunc {
|
||||
return func(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if len(value) > length {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot be longer than %d characters: %q", k, length, value))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func validateCloudWatchEventTargetId(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if len(value) > 64 {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot be longer than 64 characters: %q", k, value))
|
||||
}
|
||||
|
||||
// http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_Target.html
|
||||
pattern := `^[\.\-_A-Za-z0-9]+$`
|
||||
if !regexp.MustCompile(pattern).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q doesn't comply with restrictions (%q): %q",
|
||||
k, pattern, value))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -43,3 +43,30 @@ func TestValidateEcrRepositoryName(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCloudWatchEventRuleName(t *testing.T) {
|
||||
validNames := []string{
|
||||
"HelloWorl_d",
|
||||
"hello-world",
|
||||
"hello.World0125",
|
||||
}
|
||||
for _, v := range validNames {
|
||||
_, errors := validateCloudWatchEventRuleName(v, "name")
|
||||
if len(errors) != 0 {
|
||||
t.Fatalf("%q should be a valid CW event rule name: %q", v, errors)
|
||||
}
|
||||
}
|
||||
|
||||
invalidNames := []string{
|
||||
"special@character",
|
||||
"slash/in-the-middle",
|
||||
// Length > 64
|
||||
"TooLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName",
|
||||
}
|
||||
for _, v := range invalidNames {
|
||||
_, errors := validateCloudWatchEventRuleName(v, "name")
|
||||
if len(errors) == 0 {
|
||||
t.Fatalf("%q should be an invalid CW event rule name", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# CloudWatch Event sent to Kinesis Stream
|
||||
|
||||
This example sets up a CloudWatch Event Rule with a Target and IAM Role & Policy
|
||||
to send all autoscaling events into Kinesis stream for further examination.
|
||||
|
||||
See more details about [CloudWatch Events](http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/WhatIsCloudWatchEvents.html)
|
||||
in the official AWS docs.
|
||||
|
||||
## How to run the example
|
||||
|
||||
```
|
||||
terraform apply \
|
||||
-var=aws_region=us-west-2
|
||||
```
|
|
@ -0,0 +1,72 @@
|
|||
provider "aws" {
|
||||
region = "${var.aws_region}"
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_rule" "foo" {
|
||||
name = "${var.rule_name}"
|
||||
event_pattern = <<PATTERN
|
||||
{
|
||||
"detail-type": [
|
||||
"AWS API Call via CloudTrail"
|
||||
],
|
||||
"detail": {
|
||||
"eventSource": [
|
||||
"autoscaling.amazonaws.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
PATTERN
|
||||
role_arn = "${aws_iam_role.role.arn}"
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "role" {
|
||||
name = "${var.iam_role_name}"
|
||||
assume_role_policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": "sts:AssumeRole",
|
||||
"Principal": {
|
||||
"Service": "events.amazonaws.com"
|
||||
},
|
||||
"Effect": "Allow",
|
||||
"Sid": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "policy" {
|
||||
name = "tf-example-policy"
|
||||
role = "${aws_iam_role.role.id}"
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"kinesis:PutRecord",
|
||||
"kinesis:PutRecords"
|
||||
],
|
||||
"Resource": [
|
||||
"*"
|
||||
],
|
||||
"Effect": "Allow"
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_target" "foobar" {
|
||||
rule = "${aws_cloudwatch_event_rule.foo.name}"
|
||||
target_id = "${var.target_name}"
|
||||
arn = "${aws_kinesis_stream.foo.arn}"
|
||||
}
|
||||
|
||||
resource "aws_kinesis_stream" "foo" {
|
||||
name = "${var.stream_name}"
|
||||
shard_count = 1
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
output "rule_arn" {
|
||||
value = "${aws_cloudwatch_event_rule.foo.arn}"
|
||||
}
|
||||
|
||||
output "kinesis_stream_arn" {
|
||||
value = "${aws_kinesis_stream.foo.arn}"
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
variable "aws_region" {
|
||||
description = "The AWS region to create resources in."
|
||||
default = "us-east-1"
|
||||
}
|
||||
|
||||
variable "rule_name" {
|
||||
description = "The name of the CloudWatch Event Rule"
|
||||
default = "tf-example-cloudwatch-event-rule-for-kinesis"
|
||||
}
|
||||
|
||||
variable "iam_role_name" {
|
||||
description = "The name of the IAM Role"
|
||||
default = "tf-example-iam-role-for-kinesis"
|
||||
}
|
||||
|
||||
variable "target_name" {
|
||||
description = "The name of the CloudWatch Event Target"
|
||||
default = "tf-example-cloudwatch-event-target-for-kinesis"
|
||||
}
|
||||
|
||||
variable "stream_name" {
|
||||
description = "The name of the Kinesis Stream to send events to"
|
||||
default = "tf-example-kinesis-stream"
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
# CloudWatch Event sent to SNS Topic
|
||||
|
||||
This example sets up a CloudWatch Event Rule with a Target and SNS Topic
|
||||
to send any CloudTrail API operation into that SNS topic. This allows you
|
||||
to add SNS subscriptions which may notify you about suspicious activity.
|
||||
|
||||
See more details about [CloudWatch Events](http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/WhatIsCloudWatchEvents.html)
|
||||
in the official AWS docs.
|
||||
|
||||
## How to run the example
|
||||
|
||||
```
|
||||
terraform apply \
|
||||
-var=aws_region=us-west-2
|
||||
```
|
|
@ -0,0 +1,29 @@
|
|||
provider "aws" {
|
||||
region = "${var.aws_region}"
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_rule" "foo" {
|
||||
name = "${var.rule_name}"
|
||||
event_pattern = <<PATTERN
|
||||
{
|
||||
"detail-type": [
|
||||
"AWS API Call via CloudTrail"
|
||||
],
|
||||
"detail": {
|
||||
"eventSource": [
|
||||
"cloudtrail.amazonaws.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
PATTERN
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_target" "bar" {
|
||||
rule = "${aws_cloudwatch_event_rule.foo.name}"
|
||||
target_id = "${var.target_name}"
|
||||
arn = "${aws_sns_topic.foo.arn}"
|
||||
}
|
||||
|
||||
resource "aws_sns_topic" "foo" {
|
||||
name = "${var.sns_topic_name}"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
output "rule_arn" {
|
||||
value = "${aws_cloudwatch_event_rule.foo.arn}"
|
||||
}
|
||||
|
||||
output "sns_topic_arn" {
|
||||
value = "${aws_sns_topic.foo.arn}"
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
variable "aws_region" {
|
||||
description = "The AWS region to create resources in."
|
||||
default = "us-east-1"
|
||||
}
|
||||
|
||||
variable "rule_name" {
|
||||
description = "The name of the CloudWatch Event Rule"
|
||||
default = "tf-example-cloudwatch-event-rule-for-sns"
|
||||
}
|
||||
|
||||
variable "target_name" {
|
||||
description = "The name of the CloudWatch Event Target"
|
||||
default = "tf-example-cloudwatch-event-target-for-sns"
|
||||
}
|
||||
|
||||
variable "sns_topic_name" {
|
||||
description = "The name of the SNS Topic to send events to"
|
||||
default = "tf-example-sns-topic"
|
||||
}
|
1094
vendor/github.com/aws/aws-sdk-go/service/cloudwatchevents/api.go
generated
vendored
Normal file
1094
vendor/github.com/aws/aws-sdk-go/service/cloudwatchevents/api.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
62
vendor/github.com/aws/aws-sdk-go/service/cloudwatchevents/cloudwatcheventsiface/interface.go
generated
vendored
Normal file
62
vendor/github.com/aws/aws-sdk-go/service/cloudwatchevents/cloudwatcheventsiface/interface.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
// Package cloudwatcheventsiface provides an interface for the Amazon CloudWatch Events.
|
||||
package cloudwatcheventsiface
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatchevents"
|
||||
)
|
||||
|
||||
// CloudWatchEventsAPI is the interface type for cloudwatchevents.CloudWatchEvents.
|
||||
type CloudWatchEventsAPI interface {
|
||||
DeleteRuleRequest(*cloudwatchevents.DeleteRuleInput) (*request.Request, *cloudwatchevents.DeleteRuleOutput)
|
||||
|
||||
DeleteRule(*cloudwatchevents.DeleteRuleInput) (*cloudwatchevents.DeleteRuleOutput, error)
|
||||
|
||||
DescribeRuleRequest(*cloudwatchevents.DescribeRuleInput) (*request.Request, *cloudwatchevents.DescribeRuleOutput)
|
||||
|
||||
DescribeRule(*cloudwatchevents.DescribeRuleInput) (*cloudwatchevents.DescribeRuleOutput, error)
|
||||
|
||||
DisableRuleRequest(*cloudwatchevents.DisableRuleInput) (*request.Request, *cloudwatchevents.DisableRuleOutput)
|
||||
|
||||
DisableRule(*cloudwatchevents.DisableRuleInput) (*cloudwatchevents.DisableRuleOutput, error)
|
||||
|
||||
EnableRuleRequest(*cloudwatchevents.EnableRuleInput) (*request.Request, *cloudwatchevents.EnableRuleOutput)
|
||||
|
||||
EnableRule(*cloudwatchevents.EnableRuleInput) (*cloudwatchevents.EnableRuleOutput, error)
|
||||
|
||||
ListRuleNamesByTargetRequest(*cloudwatchevents.ListRuleNamesByTargetInput) (*request.Request, *cloudwatchevents.ListRuleNamesByTargetOutput)
|
||||
|
||||
ListRuleNamesByTarget(*cloudwatchevents.ListRuleNamesByTargetInput) (*cloudwatchevents.ListRuleNamesByTargetOutput, error)
|
||||
|
||||
ListRulesRequest(*cloudwatchevents.ListRulesInput) (*request.Request, *cloudwatchevents.ListRulesOutput)
|
||||
|
||||
ListRules(*cloudwatchevents.ListRulesInput) (*cloudwatchevents.ListRulesOutput, error)
|
||||
|
||||
ListTargetsByRuleRequest(*cloudwatchevents.ListTargetsByRuleInput) (*request.Request, *cloudwatchevents.ListTargetsByRuleOutput)
|
||||
|
||||
ListTargetsByRule(*cloudwatchevents.ListTargetsByRuleInput) (*cloudwatchevents.ListTargetsByRuleOutput, error)
|
||||
|
||||
PutEventsRequest(*cloudwatchevents.PutEventsInput) (*request.Request, *cloudwatchevents.PutEventsOutput)
|
||||
|
||||
PutEvents(*cloudwatchevents.PutEventsInput) (*cloudwatchevents.PutEventsOutput, error)
|
||||
|
||||
PutRuleRequest(*cloudwatchevents.PutRuleInput) (*request.Request, *cloudwatchevents.PutRuleOutput)
|
||||
|
||||
PutRule(*cloudwatchevents.PutRuleInput) (*cloudwatchevents.PutRuleOutput, error)
|
||||
|
||||
PutTargetsRequest(*cloudwatchevents.PutTargetsInput) (*request.Request, *cloudwatchevents.PutTargetsOutput)
|
||||
|
||||
PutTargets(*cloudwatchevents.PutTargetsInput) (*cloudwatchevents.PutTargetsOutput, error)
|
||||
|
||||
RemoveTargetsRequest(*cloudwatchevents.RemoveTargetsInput) (*request.Request, *cloudwatchevents.RemoveTargetsOutput)
|
||||
|
||||
RemoveTargets(*cloudwatchevents.RemoveTargetsInput) (*cloudwatchevents.RemoveTargetsOutput, error)
|
||||
|
||||
TestEventPatternRequest(*cloudwatchevents.TestEventPatternInput) (*request.Request, *cloudwatchevents.TestEventPatternOutput)
|
||||
|
||||
TestEventPattern(*cloudwatchevents.TestEventPatternInput) (*cloudwatchevents.TestEventPatternOutput, error)
|
||||
}
|
||||
|
||||
var _ CloudWatchEventsAPI = (*cloudwatchevents.CloudWatchEvents)(nil)
|
101
vendor/github.com/aws/aws-sdk-go/service/cloudwatchevents/service.go
generated
vendored
Normal file
101
vendor/github.com/aws/aws-sdk-go/service/cloudwatchevents/service.go
generated
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
package cloudwatchevents
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
|
||||
"github.com/aws/aws-sdk-go/private/signer/v4"
|
||||
)
|
||||
|
||||
// Amazon CloudWatch Events helps you to respond to state changes in your AWS
|
||||
// resources. When your resources change state they automatically send events
|
||||
// into an event stream. You can create rules that match selected events in
|
||||
// the stream and route them to targets to take action. You can also use rules
|
||||
// to take action on a pre-determined schedule. For example, you can configure
|
||||
// rules to:
|
||||
//
|
||||
// Automatically invoke an AWS Lambda function to update DNS entries when
|
||||
// an event notifies you that Amazon EC2 instance enters the running state.
|
||||
// Direct specific API records from CloudTrail to an Amazon Kinesis stream for
|
||||
// detailed analysis of potential security or availability risks. Periodically
|
||||
// invoke a built-in target to create a snapshot of an Amazon EBS volume.
|
||||
// For more information about Amazon CloudWatch Events features, see the Amazon
|
||||
// CloudWatch Developer Guide (http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide).
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type CloudWatchEvents struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// Used for custom client initialization logic
|
||||
var initClient func(*client.Client)
|
||||
|
||||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// A ServiceName is the name of the service the client will make API calls to.
|
||||
const ServiceName = "events"
|
||||
|
||||
// New creates a new instance of the CloudWatchEvents client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a CloudWatchEvents client from just a session.
|
||||
// svc := cloudwatchevents.New(mySession)
|
||||
//
|
||||
// // Create a CloudWatchEvents client with additional configuration
|
||||
// svc := cloudwatchevents.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *CloudWatchEvents {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *CloudWatchEvents {
|
||||
svc := &CloudWatchEvents{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2014-02-03",
|
||||
JSONVersion: "1.1",
|
||||
TargetPrefix: "AWSEvents",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
|
||||
// Handlers
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(jsonrpc.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(jsonrpc.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(jsonrpc.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(jsonrpc.UnmarshalError)
|
||||
|
||||
// Run custom client initialization if present
|
||||
if initClient != nil {
|
||||
initClient(svc.Client)
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a CloudWatchEvents operation and runs any
|
||||
// custom request initialization.
|
||||
func (c *CloudWatchEvents) newRequest(op *request.Operation, params, data interface{}) *request.Request {
|
||||
req := c.NewRequest(op, params, data)
|
||||
|
||||
// Run custom request initialization if present
|
||||
if initRequest != nil {
|
||||
initRequest(req)
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: aws_cloudwatch_event_rule"
|
||||
sidebar_current: "docs-aws-resource-cloudwatch-event-rule"
|
||||
description: |-
|
||||
Provides a CloudWatch Event Rule resource.
|
||||
---
|
||||
|
||||
# aws\_cloudwatch\_event\_rule
|
||||
|
||||
Provides a CloudWatch Event Rule resource.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "aws_cloudwatch_event_rule" "console" {
|
||||
name = "capture-aws-sign-in"
|
||||
description = "Capture each AWS Console Sign In"
|
||||
event_pattern = <<PATTERN
|
||||
{
|
||||
"detail-type": [
|
||||
"AWS Console Sign In via CloudTrail"
|
||||
]
|
||||
}
|
||||
PATTERN
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_target" "sns" {
|
||||
rule = "${aws_cloudwatch_event_rule.console.name}"
|
||||
target_id = "SendToSNS"
|
||||
arn = "${aws_sns_topic.aws_logins.arn}"
|
||||
}
|
||||
|
||||
resource "aws_sns_topic" "aws_logins" {
|
||||
name = "aws-console-logins"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The rule's name.
|
||||
* `schedule_expression` - (Required, if `event_pattern` isn't specified) The scheduling expression.
|
||||
For example, `cron(0 20 * * ? *)` or `rate(5 minutes)`.
|
||||
* `event_pattern` - (Required, if `schedule_expression` isn't specified) Event pattern
|
||||
described a JSON object.
|
||||
See full documentation of [CloudWatch Events and Event Patterns](http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/CloudWatchEventsandEventPatterns.html) for details.
|
||||
* `description` - (Optional) The description of the rule.
|
||||
* `role_arn` - (Optional) The Amazon Resource Name (ARN) associated with the role that is used for target invocation.
|
||||
* `is_enabled` - (Optional) Whether the rule should be enabled (defaults to `true`).
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `arn` - The Amazon Resource Name (ARN) of the rule.
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: aws_cloudwatch_event_target"
|
||||
sidebar_current: "docs-aws-resource-cloudwatch-event-target"
|
||||
description: |-
|
||||
Provides a CloudWatch Event Target resource.
|
||||
---
|
||||
|
||||
# aws\_cloudwatch\_event\_target
|
||||
|
||||
Provides a CloudWatch Event Target resource.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "aws_cloudwatch_event_target" "yada" {
|
||||
target_id = "Yada"
|
||||
rule = "${aws_cloudwatch_event_rule.console.arn}"
|
||||
arn = "${aws_kinesis_stream.test_stream.arn}"
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_rule" "console" {
|
||||
name = "capture-ec2-scaling-events"
|
||||
description = "Capture all EC2 scaling events"
|
||||
event_pattern = <<PATTERN
|
||||
{
|
||||
"source": [
|
||||
"aws.autoscaling"
|
||||
],
|
||||
"detail-type": [
|
||||
"EC2 Instance Launch Successful",
|
||||
"EC2 Instance Terminate Successful",
|
||||
"EC2 Instance Launch Unsuccessful",
|
||||
"EC2 Instance Terminate Unsuccessful"
|
||||
]
|
||||
}
|
||||
PATTERN
|
||||
}
|
||||
|
||||
resource "aws_kinesis_stream" "test_stream" {
|
||||
name = "terraform-kinesis-test"
|
||||
shard_count = 1
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
-> **Note:** `input` and `input_path` are mutually exclusive options.
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `rule` - (Required) The name of the rule you want to add targets to.
|
||||
* `target_id` - (Required) The unique target assignment ID.
|
||||
* `arn` - (Required) The Amazon Resource Name (ARN) associated of the target.
|
||||
* `input` - (Optional) Valid JSON text passed to the target.
|
||||
* `input_path` - (Optional) The value of the [JSONPath](http://goessner.net/articles/JsonPath/)
|
||||
that is used for extracting part of the matched event when passing it to the target.
|
|
@ -31,6 +31,13 @@
|
|||
<li<%= sidebar_current(/^docs-aws-resource-cloudwatch/) %>>
|
||||
<a href="#">CloudWatch Resources</a>
|
||||
<ul class="nav nav-visible">
|
||||
<li<%= sidebar_current("docs-aws-resource-cloudwatch-event-rule") %>>
|
||||
<a href="/docs/providers/aws/r/cloudwatch_event_rule.html">aws_cloudwatch_event_rule</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-cloudwatch-event-target") %>>
|
||||
<a href="/docs/providers/aws/r/cloudwatch_event_target.html">aws_cloudwatch_event_target</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-cloudwatch-log-group") %>>
|
||||
<a href="/docs/providers/aws/r/cloudwatch_log_group.html">aws_cloudwatch_log_group</a>
|
||||
|
|
Loading…
Reference in New Issue