diff --git a/.changelog/17241.txt b/.changelog/17241.txt new file mode 100644 index 00000000000..cc726257b85 --- /dev/null +++ b/.changelog/17241.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_cloudwatch_event_target: Adds `retry_policy` attributes +``` + +```release-note:enhancement +resource/aws_cloudwatch_event_target: Adds `dead_letter_config` attributes +``` \ No newline at end of file diff --git a/aws/resource_aws_cloudwatch_event_target.go b/aws/resource_aws_cloudwatch_event_target.go index 28e6ff5199c..a895d74bf5a 100644 --- a/aws/resource_aws_cloudwatch_event_target.go +++ b/aws/resource_aws_cloudwatch_event_target.go @@ -248,6 +248,40 @@ func resourceAwsCloudWatchEventTarget() *schema.Resource { }, }, }, + + "retry_policy": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "maximum_event_age_in_seconds": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(60), + }, + "maximum_retry_attempts": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + + "dead_letter_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, + }, + }, + }, + }, }, } } @@ -350,6 +384,18 @@ func resourceAwsCloudWatchEventTargetRead(d *schema.ResourceData, meta interface } } + if t.RetryPolicy != nil { + if err := d.Set("retry_policy", flatternAwsCloudWatchEventTargetRetryPolicy(t.RetryPolicy)); err != nil { + return fmt.Errorf("Error setting retry_policy error: #{err}") + } + } + + if t.DeadLetterConfig != nil { + if err := d.Set("dead_letter_config", flatternAwsCloudWatchEventTargetDeadLetterConfig(t.DeadLetterConfig)); err != nil { + return fmt.Errorf("Error setting dead_letter_config error: #{err}") + } + } + return nil } @@ -434,6 +480,14 @@ func buildPutTargetInputStruct(d *schema.ResourceData) *events.PutTargetsInput { e.InputTransformer = expandAwsCloudWatchEventTransformerParameters(v.([]interface{})) } + if v, ok := d.GetOk("retry_policy"); ok { + e.RetryPolicy = expandAwsCloudWatchEventRetryPolicyParameters(v.([]interface{})) + } + + if v, ok := d.GetOk("dead_letter_config"); ok { + e.DeadLetterConfig = expandAwsCloudWatchEventDeadLetterConfigParameters(v.([]interface{})) + } + input := events.PutTargetsInput{ Rule: aws.String(d.Get("rule").(string)), Targets: []*events.Target{e}, @@ -485,6 +539,39 @@ func expandAwsCloudWatchEventTargetEcsParameters(config []interface{}) *events.E return ecsParameters } + +func expandAwsCloudWatchEventRetryPolicyParameters(rp []interface{}) *events.RetryPolicy { + retryPolicy := &events.RetryPolicy{} + + for _, v := range rp { + params := v.(map[string]interface{}) + + if val, ok := params["maximum_event_age_in_seconds"].(int); ok { + retryPolicy.MaximumEventAgeInSeconds = aws.Int64(int64(val)) + } + + if val, ok := params["maximum_retry_attempts"].(int); ok { + retryPolicy.MaximumRetryAttempts = aws.Int64(int64(val)) + } + } + + return retryPolicy +} + +func expandAwsCloudWatchEventDeadLetterConfigParameters(dlp []interface{}) *events.DeadLetterConfig { + deadLetterConfig := &events.DeadLetterConfig{} + + for _, v := range dlp { + params := v.(map[string]interface{}) + + if val, ok := params["arn"].(string); ok && val != "" { + deadLetterConfig.Arn = aws.String(val) + } + } + + return deadLetterConfig +} + func expandAwsCloudWatchEventTargetEcsParametersNetworkConfiguration(nc []interface{}) *events.NetworkConfiguration { if len(nc) == 0 { return nil @@ -658,6 +745,25 @@ func flattenAwsCloudWatchInputTransformer(inputTransformer *events.InputTransfor return result } +func flatternAwsCloudWatchEventTargetRetryPolicy(rp *events.RetryPolicy) []map[string]interface{} { + config := make(map[string]interface{}) + + config["maximum_event_age_in_seconds"] = aws.Int64Value(rp.MaximumEventAgeInSeconds) + config["maximum_retry_attempts"] = aws.Int64Value(rp.MaximumRetryAttempts) + + result := []map[string]interface{}{config} + return result +} + +func flatternAwsCloudWatchEventTargetDeadLetterConfig(dlc *events.DeadLetterConfig) []map[string]interface{} { + config := make(map[string]interface{}) + + config["arn"] = aws.StringValue(dlc.Arn) + + result := []map[string]interface{}{config} + return result +} + func resourceAwsCloudWatchEventTargetImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { busName, ruleName, targetID, err := tfevents.TargetParseImportID(d.Id()) if err != nil { diff --git a/aws/resource_aws_cloudwatch_event_target_test.go b/aws/resource_aws_cloudwatch_event_target_test.go index c6d3e17a84e..f258ded59aa 100644 --- a/aws/resource_aws_cloudwatch_event_target_test.go +++ b/aws/resource_aws_cloudwatch_event_target_test.go @@ -247,6 +247,39 @@ func TestAccAWSCloudWatchEventTarget_GeneratedTargetId(t *testing.T) { }) } +func TestAccAWSCloudWatchEventTarget_RetryPolicy_DeadLetterConfig(t *testing.T) { + resourceName := "aws_cloudwatch_event_target.test" + kinesisStreamResourceName := "aws_kinesis_stream.test" + queueResourceName := "aws_sqs_queue.test" + var v events.Target + + ruleName := acctest.RandomWithPrefix("tf-acc-cw-event-rule-full") + ssmDocumentName := acctest.RandomWithPrefix("tf_ssm_Document") + targetID := acctest.RandomWithPrefix("tf-acc-cw-target-full") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventTargetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventTargetConfig_retryPolicyDlc(ruleName, targetID, ssmDocumentName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventTargetExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "rule", ruleName), + resource.TestCheckResourceAttr(resourceName, "target_id", targetID), + resource.TestCheckResourceAttrPair(resourceName, "arn", kinesisStreamResourceName, "arn"), + testAccCheckResourceAttrEquivalentJSON(resourceName, "input", `{"source": ["aws.cloudtrail"]}`), + resource.TestCheckResourceAttr(resourceName, "input_path", ""), + resource.TestCheckResourceAttr(resourceName, "retry_policy.0.maximum_event_age_in_seconds", "60"), + resource.TestCheckResourceAttr(resourceName, "retry_policy.0.maximum_retry_attempts", "5"), + resource.TestCheckResourceAttrPair(resourceName, "dead_letter_config.0.arn", queueResourceName, "arn"), + ), + }, + }, + }) +} + func TestAccAWSCloudWatchEventTarget_full(t *testing.T) { resourceName := "aws_cloudwatch_event_target.test" kinesisStreamResourceName := "aws_kinesis_stream.test" @@ -626,6 +659,8 @@ func testAccAWSCloudWatchEventTargetImportStateIdFunc(resourceName string) resou return "", fmt.Errorf("Not found: %s", resourceName) } + fmt.Printf("%#v", rs.Primary.Attributes) + return fmt.Sprintf("%s/%s/%s", rs.Primary.Attributes["event_bus_name"], rs.Primary.Attributes["rule"], rs.Primary.Attributes["target_id"]), nil } } @@ -730,6 +765,89 @@ resource "aws_sns_topic" "test" { `, ruleName, snsTopicName) } +func testAccAWSCloudWatchEventTargetConfig_retryPolicyDlc(ruleName, targetName, rName string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_rule" "test" { + name = %[1]q + schedule_expression = "rate(1 hour)" + role_arn = aws_iam_role.test.arn +} + +resource "aws_iam_role" "test" { + name = %[2]q + + assume_role_policy = <