Skip to content

Commit

Permalink
resource/aws_cloudwatch_event_target: Include state upgrade for new d…
Browse files Browse the repository at this point in the history
…efault event bus name in Read path and only include EventBusName when non-empty in API requests (#16075)

Reference: #16069

Until we sort out the details of setting up the acceptance testing framework to handle state upgrades (likely via Terraform CLI 0.13+ and TestCase.ExternalProviders), manually verified with the following:

```terraform
terraform {
  required_providers {
    aws = "3.13.0"
  }
  required_version = "0.12.29"
}

provider "aws" {
  region = "us-east-2"
}

resource "aws_cloudwatch_event_rule" "test" {
  name                = "16069-test"
  schedule_expression = "rate(1 hour)"
}

resource "aws_cloudwatch_event_target" "test" {
  rule      = aws_cloudwatch_event_rule.test.name
  target_id = "16069-test"
  arn       = aws_sns_topic.test.arn
}

resource "aws_sns_topic" "test" {
  name = "16069-test"
}
```

```console
$ terraform init
$ terraform apply
# update version to 3.14.0
$ terraform init
$ terraform apply
aws_cloudwatch_event_rule.test: Refreshing state... [id=16069-test]
aws_sns_topic.test: Refreshing state... [id=arn:aws:sns:us-east-2:--OMITTED--:16069-test]
aws_cloudwatch_event_target.test: Refreshing state... [id=16069-test-16069-test]

Error: InvalidParameter: 1 validation error(s) found.
- minimum field size of 1, ListTargetsByRuleInput.EventBusName.
```

After updating local plugin:

```console
$ terraform apply
...
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
```

Output from acceptance testing in AWS Commercial:

```
--- PASS: TestAccAWSCloudWatchEventTarget_basic (41.56s)
--- PASS: TestAccAWSCloudWatchEventTarget_batch (146.89s)
--- PASS: TestAccAWSCloudWatchEventTarget_disappears (15.51s)
--- PASS: TestAccAWSCloudWatchEventTarget_ecs (34.45s)
--- PASS: TestAccAWSCloudWatchEventTarget_ecsWithBlankTaskCount (34.90s)
--- PASS: TestAccAWSCloudWatchEventTarget_EventBusName (36.74s)
--- PASS: TestAccAWSCloudWatchEventTarget_full (62.30s)
--- PASS: TestAccAWSCloudWatchEventTarget_GeneratedTargetId (17.97s)
--- PASS: TestAccAWSCloudWatchEventTarget_input_transformer (43.71s)
--- PASS: TestAccAWSCloudWatchEventTarget_inputTransformerJsonString (48.88s)
--- PASS: TestAccAWSCloudWatchEventTarget_kinesis (62.16s)
--- PASS: TestAccAWSCloudWatchEventTarget_sqs (18.22s)
--- PASS: TestAccAWSCloudWatchEventTarget_ssmDocument (21.40s)
```

Output from acceptance testing in AWS GovCloud (US):

```
--- PASS: TestAccAWSCloudWatchEventTarget_basic (51.37s)
--- PASS: TestAccAWSCloudWatchEventTarget_batch (153.85s)
--- PASS: TestAccAWSCloudWatchEventTarget_disappears (19.90s)
--- PASS: TestAccAWSCloudWatchEventTarget_ecs (40.23s)
--- PASS: TestAccAWSCloudWatchEventTarget_ecsWithBlankTaskCount (40.10s)
--- PASS: TestAccAWSCloudWatchEventTarget_EventBusName (43.57s)
--- PASS: TestAccAWSCloudWatchEventTarget_full (67.95s)
--- PASS: TestAccAWSCloudWatchEventTarget_GeneratedTargetId (22.57s)
--- PASS: TestAccAWSCloudWatchEventTarget_input_transformer (49.06s)
--- PASS: TestAccAWSCloudWatchEventTarget_inputTransformerJsonString (39.35s)
--- PASS: TestAccAWSCloudWatchEventTarget_kinesis (66.38s)
--- PASS: TestAccAWSCloudWatchEventTarget_sqs (22.96s)
--- PASS: TestAccAWSCloudWatchEventTarget_ssmDocument (25.39s)
```
  • Loading branch information
bflad authored Nov 6, 2020
1 parent 6328475 commit 3b79f2d
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 7 deletions.
10 changes: 7 additions & 3 deletions aws/internal/service/cloudwatchevents/lister/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import (

func ListAllTargetsForRulePages(conn *events.CloudWatchEvents, busName, ruleName string, fn func(*events.ListTargetsByRuleOutput, bool) bool) error {
input := &events.ListTargetsByRuleInput{
Rule: aws.String(ruleName),
EventBusName: aws.String(busName),
Limit: aws.Int64(100), // Set limit to allowed maximum to prevent API throttling
Rule: aws.String(ruleName),
Limit: aws.Int64(100), // Set limit to allowed maximum to prevent API throttling
}

if busName != "" {
input.EventBusName = aws.String(busName)
}

return ListTargetsByRulePages(conn, input, fn)
}
19 changes: 15 additions & 4 deletions aws/resource_aws_cloudwatch_event_target.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ func resourceAwsCloudWatchEventTarget() *schema.Resource {
State: resourceAwsCloudWatchEventTargetImport,
},

SchemaVersion: 1,
StateUpgraders: []schema.StateUpgrader{
{
Type: resourceAwsCloudWatchEventTargetV0().CoreConfigSchema().ImpliedType(),
Upgrade: resourceAwsCloudWatchEventTargetStateUpgradeV0,
Version: 0,
},
},

Schema: map[string]*schema.Schema{
"event_bus_name": {
Type: schema.TypeString,
Expand Down Expand Up @@ -361,11 +370,13 @@ func resourceAwsCloudWatchEventTargetUpdate(d *schema.ResourceData, meta interfa
func resourceAwsCloudWatchEventTargetDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).cloudwatcheventsconn

busName := d.Get("event_bus_name").(string)
input := &events.RemoveTargetsInput{
Ids: []*string{aws.String(d.Get("target_id").(string))},
Rule: aws.String(d.Get("rule").(string)),
EventBusName: aws.String(busName),
Ids: []*string{aws.String(d.Get("target_id").(string))},
Rule: aws.String(d.Get("rule").(string)),
}

if v, ok := d.GetOk("event_bus_name"); ok {
input.EventBusName = aws.String(v.(string))
}

output, err := conn.RemoveTargets(input)
Expand Down
177 changes: 177 additions & 0 deletions aws/resource_aws_cloudwatch_event_target_migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package aws

import (
"context"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
tfevents "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents"
)

func resourceAwsCloudWatchEventTargetV0() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Required: true,
},
"batch_target": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"array_size": {
Type: schema.TypeInt,
Optional: true,
},
"job_attempts": {
Type: schema.TypeInt,
Optional: true,
},
"job_definition": {
Type: schema.TypeString,
Required: true,
},
"job_name": {
Type: schema.TypeString,
Required: true,
},
},
},
},
"ecs_target": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"group": {
Type: schema.TypeString,
Optional: true,
},
"launch_type": {
Type: schema.TypeString,
Optional: true,
},
"network_configuration": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"assign_public_ip": {
Type: schema.TypeBool,
Optional: true,
},
"security_groups": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"subnets": {
Type: schema.TypeSet,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
"platform_version": {
Type: schema.TypeString,
Optional: true,
},
"task_count": {
Type: schema.TypeInt,
Optional: true,
},
"task_definition_arn": {
Type: schema.TypeString,
Required: true,
},
},
},
},
"input": {
Type: schema.TypeString,
Optional: true,
},
"input_path": {
Type: schema.TypeString,
Optional: true,
},
"input_transformer": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"input_paths": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"input_template": {
Type: schema.TypeString,
Required: true,
},
},
},
},
"kinesis_target": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"partition_key_path": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
"role_arn": {
Type: schema.TypeString,
Optional: true,
},
"rule": {
Type: schema.TypeString,
Required: true,
},
"run_command_targets": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Required: true,
},
"values": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
"sqs_target": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"message_group_id": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
"target_id": {
Type: schema.TypeString,
Optional: true,
},
},
}
}

func resourceAwsCloudWatchEventTargetStateUpgradeV0(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
rawState["event_bus_name"] = tfevents.DefaultEventBusName

return rawState, nil
}
37 changes: 37 additions & 0 deletions aws/resource_aws_cloudwatch_event_target_migrate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package aws

import (
"context"
"reflect"
"testing"
)

func testResourceAwsCloudWatchEventTargetStateDataV0() map[string]interface{} {
return map[string]interface{}{
"arn": "arn:aws:test:us-east-1:123456789012:test", //lintignore:AWSAT003,AWSAT005
"rule": "testrule",
"target_id": "testtargetid",
}
}

func testResourceAwsCloudWatchEventTargetStateDataV1() map[string]interface{} {
v0 := testResourceAwsCloudWatchEventTargetStateDataV0()
return map[string]interface{}{
"arn": v0["arn"],
"event_bus_name": "default",
"rule": v0["rule"],
"target_id": v0["target_id"],
}
}

func TestResourceAwsCloudWatchEventTargetStateUpgradeV0(t *testing.T) {
expected := testResourceAwsCloudWatchEventTargetStateDataV1()
actual, err := resourceAwsCloudWatchEventTargetStateUpgradeV0(context.Background(), testResourceAwsCloudWatchEventTargetStateDataV0(), nil)
if err != nil {
t.Fatalf("error migrating state: %s", err)
}

if !reflect.DeepEqual(expected, actual) {
t.Fatalf("\n\nexpected:\n\n%#v\n\ngot:\n\n%#v\n\n", expected, actual)
}
}

0 comments on commit 3b79f2d

Please sign in to comment.