From 54d91a275a46938370afb723da6f7639026aff35 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Nov 2020 09:29:56 -0500 Subject: [PATCH] resource/aws_cloudwatch_event_target: Prevent potential panic and passthrough custom event_bus_name in v0 state upgrade Reference: https://github.com/hashicorp/terraform-provider-aws/issues/16394 If a configuration was applied with version 3.14.0, the `event_bus_name` attribute could have a custom value and the state upgrader function would previously not pass it through. Previous output from new unit test: ``` --- FAIL: TestResourceAwsCloudWatchEventTargetStateUpgradeV0EventBusName (0.00s) resource_aws_cloudwatch_event_target_migrate_test.go:66: expected: map[string]interface {}{"arn":"arn:aws:test:us-east-1:123456789012:test", "event_bus_name":"testbus", "rule":"testrule", "target_id":"testtargetid"} got: map[string]interface {}{"arn":"arn:aws:test:us-east-1:123456789012:test", "event_bus_name":"default", "rule":"testrule", "target_id":"testtargetid"} ``` Given this configuration: ```terraform terraform { required_providers { aws = "3.14.0" } required_version = "0.12.29" } provider "aws" { region = "us-east-2" } resource "aws_cloudwatch_event_bus" "test" { name = "16394-test" } resource "aws_cloudwatch_event_rule" "test" { event_bus_name = aws_cloudwatch_event_bus.test.name event_pattern = jsonencode({ source = ["aws.ec2"] }) name = "16394-test" } resource "aws_cloudwatch_event_target" "test" { arn = aws_sns_topic.test.arn event_bus_name = aws_cloudwatch_event_bus.test.name rule = aws_cloudwatch_event_rule.test.name target_id = "16394-test" } resource "aws_sns_topic" "test" { name = "16394-test" } ``` Output from console: ```console $ terraform init ... $ terraform apply ... Apply complete! Resources: 4 added, 0 changed, 0 destroyed. # edit provider version to 3.18.0 $ terraform init ... $ terraform apply ... An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_cloudwatch_event_target.test will be created + resource "aws_cloudwatch_event_target" "test" { + arn = "arn:aws:sns:us-east-2:--OMITTED--:16394-test" + event_bus_name = "16394-test" + id = (known after apply) + rule = "16394-test" + target_id = "16394-test" } Plan: 1 to add, 0 to change, 0 to destroy. # swap in built Terraform AWS Provider binary $ terraform apply ... Apply complete! Resources: 0 added, 0 changed, 0 destroyed. ``` Output from acceptance testing: ``` --- PASS: TestAccAWSCloudWatchEventTarget_basic (35.74s) --- PASS: TestAccAWSCloudWatchEventTarget_batch (140.33s) --- PASS: TestAccAWSCloudWatchEventTarget_disappears (17.51s) --- PASS: TestAccAWSCloudWatchEventTarget_ecs (28.63s) --- PASS: TestAccAWSCloudWatchEventTarget_ecsWithBlankTaskCount (31.25s) --- PASS: TestAccAWSCloudWatchEventTarget_EventBusName (32.01s) --- PASS: TestAccAWSCloudWatchEventTarget_full (59.07s) --- PASS: TestAccAWSCloudWatchEventTarget_GeneratedTargetId (16.62s) --- PASS: TestAccAWSCloudWatchEventTarget_input_transformer (47.34s) --- PASS: TestAccAWSCloudWatchEventTarget_inputTransformerJsonString (38.99s) --- PASS: TestAccAWSCloudWatchEventTarget_kinesis (59.09s) --- PASS: TestAccAWSCloudWatchEventTarget_sqs (16.71s) --- PASS: TestAccAWSCloudWatchEventTarget_ssmDocument (18.77s) ``` --- ...rce_aws_cloudwatch_event_target_migrate.go | 8 ++++- ...ws_cloudwatch_event_target_migrate_test.go | 31 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudwatch_event_target_migrate.go b/aws/resource_aws_cloudwatch_event_target_migrate.go index 185f76a1dab1..11aa0687e21c 100644 --- a/aws/resource_aws_cloudwatch_event_target_migrate.go +++ b/aws/resource_aws_cloudwatch_event_target_migrate.go @@ -171,7 +171,13 @@ func resourceAwsCloudWatchEventTargetV0() *schema.Resource { } func resourceAwsCloudWatchEventTargetStateUpgradeV0(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { - rawState["event_bus_name"] = tfevents.DefaultEventBusName + if rawState == nil { + rawState = map[string]interface{}{} + } + + if _, ok := rawState["event_bus_name"]; !ok { + rawState["event_bus_name"] = tfevents.DefaultEventBusName + } return rawState, nil } diff --git a/aws/resource_aws_cloudwatch_event_target_migrate_test.go b/aws/resource_aws_cloudwatch_event_target_migrate_test.go index 4dbed0b29113..3ae042c208cb 100644 --- a/aws/resource_aws_cloudwatch_event_target_migrate_test.go +++ b/aws/resource_aws_cloudwatch_event_target_migrate_test.go @@ -14,6 +14,15 @@ func testResourceAwsCloudWatchEventTargetStateDataV0() map[string]interface{} { } } +func testResourceAwsCloudWatchEventTargetStateDataV0EventBusName() map[string]interface{} { + return map[string]interface{}{ + "arn": "arn:aws:test:us-east-1:123456789012:test", //lintignore:AWSAT003,AWSAT005 + "event_bus_name": "testbus", + "rule": "testrule", + "target_id": "testtargetid", + } +} + func testResourceAwsCloudWatchEventTargetStateDataV1() map[string]interface{} { v0 := testResourceAwsCloudWatchEventTargetStateDataV0() return map[string]interface{}{ @@ -24,6 +33,16 @@ func testResourceAwsCloudWatchEventTargetStateDataV1() map[string]interface{} { } } +func testResourceAwsCloudWatchEventTargetStateDataV1EventBusName() map[string]interface{} { + v0 := testResourceAwsCloudWatchEventTargetStateDataV0EventBusName() + return map[string]interface{}{ + "arn": v0["arn"], + "event_bus_name": v0["event_bus_name"], + "rule": v0["rule"], + "target_id": v0["target_id"], + } +} + func TestResourceAwsCloudWatchEventTargetStateUpgradeV0(t *testing.T) { expected := testResourceAwsCloudWatchEventTargetStateDataV1() actual, err := resourceAwsCloudWatchEventTargetStateUpgradeV0(context.Background(), testResourceAwsCloudWatchEventTargetStateDataV0(), nil) @@ -35,3 +54,15 @@ func TestResourceAwsCloudWatchEventTargetStateUpgradeV0(t *testing.T) { t.Fatalf("\n\nexpected:\n\n%#v\n\ngot:\n\n%#v\n\n", expected, actual) } } + +func TestResourceAwsCloudWatchEventTargetStateUpgradeV0EventBusName(t *testing.T) { + expected := testResourceAwsCloudWatchEventTargetStateDataV1EventBusName() + actual, err := resourceAwsCloudWatchEventTargetStateUpgradeV0(context.Background(), testResourceAwsCloudWatchEventTargetStateDataV0EventBusName(), 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) + } +}