terraform/builtin/providers/aws/resource_aws_cloudwatch_eve...

292 lines
7.4 KiB
Go

package aws
import (
"fmt"
"log"
"regexp"
"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"
events "github.com/aws/aws-sdk-go/service/cloudwatchevents"
"github.com/hashicorp/terraform/helper/validation"
)
func resourceAwsCloudWatchEventTarget() *schema.Resource {
return &schema.Resource{
Create: resourceAwsCloudWatchEventTargetCreate,
Read: resourceAwsCloudWatchEventTargetRead,
Update: resourceAwsCloudWatchEventTargetUpdate,
Delete: resourceAwsCloudWatchEventTargetDelete,
Schema: map[string]*schema.Schema{
"rule": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validateCloudWatchEventRuleName,
},
"target_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ValidateFunc: validateCloudWatchEventTargetId,
},
"arn": {
Type: schema.TypeString,
Required: true,
},
"input": {
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": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"input"},
},
"role_arn": {
Type: schema.TypeString,
Optional: true,
},
"run_command_targets": {
Type: schema.TypeList,
Optional: true,
MaxItems: 5,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(1, 128),
},
"values": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
},
}
}
func resourceAwsCloudWatchEventTargetCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).cloudwatcheventsconn
rule := d.Get("rule").(string)
var targetId string
if v, ok := d.GetOk("target_id"); ok {
targetId = v.(string)
} else {
targetId = resource.UniqueId()
d.Set("target_id", targetId)
}
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)
}
id := rule + "-" + targetId
d.SetId(id)
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
}
if awsErr, ok := err.(awserr.Error); ok {
// This should never happen, but it's useful
// for recovering from https://github.com/hashicorp/terraform/issues/5389
if awsErr.Code() == "ValidationException" {
log.Printf("[WARN] Removing CloudWatch Event Target %q because it never existed.", d.Id())
d.SetId("")
return nil
}
if awsErr.Code() == "ResourceNotFoundException" {
log.Printf("[WARN] CloudWatch Event Target (%q) not found. Removing it from state.", 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)
d.Set("role_arn", t.RoleArn)
if t.RunCommandParameters != nil {
if err := d.Set("run_command_targets", flattenAwsCloudWatchEventTargetRunParameters(t.RunCommandParameters)); err != nil {
return fmt.Errorf("[DEBUG] Error setting run_command_targets error: %#v", err)
}
}
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))
}
if v, ok := d.GetOk("role_arn"); ok {
e.RoleArn = aws.String(v.(string))
}
if v, ok := d.GetOk("run_command_targets"); ok {
e.RunCommandParameters = expandAwsCloudWatchEventTargetRunParameters(v.([]interface{}))
}
input := events.PutTargetsInput{
Rule: aws.String(d.Get("rule").(string)),
Targets: []*events.Target{e},
}
return &input
}
func expandAwsCloudWatchEventTargetRunParameters(config []interface{}) *events.RunCommandParameters {
commands := make([]*events.RunCommandTarget, 0)
for _, c := range config {
param := c.(map[string]interface{})
command := &events.RunCommandTarget{
Key: aws.String(param["key"].(string)),
Values: expandStringList(param["values"].([]interface{})),
}
commands = append(commands, command)
}
command := &events.RunCommandParameters{
RunCommandTargets: commands,
}
return command
}
func flattenAwsCloudWatchEventTargetRunParameters(runCommand *events.RunCommandParameters) []map[string]interface{} {
result := make([]map[string]interface{}, 0)
for _, x := range runCommand.RunCommandTargets {
config := make(map[string]interface{})
config["key"] = *x.Key
config["values"] = flattenStringList(x.Values)
result = append(result, config)
}
return result
}