From 79edd37083955af5612bd5b935801ca654aff98f Mon Sep 17 00:00:00 2001 From: Daniel Basedow Date: Sun, 8 Nov 2020 20:31:55 +0100 Subject: [PATCH 01/87] added support for iot rule action "http" --- aws/resource_aws_iot_topic_rule.go | 134 ++++++++++++++++++++++++ aws/resource_aws_iot_topic_rule_test.go | 93 ++++++++++++++++ 2 files changed, 227 insertions(+) diff --git a/aws/resource_aws_iot_topic_rule.go b/aws/resource_aws_iot_topic_rule.go index 2941ae57c22..8223aa47196 100644 --- a/aws/resource_aws_iot_topic_rule.go +++ b/aws/resource_aws_iot_topic_rule.go @@ -226,6 +226,40 @@ func resourceAwsIotTopicRule() *schema.Resource { }, }, }, + "http": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + "confirmation_url": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + "headers": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, "iot_analytics": { Type: schema.TypeSet, Optional: true, @@ -1155,6 +1189,10 @@ func resourceAwsIotTopicRuleRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error setting firehose: %w", err) } + if err := d.Set("http", flattenIotHttpActions(out.Rule.Actions)); err != nil { + return fmt.Errorf("error setting http: %w", err) + } + if err := d.Set("iot_analytics", flattenIotIotAnalyticsActions(out.Rule.Actions)); err != nil { return fmt.Errorf("error setting iot_analytics: %w", err) } @@ -1210,6 +1248,7 @@ func resourceAwsIotTopicRuleUpdate(d *schema.ResourceData, meta interface{}) err "elasticsearch", "enabled", "firehose", + "http", "iot_analytics", "iot_events", "kinesis", @@ -1462,6 +1501,42 @@ func expandIotFirehoseAction(tfList []interface{}) *iot.FirehoseAction { return apiObject } +func expandIotHttpAction(tfList []interface{}) *iot.HttpAction { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + apiObject := &iot.HttpAction{} + tfMap := tfList[0].(map[string]interface{}) + + if v, ok := tfMap["url"].(string); ok && v != "" { + apiObject.Url = aws.String(v) + } + + if v, ok := tfMap["confirmation_url"].(string); ok && v != "" { + apiObject.ConfirmationUrl = aws.String(v) + } + + if v, ok := tfMap["headers"].([]interface{}); ok { + headerObjs := []*iot.HttpActionHeader{} + for _, val := range v { + if m, ok := val.(map[string]interface{}); ok { + headerObj := &iot.HttpActionHeader{} + if v, ok := m["key"].(string); ok && v != "" { + headerObj.Key = aws.String(v) + } + if v, ok := m["value"].(string); ok && v != "" { + headerObj.Value = aws.String(v) + } + headerObjs = append(headerObjs, headerObj) + } + } + apiObject.Headers = headerObjs + } + + return apiObject +} + func expandIotIotAnalyticsAction(tfList []interface{}) *iot.IotAnalyticsAction { if len(tfList) == 0 || tfList[0] == nil { return nil @@ -1726,6 +1801,17 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { actions = append(actions, &iot.Action{Firehose: action}) } + // Legacy root attribute handling + for _, tfMapRaw := range d.Get("http").(*schema.Set).List() { + action := expandIotHttpAction([]interface{}{tfMapRaw}) + + if action == nil { + continue + } + + actions = append(actions, &iot.Action{Http: action}) + } + // Legacy root attribute handling for _, tfMapRaw := range d.Get("iot_analytics").(*schema.Set).List() { action := expandIotIotAnalyticsAction([]interface{}{tfMapRaw}) @@ -2705,3 +2791,51 @@ func flattenIotStepFunctionsAction(apiObject *iot.StepFunctionsAction) []interfa return []interface{}{tfMap} } + +// Legacy root attribute handling +func flattenIotHttpActions(actions []*iot.Action) []interface{} { + results := make([]interface{}, 0) + + for _, action := range actions { + if action == nil { + continue + } + + if v := action.Http; v != nil { + results = append(results, flattenIotHttpAction(v)...) + } + } + + return results +} + +func flattenIotHttpAction(apiObject *iot.HttpAction) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := make(map[string]interface{}) + + if v := apiObject.Url; v != nil { + tfMap["url"] = aws.StringValue(v) + } + + if v := apiObject.ConfirmationUrl; v != nil { + tfMap["confirmation_url"] = aws.StringValue(v) + } + + if v := apiObject.Headers; v != nil { + headers := []map[string]string{} + + for _, h := range v { + m := map[string]string{ + "key": aws.StringValue(h.Key), + "value": aws.StringValue(h.Value), + } + headers = append(headers, m) + } + tfMap["headers"] = headers + } + + return []interface{}{tfMap} +} diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 9a596fe3730..8bb4783d89c 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -271,6 +271,42 @@ func TestAccAWSIoTTopicRule_firehose_separator(t *testing.T) { }) } +func TestAccAWSIoTTopicRule_http(t *testing.T) { + rName := acctest.RandString(5) + resourceName := "aws_iot_topic_rule.rule" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSIoTTopicRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSIoTTopicRule_http(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSIoTTopicRule_http_confirmation_url(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), + ), + }, + { + Config: testAccAWSIoTTopicRule_http_headers(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), + ), + }, + }, + }) +} + func TestAccAWSIoTTopicRule_kinesis(t *testing.T) { rName := acctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" @@ -841,6 +877,63 @@ resource "aws_iot_topic_rule" "rule" { `, rName, separator) } +func testAccAWSIoTTopicRule_http(rName string) string { + return fmt.Sprintf(` +resource "aws_iot_topic_rule" "rule" { + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + http { + url = "https://foo.bar/ingress" + } +} +`, rName) +} + +func testAccAWSIoTTopicRule_http_confirmation_url(rName string) string { + return fmt.Sprintf(` +resource "aws_iot_topic_rule" "rule" { + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + http { + url = "https://foo.bar/ingress" + confirmation_url = "https://foo.bar/" + } +} +`, rName) +} + +func testAccAWSIoTTopicRule_http_headers(rName string) string { + return fmt.Sprintf(` +resource "aws_iot_topic_rule" "rule" { + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + http { + url = "https://foo.bar/ingress" + headers { + key = "foo" + value = "bar" + } + headers { + key = "oof" + value = "rab" + } + } +} +`, rName) +} + func testAccAWSIoTTopicRule_kinesis(rName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` resource "aws_iot_topic_rule" "rule" { From a120e2cdd0f02c5e9f1ba22928f29da8f8fb4b8f Mon Sep 17 00:00:00 2001 From: Daniel Basedow Date: Mon, 9 Nov 2020 10:27:17 +0100 Subject: [PATCH 02/87] rename headers to http_header --- aws/resource_aws_iot_topic_rule.go | 6 +++--- aws/resource_aws_iot_topic_rule_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule.go b/aws/resource_aws_iot_topic_rule.go index 8223aa47196..07170896a32 100644 --- a/aws/resource_aws_iot_topic_rule.go +++ b/aws/resource_aws_iot_topic_rule.go @@ -241,7 +241,7 @@ func resourceAwsIotTopicRule() *schema.Resource { Optional: true, ValidateFunc: validation.IsURLWithHTTPS, }, - "headers": { + "http_header": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ @@ -1517,7 +1517,7 @@ func expandIotHttpAction(tfList []interface{}) *iot.HttpAction { apiObject.ConfirmationUrl = aws.String(v) } - if v, ok := tfMap["headers"].([]interface{}); ok { + if v, ok := tfMap["http_header"].([]interface{}); ok { headerObjs := []*iot.HttpActionHeader{} for _, val := range v { if m, ok := val.(map[string]interface{}); ok { @@ -2834,7 +2834,7 @@ func flattenIotHttpAction(apiObject *iot.HttpAction) []interface{} { } headers = append(headers, m) } - tfMap["headers"] = headers + tfMap["http_header"] = headers } return []interface{}{tfMap} diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 8bb4783d89c..e6fdce13292 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -921,11 +921,11 @@ resource "aws_iot_topic_rule" "rule" { http { url = "https://foo.bar/ingress" - headers { + http_header { key = "foo" value = "bar" } - headers { + http_header { key = "oof" value = "rab" } From 72a156daaed28a82006a2e3f61573f7ef6f819d9 Mon Sep 17 00:00:00 2001 From: Daniel Basedow Date: Mon, 9 Nov 2020 10:54:17 +0100 Subject: [PATCH 03/87] add support for http error actions --- aws/resource_aws_iot_topic_rule.go | 82 +++++++++++++++++++++++++ aws/resource_aws_iot_topic_rule_test.go | 28 +++++++++ 2 files changed, 110 insertions(+) diff --git a/aws/resource_aws_iot_topic_rule.go b/aws/resource_aws_iot_topic_rule.go index 07170896a32..026bc7fcd6c 100644 --- a/aws/resource_aws_iot_topic_rule.go +++ b/aws/resource_aws_iot_topic_rule.go @@ -495,6 +495,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -547,6 +548,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -619,6 +621,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -663,6 +666,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -711,6 +715,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -751,6 +756,60 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.step_functions", + "error_action.0.sns", + "error_action.0.sqs", + }, + }, + "http": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + "confirmation_url": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + "http_header": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + ExactlyOneOf: []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -786,6 +845,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -825,6 +885,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -864,6 +925,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -895,6 +957,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -936,6 +999,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -975,6 +1039,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -1014,6 +1079,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -1055,6 +1121,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -1094,6 +1161,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -1982,6 +2050,16 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { iotErrorAction = &iot.Action{Firehose: action} } + case "http": + for _, tfMapRaw := range v.([]interface{}) { + action := expandIotHttpAction([]interface{}{tfMapRaw}) + + if action == nil { + continue + } + + iotErrorAction = &iot.Action{Http: action} + } case "iot_analytics": for _, tfMapRaw := range v.([]interface{}) { action := expandIotIotAnalyticsAction([]interface{}{tfMapRaw}) @@ -2730,6 +2808,10 @@ func flattenIotErrorAction(errorAction *iot.Action) []map[string]interface{} { results = append(results, map[string]interface{}{"firehose": flattenIotFirehoseActions(input)}) return results } + if errorAction.Http != nil { + results = append(results, map[string]interface{}{"http": flattenIotHttpActions(input)}) + return results + } if errorAction.IotAnalytics != nil { results = append(results, map[string]interface{}{"iot_analytics": flattenIotIotAnalyticsActions(input)}) return results diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index e6fdce13292..af4e116ab55 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -303,6 +303,12 @@ func TestAccAWSIoTTopicRule_http(t *testing.T) { testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), ), }, + { + Config: testAccAWSIoTTopicRule_http_errorAction(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), + ), + }, }, }) } @@ -934,6 +940,28 @@ resource "aws_iot_topic_rule" "rule" { `, rName) } +func testAccAWSIoTTopicRule_http_errorAction(rName string) string { + return fmt.Sprintf(` +resource "aws_iot_topic_rule" "rule" { + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + http { + url = "https://foo.bar/ingress" + } + + error_action { + http { + url = "https://bar.foo/error-ingress" + } + } +} +`, rName) +} + func testAccAWSIoTTopicRule_kinesis(rName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` resource "aws_iot_topic_rule" "rule" { From 796742f83bdfc38e6ae05172724d55aa9d71cfa3 Mon Sep 17 00:00:00 2001 From: Daniel Basedow Date: Mon, 9 Nov 2020 10:55:38 +0100 Subject: [PATCH 04/87] update documentation for http action --- website/docs/r/iot_topic_rule.html.markdown | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/website/docs/r/iot_topic_rule.html.markdown b/website/docs/r/iot_topic_rule.html.markdown index 221d63ecd0d..c9c7b02cf42 100644 --- a/website/docs/r/iot_topic_rule.html.markdown +++ b/website/docs/r/iot_topic_rule.html.markdown @@ -88,7 +88,7 @@ EOF * `enabled` - (Required) Specifies whether the rule is enabled. * `sql` - (Required) The SQL statement used to query the topic. For more information, see AWS IoT SQL Reference (http://docs.aws.amazon.com/iot/latest/developerguide/iot-rules.html#aws-iot-sql-reference) in the AWS IoT Developer Guide. * `sql_version` - (Required) The version of the SQL rules engine to use when evaluating the rule. -* `error_action` - (Optional) Configuration block with error action to be associated with the rule. See the documentation for `cloudwatch_alarm`, `cloudwatch_metric`, `dynamodb`, `dynamodbv2`, `elasticsearch`, `firehose`, `iot_analytics`, `iot_events`, `kinesis`, `lambda`, `republish`, `s3`, `step_functions`, `sns`, `sqs` configuration blocks for further configuration details. +* `error_action` - (Optional) Configuration block with error action to be associated with the rule. See the documentation for `cloudwatch_alarm`, `cloudwatch_metric`, `dynamodb`, `dynamodbv2`, `elasticsearch`, `firehose`, `http`, `iot_analytics`, `iot_events`, `kinesis`, `lambda`, `republish`, `s3`, `step_functions`, `sns`, `sqs` configuration blocks for further configuration details. * `tags` - (Optional) Key-value map of resource tags The `cloudwatch_alarm` object takes the following arguments: @@ -140,6 +140,17 @@ The `firehose` object takes the following arguments: * `role_arn` - (Required) The IAM role ARN that grants access to the Amazon Kinesis Firehose stream. * `separator` - (Optional) A character separator that is used to separate records written to the Firehose stream. Valid values are: '\n' (newline), '\t' (tab), '\r\n' (Windows newline), ',' (comma). +The `http` object takes the following arguments: + +* `url` - (Required) The HTTPS URL. +* `confirmation_url` - (Optional) The HTTPS URL used to verify ownership of `url`. +* `http_header` - (Optional) Custom HTTP header IoT Core should send. It is possible to define more than one custom header. + +The `http_header` object takes the following arguments: + +* `key` - (Required) The name of the HTTP header. +* `value` - (Required) The value of the HTTP header. + The `kinesis` object takes the following arguments: * `partition_key` - (Optional) The partition key. From d4767b909e1b4d4ffa9bef0dfa864c2393c39c72 Mon Sep 17 00:00:00 2001 From: Daniel Basedow Date: Mon, 9 Nov 2020 11:32:17 +0100 Subject: [PATCH 05/87] fix formatting of test data --- aws/resource_aws_iot_topic_rule_test.go | 52 ++++++++++++------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index af4e116ab55..9f3a6e58d03 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -893,7 +893,7 @@ resource "aws_iot_topic_rule" "rule" { sql_version = "2015-10-08" http { - url = "https://foo.bar/ingress" + url = "https://foo.bar/ingress" } } `, rName) @@ -909,8 +909,8 @@ resource "aws_iot_topic_rule" "rule" { sql_version = "2015-10-08" http { - url = "https://foo.bar/ingress" - confirmation_url = "https://foo.bar/" + url = "https://foo.bar/ingress" + confirmation_url = "https://foo.bar/" } } `, rName) @@ -926,15 +926,15 @@ resource "aws_iot_topic_rule" "rule" { sql_version = "2015-10-08" http { - url = "https://foo.bar/ingress" - http_header { - key = "foo" - value = "bar" - } - http_header { - key = "oof" - value = "rab" - } + url = "https://foo.bar/ingress" + http_header { + key = "foo" + value = "bar" + } + http_header { + key = "oof" + value = "rab" + } } } `, rName) @@ -943,21 +943,21 @@ resource "aws_iot_topic_rule" "rule" { func testAccAWSIoTTopicRule_http_errorAction(rName string) string { return fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" - enabled = true - sql = "SELECT * FROM 'topic/test'" - sql_version = "2015-10-08" - - http { - url = "https://foo.bar/ingress" - } + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" - error_action { - http { - url = "https://bar.foo/error-ingress" - } - } + http { + url = "https://foo.bar/ingress" + } + + error_action { + http { + url = "https://bar.foo/error-ingress" + } + } } `, rName) } From 76dae68dcf61eae843491113ebf49582ccbe573a Mon Sep 17 00:00:00 2001 From: Todd Radigan Date: Wed, 7 Apr 2021 17:07:50 -0400 Subject: [PATCH 06/87] add kafka rule type to iot topic rules --- aws/resource_aws_iot_topic_rule.go | 595 ++++++++++++++++++++++++ aws/resource_aws_iot_topic_rule_test.go | 50 ++ 2 files changed, 645 insertions(+) diff --git a/aws/resource_aws_iot_topic_rule.go b/aws/resource_aws_iot_topic_rule.go index 315815c0f1e..d9e89cd044f 100644 --- a/aws/resource_aws_iot_topic_rule.go +++ b/aws/resource_aws_iot_topic_rule.go @@ -264,6 +264,143 @@ func resourceAwsIotTopicRule() *schema.Resource { }, }, }, + "kafka": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "acks": { + Type: schema.TypeInt, + Optional: true, + Default: 1, + ValidateFunc: validation.IntBetween(0, 1), + }, + "bootstrap_servers": { + Type: schema.TypeString, + Required: true, + }, + "compression_type": { + Type: schema.TypeString, + Optional: true, + Default: "none", + ValidateFunc: validation.StringInSlice([]string{ + "none", + "gzip", + "snappy", + "lz4", + "zstd", + }, false), + }, + "destination_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + "key": { + Type: schema.TypeString, + Optional: true, + }, + "key_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.StringSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.StringSerializer", + }, false), + }, + "partition": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_keytab": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_krb5_kdc": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_krb5_realm": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_principal": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_service_name": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_mechanism": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "PLAIN", + "GSSAPI", + "SCRAM-SHA-512", + }, false), + }, + "sasl_plain_username": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_plain_password": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_scram_username": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_scram_password": { + Type: schema.TypeString, + Optional: true, + }, + "security_protocol": { + Type: schema.TypeString, + Optional: true, + Default: "SSL", + ValidateFunc: validation.StringInSlice([]string{ + "SSL", + "SASL_SSL", + }, false), + }, + "ssl_key_password": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_keystore": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_keystore_password": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_truststore": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_truststore_password": { + Type: schema.TypeString, + Optional: true, + }, + "topic": { + Type: schema.TypeString, + Required: true, + }, + "value_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.ByteBufferSerializer", + }, false), + }, + }, + }, + }, "kinesis": { Type: schema.TypeSet, Optional: true, @@ -463,6 +600,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -515,6 +653,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -587,6 +726,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -631,6 +771,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -679,6 +820,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -719,6 +861,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -754,6 +897,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -793,6 +937,163 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.step_functions", + "error_action.0.sns", + "error_action.0.sqs", + }, + }, + "kafka": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "acks": { + Type: schema.TypeInt, + Optional: true, + Default: 1, + ValidateFunc: validation.IntBetween(0, 1), + }, + "bootstrap_servers": { + Type: schema.TypeString, + Required: true, + }, + "compression_type": { + Type: schema.TypeString, + Optional: true, + Default: "none", + ValidateFunc: validation.StringInSlice([]string{ + "none", + "gzip", + "snappy", + "lz4", + "zstd", + }, false), + }, + "destination_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + "key": { + Type: schema.TypeString, + Optional: true, + }, + "key_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.StringSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.StringSerializer", + }, false), + }, + "partition": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_keytab": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_krb5_kdc": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_krb5_realm": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_principal": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_service_name": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_mechanism": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "PLAIN", + "GSSAPI", + "SCRAM-SHA-512", + }, false), + }, + "sasl_plain_username": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_plain_password": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_scram_username": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_scram_password": { + Type: schema.TypeString, + Optional: true, + }, + "security_protocol": { + Type: schema.TypeString, + Optional: true, + Default: "SSL", + ValidateFunc: validation.StringInSlice([]string{ + "SSL", + "SASL_SSL", + }, false), + }, + "ssl_key_password": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_keystore": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_keystore_password": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_truststore": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_truststore_password": { + Type: schema.TypeString, + Optional: true, + }, + "topic": { + Type: schema.TypeString, + Required: true, + }, + "value_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.ByteBufferSerializer", + }, false), + }, + }, + }, + ExactlyOneOf: []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -832,6 +1133,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -863,6 +1165,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -904,6 +1207,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -943,6 +1247,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -982,6 +1287,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1023,6 +1329,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1062,6 +1369,7 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1163,6 +1471,10 @@ func resourceAwsIotTopicRuleRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error setting iot_events: %w", err) } + if err := d.Set("kafka", flattenIotKafkaActions(out.Rule.Actions)); err != nil { + return fmt.Errorf("error setting kafka: %w", err) + } + if err := d.Set("kinesis", flattenIotKinesisActions(out.Rule.Actions)); err != nil { return fmt.Errorf("error setting kinesis: %w", err) } @@ -1212,6 +1524,7 @@ func resourceAwsIotTopicRuleUpdate(d *schema.ResourceData, meta interface{}) err "firehose", "iot_analytics", "iot_events", + "kafka", "kinesis", "lambda", "republish", @@ -1504,6 +1817,126 @@ func expandIotIotEventsAction(tfList []interface{}) *iot.IotEventsAction { return apiObject } +func expandIotKafkaAction(tfList []interface{}) *iot.KafkaAction { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + apiObject := &iot.KafkaAction{} + tfMap := tfList[0].(map[string]interface{}) + clientProperties := make(map[string]*string) + + if v, ok := tfMap["acks"].(string); ok && v != "" { + clientProperties["acks"] = aws.String(v) + } + + if v, ok := tfMap["bootstrap_servers"].(string); ok && v != "" { + clientProperties["bootstrap.servers"] = aws.String(v) + } + + if v, ok := tfMap["compression_type"].(string); ok && v != "" { + clientProperties["compression.type"] = aws.String(v) + } + + if v, ok := tfMap["destination_arn"].(string); ok && v != "" { + apiObject.DestinationArn = aws.String(v) + } + + if v, ok := tfMap["key"].(string); ok && v != "" { + apiObject.Key = aws.String(v) + } + + if v, ok := tfMap["key_serializer"].(string); ok && v != "" { + clientProperties["key.serializer"] = aws.String(v) + } + + if v, ok := tfMap["partition"].(string); ok && v != "" { + apiObject.Partition = aws.String(v) + } + + if sp, ok := tfMap["security_protocol"].(string); ok && sp != "" { + clientProperties["security.protocol"] = aws.String(sp) + + switch sp { + case "SSL": + if v, ok := tfMap["ssl_keystore"].(string); ok && v != "" { + clientProperties["ssl.keystore"] = aws.String(v) + } + + if v, ok := tfMap["ssl_keystore_password"].(string); ok && v != "" { + clientProperties["ssl.keystore.password"] = aws.String(v) + } + + if v, ok := tfMap["ssl_key_password"].(string); ok && v != "" { + clientProperties["ssl.key.password"] = aws.String(v) + } + case "SASL": + if mechanism, ok := tfMap["sasl_mechanism"].(string); ok && mechanism != "" { + clientProperties["sasl.mechanism"] = aws.String(mechanism) + + switch mechanism { + case "PLAIN": + if v, ok := tfMap["sasl_plain_username"].(string); ok && v != "" { + clientProperties["sasl.plain.username"] = aws.String(v) + } + + if v, ok := tfMap["sasl_plain_password"].(string); ok && v != "" { + clientProperties["sasl.plain.password"] = aws.String(v) + } + case "SCRAM-SHA-512": + if v, ok := tfMap["sasl_scram_username"].(string); ok && v != "" { + clientProperties["sasl.scram.username"] = aws.String(v) + } + + if v, ok := tfMap["sasl_scram_password"].(string); ok && v != "" { + clientProperties["sasl.scram.password"] = aws.String(v) + } + case "GSSAPI": + if v, ok := tfMap["sasl_kerberos_keytab"].(string); ok && v != "" { + clientProperties["sasl.kerberos.keytab"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_krb5_kdc"].(string); ok && v != "" { + clientProperties["sasl.kerberos.krb5.kdc"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_krb5_realm"].(string); ok && v != "" { + clientProperties["sasl.kerberos.krb5.realm"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_principal"].(string); ok && v != "" { + clientProperties["sasl.kerberos.principal"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_service_name"].(string); ok && v != "" { + clientProperties["sasl.kerberos.service.name"] = aws.String(v) + } + } + } + } + } + + if v, ok := tfMap["ssl_truststore"].(string); ok && v != "" { + clientProperties["ssl.truststore"] = aws.String(v) + } + + if v, ok := tfMap["ssl_truststore_password"].(string); ok && v != "" { + clientProperties["ssl.truststore.password"] = aws.String(v) + } + + if v, ok := tfMap["topic"].(string); ok && v != "" { + apiObject.Topic = aws.String(v) + } + + if v, ok := tfMap["value_serializer"].(string); ok && v != "" { + clientProperties["value.serializer"] = aws.String(v) + } + + apiObject.ClientProperties = clientProperties + + return apiObject +} + func expandIotKinesisAction(tfList []interface{}) *iot.KinesisAction { if len(tfList) == 0 || tfList[0] == nil { return nil @@ -1748,6 +2181,17 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { actions = append(actions, &iot.Action{IotEvents: action}) } + // Legacy root attribute handling + for _, tfMapRaw := range d.Get("kafka").(*schema.Set).List() { + action := expandIotKafkaAction([]interface{}{tfMapRaw}) + + if action == nil { + continue + } + + actions = append(actions, &iot.Action{Kafka: action}) + } + // Legacy root attribute handling for _, tfMapRaw := range d.Get("kinesis").(*schema.Set).List() { action := expandIotKinesisAction([]interface{}{tfMapRaw}) @@ -1916,6 +2360,16 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { iotErrorAction = &iot.Action{IotEvents: action} } + case "kafka": + for _, tfMapRaw := range v.([]interface{}) { + action := expandIotKafkaAction([]interface{}{tfMapRaw}) + + if action == nil { + continue + } + + iotErrorAction = &iot.Action{Kafka: action} + } case "kinesis": for _, tfMapRaw := range v.([]interface{}) { action := expandIotKinesisAction([]interface{}{tfMapRaw}) @@ -2356,6 +2810,143 @@ func flattenIotIotEventsAction(apiObject *iot.IotEventsAction) []interface{} { return []interface{}{tfMap} } +// Legacy root attribute handling +func flattenIotKafkaActions(actions []*iot.Action) []interface{} { + results := make([]interface{}, 0) + + for _, action := range actions { + if action == nil { + continue + } + + if v := action.Kafka; v != nil { + results = append(results, flattenIotKafkaAction(v)...) + } + } + + return results +} + +func flattenIotKafkaAction(apiObject *iot.KafkaAction) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := make(map[string]interface{}) + + if v := apiObject.DestinationArn; v != nil { + tfMap["destination_arn"] = aws.StringValue(v) + } + + if v := apiObject.Key; v != nil { + tfMap["key"] = aws.StringValue(v) + } + + if v := apiObject.Partition; v != nil { + tfMap["partition"] = aws.StringValue(v) + } + + if v := apiObject.Topic; v != nil { + tfMap["topic"] = aws.StringValue(v) + } + + if cp := apiObject.ClientProperties; cp != nil { + if v, ok := cp["acks"]; ok && v != nil { + tfMap["acks"] = aws.StringValue(v) + } + + if v, ok := cp["bootstrap.servers"]; ok && v != nil { + tfMap["bootstrap_servers"] = aws.StringValue(v) + } + + if v, ok := cp["compression.type"]; ok && v != nil { + tfMap["compression_type"] = aws.StringValue(v) + } + + if v, ok := cp["key.serializer"]; ok && v != nil { + tfMap["key_serializer"] = aws.StringValue(v) + } + + if v, ok := cp["value.serializer"]; ok && v != nil { + tfMap["value_serializer"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.truststore"]; ok && v != nil { + tfMap["ssl_truststore"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.truststore.password"]; ok && v != nil { + tfMap["ssl_truststore_password"] = aws.StringValue(v) + } + + if sp, ok := cp["security.protocol"]; ok && sp != nil { + protocol := aws.StringValue(sp) + tfMap["security_protocol"] = protocol + + switch protocol { + case "SSL": + if v, ok := cp["ssl.keystore"]; ok && v != nil { + tfMap["ssl_keystore"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.keystore.password"]; ok && v != nil { + tfMap["ssl_keystore_password"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.key.password"]; ok && v != nil { + tfMap["ssl_key_password"] = aws.StringValue(v) + } + case "SASL": + if m, ok := cp["sasl.mechanism"]; ok && m != nil { + mechanism := aws.StringValue(m) + tfMap["sasl_mechanism"] = mechanism + + switch mechanism { + case "PLAIN": + if v, ok := cp["sasl.plain.username"]; ok && v != nil { + tfMap["sasl_plain_username"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.plain.password"]; ok && v != nil { + tfMap["sasl_plain_password"] = aws.StringValue(v) + } + case "SCRAM-SHA-512": + if v, ok := cp["sasl.scram.username"]; ok && v != nil { + tfMap["sasl_scram_username"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.scram.password"]; ok && v != nil { + tfMap["sasl_scram_password"] = aws.StringValue(v) + } + case "GSSAPI": + if v, ok := cp["sasl.kerberos.keytab"]; ok && v != nil { + tfMap["sasl_kerberos_keytab"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.krb5.kdc"]; ok && v != nil { + tfMap["sasl_kerberos_krb5_kdc"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.krb5.realm"]; ok && v != nil { + tfMap["sasl_kerberos_krb5_realm"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.principal"]; ok && v != nil { + tfMap["sasl_kerberos_principal"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.service.name"]; ok && v != nil { + tfMap["sasl_kerberos_service_name"] = aws.StringValue(v) + } + } + } + } + } + } + + return []interface{}{tfMap} +} + // Legacy root attribute handling func flattenIotKinesisActions(actions []*iot.Action) []interface{} { results := make([]interface{}, 0) @@ -2652,6 +3243,10 @@ func flattenIotErrorAction(errorAction *iot.Action) []map[string]interface{} { results = append(results, map[string]interface{}{"iot_events": flattenIotIotEventsActions(input)}) return results } + if errorAction.Kafka != nil { + results = append(results, map[string]interface{}{"kafka": flattenIotKafkaActions(input)}) + return results + } if errorAction.Kinesis != nil { results = append(results, map[string]interface{}{"kinesis": flattenIotKinesisActions(input)}) return results diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 061162aab9d..f8aa3e7293f 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -279,6 +279,31 @@ func TestAccAWSIoTTopicRule_firehose_separator(t *testing.T) { }) } +func TestAccAWSIoTTopicRule_kafka(t *testing.T) { + rName := acctest.RandString(5) + resourceName := "aws_iot_topic_rule.rule" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, iot.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSIoTTopicRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSIoTTopicRule_kafka(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSIoTTopicRule_kinesis(t *testing.T) { rName := acctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" @@ -861,6 +886,31 @@ resource "aws_iot_topic_rule" "rule" { `, rName, separator) } +func testAccAWSIoTTopicRule_kafka(rName string) string { + return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` +resource "aws_vpc" "iot_vpc" { + cidr_block = "10.0.0.0/16" +} +resource "aws_secretsmanager_secret" "keystore" { + name = "keystore" +} +resource "aws_iot_topic_rule" "rule" { + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + kafka { + destination_arn = aws_vpc.iot_vpc.arn + topic = "fake_topic" + bootstrap_servers = "b-1.localhost:9094" + ssl_keystore = "${get_secret("aws_secretsmanager_secret.keystore.arn", "SecretBinary", "", "aws_iam_role.iot_role.arn")}" + ssl_keystore_password = "password" + } +} +`, rName) +} + func testAccAWSIoTTopicRule_kinesis(rName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` resource "aws_iot_topic_rule" "rule" { From e06d81fa6380513018d980d7a7c6f50ff81e8e22 Mon Sep 17 00:00:00 2001 From: Todd Radigan Date: Wed, 7 Apr 2021 17:29:36 -0400 Subject: [PATCH 07/87] add changelog --- .changelog/18639.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/18639.txt diff --git a/.changelog/18639.txt b/.changelog/18639.txt new file mode 100644 index 00000000000..2c8b044d456 --- /dev/null +++ b/.changelog/18639.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_iot_topic_rule: Add `kafka` iot rule type +``` From d4712e18f87edd95bbcd2db3934fabf1bef3e54f Mon Sep 17 00:00:00 2001 From: Todd Radigan Date: Thu, 8 Apr 2021 11:10:29 -0400 Subject: [PATCH 08/87] escape get_secret --- aws/resource_aws_iot_topic_rule_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index f8aa3e7293f..3fc16e00c65 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -901,10 +901,10 @@ resource "aws_iot_topic_rule" "rule" { sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" kafka { - destination_arn = aws_vpc.iot_vpc.arn - topic = "fake_topic" - bootstrap_servers = "b-1.localhost:9094" - ssl_keystore = "${get_secret("aws_secretsmanager_secret.keystore.arn", "SecretBinary", "", "aws_iam_role.iot_role.arn")}" + destination_arn = aws_vpc.iot_vpc.arn + topic = "fake_topic" + bootstrap_servers = "b-1.localhost:9094" + ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.keystore.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" ssl_keystore_password = "password" } } From 75db50436250350c7a36622e1728bfe8bbbf3590 Mon Sep 17 00:00:00 2001 From: Todd Radigan Date: Thu, 8 Apr 2021 12:28:55 -0400 Subject: [PATCH 09/87] randomize secret name in test --- aws/resource_aws_iot_topic_rule_test.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 3fc16e00c65..8c835420ba5 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -281,6 +281,7 @@ func TestAccAWSIoTTopicRule_firehose_separator(t *testing.T) { func TestAccAWSIoTTopicRule_kafka(t *testing.T) { rName := acctest.RandString(5) + kName := acctest.RandomWithPrefix("secret_key") resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -290,7 +291,7 @@ func TestAccAWSIoTTopicRule_kafka(t *testing.T) { CheckDestroy: testAccCheckAWSIoTTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSIoTTopicRule_kafka(rName), + Config: testAccAWSIoTTopicRule_kafka(rName, kName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -886,13 +887,10 @@ resource "aws_iot_topic_rule" "rule" { `, rName, separator) } -func testAccAWSIoTTopicRule_kafka(rName string) string { +func testAccAWSIoTTopicRule_kafka(rName, kName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` -resource "aws_vpc" "iot_vpc" { - cidr_block = "10.0.0.0/16" -} -resource "aws_secretsmanager_secret" "keystore" { - name = "keystore" +resource "aws_secretsmanager_secret" "%[2]s" { + name = "%[2]s" } resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -901,14 +899,14 @@ resource "aws_iot_topic_rule" "rule" { sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" kafka { - destination_arn = aws_vpc.iot_vpc.arn + destination_arn = "[vpc destination arn]" topic = "fake_topic" bootstrap_servers = "b-1.localhost:9094" - ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.keystore.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" + ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.%[2]s.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" ssl_keystore_password = "password" } } -`, rName) +`, rName, kName) } func testAccAWSIoTTopicRule_kinesis(rName string) string { From 4716b20c50b9c04b039c9f320f82e1313b036a80 Mon Sep 17 00:00:00 2001 From: Todd Radigan Date: Thu, 8 Apr 2021 13:23:20 -0400 Subject: [PATCH 10/87] lint: TypeSet -> TypeList --- aws/resource_aws_iot_topic_rule.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_iot_topic_rule.go b/aws/resource_aws_iot_topic_rule.go index d9e89cd044f..4b03449e90c 100644 --- a/aws/resource_aws_iot_topic_rule.go +++ b/aws/resource_aws_iot_topic_rule.go @@ -948,7 +948,7 @@ func resourceAwsIotTopicRule() *schema.Resource { }, }, "kafka": { - Type: schema.TypeSet, + Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ From 8b3392f7a93ad74ae6221662343cc0d0f41e9570 Mon Sep 17 00:00:00 2001 From: Todd Radigan Date: Thu, 8 Apr 2021 13:34:45 -0400 Subject: [PATCH 11/87] lint: fix spacing --- aws/resource_aws_iot_topic_rule_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 8c835420ba5..44ab5889e5e 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -890,7 +890,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccAWSIoTTopicRule_kafka(rName, kName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` resource "aws_secretsmanager_secret" "%[2]s" { - name = "%[2]s" + name = "%[2]s" } resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -899,11 +899,11 @@ resource "aws_iot_topic_rule" "rule" { sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" kafka { - destination_arn = "[vpc destination arn]" - topic = "fake_topic" - bootstrap_servers = "b-1.localhost:9094" - ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.%[2]s.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" - ssl_keystore_password = "password" + destination_arn = "[vpc destination arn]" + topic = "fake_topic" + bootstrap_servers = "b-1.localhost:9094" + ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.%[2]s.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" + ssl_keystore_password = "password" } } `, rName, kName) From 5f837a9cedd87a9f5bdc4e71bd0f8ea82a83320d Mon Sep 17 00:00:00 2001 From: Todd Radigan Date: Thu, 8 Apr 2021 16:46:54 -0400 Subject: [PATCH 12/87] remove secret creation --- aws/resource_aws_iot_topic_rule_test.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 44ab5889e5e..391d8cdb148 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -281,7 +281,6 @@ func TestAccAWSIoTTopicRule_firehose_separator(t *testing.T) { func TestAccAWSIoTTopicRule_kafka(t *testing.T) { rName := acctest.RandString(5) - kName := acctest.RandomWithPrefix("secret_key") resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -291,7 +290,7 @@ func TestAccAWSIoTTopicRule_kafka(t *testing.T) { CheckDestroy: testAccCheckAWSIoTTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSIoTTopicRule_kafka(rName, kName), + Config: testAccAWSIoTTopicRule_kafka(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -887,11 +886,8 @@ resource "aws_iot_topic_rule" "rule" { `, rName, separator) } -func testAccAWSIoTTopicRule_kafka(rName, kName string) string { +func testAccAWSIoTTopicRule_kafka(rName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` -resource "aws_secretsmanager_secret" "%[2]s" { - name = "%[2]s" -} resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" description = "Example rule" @@ -902,11 +898,11 @@ resource "aws_iot_topic_rule" "rule" { destination_arn = "[vpc destination arn]" topic = "fake_topic" bootstrap_servers = "b-1.localhost:9094" - ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.%[2]s.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" + ssl_keystore = "$${get_secret('secret_name', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" ssl_keystore_password = "password" } } -`, rName, kName) +`, rName) } func testAccAWSIoTTopicRule_kinesis(rName string) string { From 45c5f7d00f68b114655a2705771c974572f203b0 Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Wed, 22 Dec 2021 16:07:58 -0300 Subject: [PATCH 13/87] r/aws_iot_topic_rule: read support for timestream action --- internal/service/iot/topic_rule.go | 151 +++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index ecc0a43de41..7fcf8d7c5d8 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -16,6 +16,19 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/verify" ) +var timestreamDimensionResource *schema.Resource = &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, +} + func ResourceTopicRule() *schema.Resource { return &schema.Resource{ Create: resourceTopicRuleCreate, @@ -429,6 +442,49 @@ func ResourceTopicRule() *schema.Resource { }, "tags": tftags.TagsSchema(), "tags_all": tftags.TagsSchemaComputed(), + "timestream": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "database_name": { + Type: schema.TypeString, + Required: true, + }, + "dimension": { + Type: schema.TypeSet, + Required: true, + Elem: timestreamDimensionResource, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "table_name": { + Type: schema.TypeString, + Required: true, + }, + "timestamp": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, "error_action": { Type: schema.TypeList, Optional: true, @@ -1231,6 +1287,10 @@ func resourceTopicRuleRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error setting step_functions: %w", err) } + if err := d.Set("timestream", flattenIotTimestreamActions(out.Rule.Actions)); err != nil { + return fmt.Errorf("error setting timestream: %w", err) + } + if err := d.Set("error_action", flattenIotErrorAction(out.Rule.ErrorAction)); err != nil { return fmt.Errorf("error setting error_action: %w", err) } @@ -2725,6 +2785,23 @@ func flattenIotErrorAction(errorAction *iot.Action) []map[string]interface{} { return results } +// Legacy root attribute handling +func flattenIotTimestreamActions(actions []*iot.Action) []interface{} { + results := make([]interface{}, 0) + + for _, action := range actions { + if action == nil { + continue + } + + if v := action.Timestream; v != nil { + results = append(results, flattenIotTimestreamAction(v)...) + } + } + + return results +} + func flattenIotStepFunctionsAction(apiObject *iot.StepFunctionsAction) []interface{} { if apiObject == nil { return nil @@ -2746,3 +2823,77 @@ func flattenIotStepFunctionsAction(apiObject *iot.StepFunctionsAction) []interfa return []interface{}{tfMap} } + +func flattenIotTimestreamAction(apiObject *iot.TimestreamAction) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := make(map[string]interface{}) + + if v := apiObject.DatabaseName; v != nil { + tfMap["database_name"] = aws.StringValue(v) + } + + if v := apiObject.Dimensions; v != nil { + tfMap["dimension"] = flattenIotTimestreamDimensions(v) + } + + if v := apiObject.RoleArn; v != nil { + tfMap["role_arn"] = aws.StringValue(v) + } + + if v := apiObject.TableName; v != nil { + tfMap["table_name"] = aws.StringValue(v) + } + + if v := apiObject.Timestamp; v != nil { + tfMap["timestamp"] = flattenIotTimestreamTimestamp(v) + } + + return []interface{}{tfMap} +} + +func flattenIotTimestreamDimensions(apiObjects []*iot.TimestreamDimension) *schema.Set { + if apiObjects == nil { + return nil + } + + tfSet := schema.NewSet(schema.HashResource(timestreamDimensionResource), []interface{}{}) + + for _, apiObject := range apiObjects { + if apiObject != nil { + tfMap := make(map[string]interface{}) + + if v := apiObject.Name; v != nil { + tfMap["name"] = aws.StringValue(v) + } + + if v := apiObject.Value; v != nil { + tfMap["value"] = aws.StringValue(v) + } + + tfSet.Add(tfMap) + } + } + + return tfSet +} + +func flattenIotTimestreamTimestamp(apiObject *iot.TimestreamTimestamp) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := make(map[string]interface{}) + + if v := apiObject.Unit; v != nil { + tfMap["unit"] = aws.StringValue(v) + } + + if v := apiObject.Value; v != nil { + tfMap["value"] = aws.StringValue(v) + } + + return []interface{}{tfMap} +} From d5b741b3581af2e7329d35671b9b8da9024595dc Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Wed, 22 Dec 2021 18:24:13 -0300 Subject: [PATCH 14/87] r/aws_iot_topic_rule: create/update support for timestream action --- internal/service/iot/topic_rule.go | 87 ++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index 7fcf8d7c5d8..09295cfc767 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -1322,6 +1322,7 @@ func resourceTopicRuleUpdate(d *schema.ResourceData, meta interface{}) error { "sql", "sql_version", "sqs", + "timestream", ) { input := &iot.ReplaceTopicRuleInput{ RuleName: aws.String(d.Get("name").(string)), @@ -1758,6 +1759,81 @@ func expandIotStepFunctionsAction(tfList []interface{}) *iot.StepFunctionsAction return apiObject } +func expandIotTimestreamAction(tfList []interface{}) *iot.TimestreamAction { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + apiObject := &iot.TimestreamAction{} + tfMap := tfList[0].(map[string]interface{}) + + if v, ok := tfMap["database_name"].(string); ok && v != "" { + apiObject.DatabaseName = aws.String(v) + } + + if v, ok := tfMap["dimension"].(*schema.Set); ok { + apiObject.Dimensions = expandIotTimestreamDimensions(v) + } + + if v, ok := tfMap["role_arn"].(string); ok && v != "" { + apiObject.RoleArn = aws.String(v) + } + + if v, ok := tfMap["table_name"].(string); ok && v != "" { + apiObject.TableName = aws.String(v) + } + + if v, ok := tfMap["timestamp"].([]interface{}); ok { + apiObject.Timestamp = expandIotTimestreamTimestamp(v) + } + + return apiObject +} + +func expandIotTimestreamDimensions(tfSet *schema.Set) []*iot.TimestreamDimension { + if tfSet == nil || tfSet.Len() == 0 { + return nil + } + + apiObjects := make([]*iot.TimestreamDimension, tfSet.Len()) + for i, elem := range tfSet.List() { + if tfMap, ok := elem.(map[string]interface{}); ok { + apiObject := &iot.TimestreamDimension{} + + if v, ok := tfMap["name"].(string); ok && v != "" { + apiObject.Name = aws.String(v) + } + + if v, ok := tfMap["value"].(string); ok && v != "" { + apiObject.Value = aws.String(v) + } + + apiObjects[i] = apiObject + } + } + + return apiObjects +} + +func expandIotTimestreamTimestamp(tfList []interface{}) *iot.TimestreamTimestamp { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + apiObject := &iot.TimestreamTimestamp{} + tfMap := tfList[0].(map[string]interface{}) + + if v, ok := tfMap["unit"].(string); ok && v != "" { + apiObject.Unit = aws.String(v) + } + + if v, ok := tfMap["value"].(string); ok && v != "" { + apiObject.Value = aws.String(v) + } + + return apiObject +} + func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { var actions []*iot.Action @@ -1926,6 +2002,17 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { actions = append(actions, &iot.Action{StepFunctions: action}) } + // Legacy root attribute handling + for _, tfMapRaw := range d.Get("timestream").(*schema.Set).List() { + action := expandIotTimestreamAction([]interface{}{tfMapRaw}) + + if action == nil { + continue + } + + actions = append(actions, &iot.Action{Timestream: action}) + } + // Prevent sending empty Actions: // - missing required field, CreateTopicRuleInput.TopicRulePayload.Actions if len(actions) == 0 { From dccefb9549a506387a201533109bd221055f0244 Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Thu, 23 Dec 2021 10:50:46 -0300 Subject: [PATCH 15/87] r/aws_iot_topic_rule: timestream as error action --- internal/service/iot/topic_rule.go | 91 ++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index 09295cfc767..bd75277848a 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -533,6 +533,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "cloudwatch_metric": { @@ -585,6 +586,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "dynamodb": { @@ -657,6 +659,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "dynamodbv2": { @@ -701,6 +704,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "elasticsearch": { @@ -749,6 +753,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "firehose": { @@ -789,6 +794,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "iot_analytics": { @@ -824,6 +830,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "iot_events": { @@ -863,6 +870,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "kinesis": { @@ -902,6 +910,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "lambda": { @@ -933,6 +942,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "republish": { @@ -974,6 +984,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "s3": { @@ -1013,6 +1024,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "step_functions": { @@ -1052,6 +1064,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "sns": { @@ -1093,6 +1106,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", }, }, "sqs": { @@ -1132,6 +1146,69 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.step_functions", "error_action.0.sns", "error_action.0.sqs", + "error_action.0.timestream", + }, + }, + "timestream": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "database_name": { + Type: schema.TypeString, + Required: true, + }, + "dimension": { + Type: schema.TypeSet, + Required: true, + Elem: timestreamDimensionResource, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "table_name": { + Type: schema.TypeString, + Required: true, + }, + "timestamp": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + ExactlyOneOf: []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.step_functions", + "error_action.0.sns", + "error_action.0.sqs", + "error_action.0.timestream", }, }, }, @@ -2174,6 +2251,16 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { iotErrorAction = &iot.Action{StepFunctions: action} } + case "timestream": + for _, tfMapRaw := range v.([]interface{}) { + action := expandIotTimestreamAction([]interface{}{tfMapRaw}) + + if action == nil { + continue + } + + iotErrorAction = &iot.Action{Timestream: action} + } } } } @@ -2868,6 +2955,10 @@ func flattenIotErrorAction(errorAction *iot.Action) []map[string]interface{} { results = append(results, map[string]interface{}{"step_functions": flattenIotStepFunctionsActions(input)}) return results } + if errorAction.Timestream != nil { + results = append(results, map[string]interface{}{"timestream": flattenIotTimestreamActions(input)}) + return results + } return results } From 37cc161df2ca5207a1c6e747aa0a0bd4265bee46 Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Thu, 23 Dec 2021 12:17:01 -0300 Subject: [PATCH 16/87] r/aws_iot_topic_rule: test for timestream as iot action --- internal/service/iot/topic_rule_test.go | 55 +++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 3705b3f72e9..efdfb62a35c 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -425,6 +425,31 @@ func TestAccIoTTopicRule_Step_functions(t *testing.T) { }) } +func TestAccIoTTopicRule_Timestream(t *testing.T) { + rName := sdkacctest.RandString(5) + resourceName := "aws_iot_topic_rule.rule" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, iot.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckTopicRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTopicRule_timestream(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccIoTTopicRule_IoT_analytics(t *testing.T) { rName := sdkacctest.RandString(5) @@ -1019,6 +1044,36 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } +func testAccTopicRule_timestream(rName string) string { + return acctest.ConfigCompose( + testAccTopicRuleRole(rName), + fmt.Sprintf(` +resource "aws_iot_topic_rule" "rule" { + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + timestream { + database_name = "TestDB" + role_arn = aws_iam_role.iot_role.arn + table_name = "test_table" + + dimension { + name = "dim" + value = "$${dim}" + } + + timestamp { + unit = "MILLISECONDS" + value = "$${time}" + } + } +} +`, rName)) +} + func testAccTopicRule_iot_analytics(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRole(rName), From 6f0e7278c35e8a5e74ea3f9f8aa3fb901bfd82c1 Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Thu, 23 Dec 2021 15:01:53 -0300 Subject: [PATCH 17/87] r/aws_iot_topic_rule: docs for timestream as iot action --- internal/service/iot/topic_rule.go | 12 ++++++++++++ website/docs/r/iot_topic_rule.html.markdown | 14 +++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index bd75277848a..8825c9bf05f 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -474,6 +474,12 @@ func ResourceTopicRule() *schema.Resource { "unit": { Type: schema.TypeString, Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "SECONDS", + "MILLISECONDS", + "MICROSECONDS", + "NANOSECONDS", + }, false), }, "value": { Type: schema.TypeString, @@ -1182,6 +1188,12 @@ func ResourceTopicRule() *schema.Resource { "unit": { Type: schema.TypeString, Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "SECONDS", + "MILLISECONDS", + "MICROSECONDS", + "NANOSECONDS", + }, false), }, "value": { Type: schema.TypeString, diff --git a/website/docs/r/iot_topic_rule.html.markdown b/website/docs/r/iot_topic_rule.html.markdown index fbe52a1f0ef..0fa72131a4a 100644 --- a/website/docs/r/iot_topic_rule.html.markdown +++ b/website/docs/r/iot_topic_rule.html.markdown @@ -88,7 +88,7 @@ EOF * `enabled` - (Required) Specifies whether the rule is enabled. * `sql` - (Required) The SQL statement used to query the topic. For more information, see AWS IoT SQL Reference (http://docs.aws.amazon.com/iot/latest/developerguide/iot-rules.html#aws-iot-sql-reference) in the AWS IoT Developer Guide. * `sql_version` - (Required) The version of the SQL rules engine to use when evaluating the rule. -* `error_action` - (Optional) Configuration block with error action to be associated with the rule. See the documentation for `cloudwatch_alarm`, `cloudwatch_metric`, `dynamodb`, `dynamodbv2`, `elasticsearch`, `firehose`, `iot_analytics`, `iot_events`, `kinesis`, `lambda`, `republish`, `s3`, `step_functions`, `sns`, `sqs` configuration blocks for further configuration details. +* `error_action` - (Optional) Configuration block with error action to be associated with the rule. See the documentation for `cloudwatch_alarm`, `cloudwatch_metric`, `dynamodb`, `dynamodbv2`, `elasticsearch`, `firehose`, `iot_analytics`, `iot_events`, `kinesis`, `lambda`, `republish`, `s3`, `step_functions`, `sns`, `sqs`, `timestream` configuration blocks for further configuration details. * `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. The `cloudwatch_alarm` object takes the following arguments: @@ -180,6 +180,18 @@ The `step_functions` object takes the following arguments: * `state_machine_name` - (Required) The name of the Step Functions state machine whose execution will be started. * `role_arn` - (Required) The ARN of the IAM role that grants access to start execution of the state machine. +The `timestream` object takes the following arguments: + +* `database_name` - (Required) The name of an Amazon Timestream database. +* `dimension` - (Required) Configuration blocks with metadata attributes of the time series that are written in each measure record. Nested arguments below. + * `name` - (Required) The metadata dimension name. This is the name of the column in the Amazon Timestream database table record. + * `value` - (Required) The value to write in this column of the database record. +* `role_arn` - (Required) The ARN of the role that grants permission to write to the Amazon Timestream database table. +* `table_name` - (Required) The name of the database table into which to write the measure records. +* `timestamp` - (Optional) Configuration block specifying an application-defined value to replace the default value assigned to the Timestream record's timestamp in the time column. Nested arguments below. + * `unit` - (Required) The precision of the timestamp value that results from the expression described in value. Valid values: `SECONDS`, `MILLISECONDS`, `MICROSECONDS`, `NANOSECONDS`. + * `value` - (Required) An expression that returns a long epoch time value. + The `iot_analytics` object takes the following arguments: * `channel_name` - (Required) Name of AWS IOT Analytics channel. From 0c398c295bae75f728cd228f1daa19c928c4af7a Mon Sep 17 00:00:00 2001 From: James Lavoy Date: Fri, 22 Apr 2022 16:54:45 -0600 Subject: [PATCH 18/87] initial push --- internal/service/iot/topic_rule.go | 646 ++++++++++++++++++++++++++++- 1 file changed, 624 insertions(+), 22 deletions(-) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index 78cfce7af8e..02cc9e50859 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -287,6 +287,146 @@ func ResourceTopicRule() *schema.Resource { }, }, }, + "kafka": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "acks": { + Type: schema.TypeString, + Optional: true, + Default: 1, + ValidateFunc: validation.StringInSlice([]string{ + "0", + "1", + }, false), + }, + "bootstrap_servers": { + Type: schema.TypeString, + Required: true, + }, + "compression_type": { + Type: schema.TypeString, + Optional: true, + Default: "none", + ValidateFunc: validation.StringInSlice([]string{ + "none", + "gzip", + "snappy", + "lz4", + "zstd", + }, false), + }, + "destination_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "key": { + Type: schema.TypeString, + Optional: true, + }, + "key_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.StringSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.StringSerializer", + }, false), + }, + "partition": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_keytab": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_krb5_kdc": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_krb5_realm": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_principal": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_service_name": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_mechanism": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "PLAIN", + "GSSAPI", + "SCRAM-SHA-512", + }, false), + }, + "sasl_plain_username": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_plain_password": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_scram_username": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_scram_password": { + Type: schema.TypeString, + Optional: true, + }, + "security_protocol": { + Type: schema.TypeString, + Optional: true, + Default: "SSL", + ValidateFunc: validation.StringInSlice([]string{ + "SSL", + "SASL_SSL", + }, false), + }, + "ssl_key_password": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_keystore": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_keystore_password": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_truststore": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_truststore_password": { + Type: schema.TypeString, + Optional: true, + }, + "topic": { + Type: schema.TypeString, + Required: true, + }, + "value_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.ByteBufferSerializer", + }, false), + }, + }, + }, + }, "kinesis": { Type: schema.TypeSet, Optional: true, @@ -488,6 +628,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -524,6 +665,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -577,6 +719,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -650,6 +793,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -695,6 +839,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -744,6 +889,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -785,6 +931,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -821,6 +968,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -861,6 +1009,167 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.step_functions", + "error_action.0.sns", + "error_action.0.sqs", + }, + }, + "kafka": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "acks": { + Type: schema.TypeString, + Optional: true, + Default: 1, + ValidateFunc: validation.StringInSlice([]string{ + "0", + "1", + }, false), + }, + "bootstrap_servers": { + Type: schema.TypeString, + Required: true, + }, + "compression_type": { + Type: schema.TypeString, + Optional: true, + Default: "none", + ValidateFunc: validation.StringInSlice([]string{ + "none", + "gzip", + "snappy", + "lz4", + "zstd", + }, false), + }, + "destination_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "key": { + Type: schema.TypeString, + Optional: true, + }, + "key_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.StringSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.StringSerializer", + }, false), + }, + "partition": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_keytab": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_krb5_kdc": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_krb5_realm": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_principal": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_service_name": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_mechanism": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "PLAIN", + "GSSAPI", + "SCRAM-SHA-512", + }, false), + }, + "sasl_plain_username": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_plain_password": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_scram_username": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_scram_password": { + Type: schema.TypeString, + Optional: true, + }, + "security_protocol": { + Type: schema.TypeString, + Optional: true, + Default: "SSL", + ValidateFunc: validation.StringInSlice([]string{ + "SSL", + "SASL_SSL", + }, false), + }, + "ssl_key_password": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_keystore": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_keystore_password": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_truststore": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_truststore_password": { + Type: schema.TypeString, + Optional: true, + }, + "topic": { + Type: schema.TypeString, + Required: true, + }, + "value_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.ByteBufferSerializer", + }, false), + }, + }, + }, + ExactlyOneOf: []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_logs", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -901,6 +1210,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -933,6 +1243,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -975,6 +1286,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1015,6 +1327,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1055,6 +1368,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1097,6 +1411,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1137,6 +1452,7 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", + "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1303,6 +1619,10 @@ func resourceTopicRuleRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error setting step_functions: %w", err) } + if err := d.Set("kafka", flattenIotKafkaActions(out.Rule.Actions)); err != nil { + return fmt.Errorf("error setting kafka: %w", err) + } + if err := d.Set("error_action", flattenIotErrorAction(out.Rule.ErrorAction)); err != nil { return fmt.Errorf("error setting error_action: %w", err) } @@ -1326,6 +1646,7 @@ func resourceTopicRuleUpdate(d *schema.ResourceData, meta interface{}) error { "firehose", "iot_analytics", "iot_events", + "kafka", "kinesis", "lambda", "republish", @@ -1790,6 +2111,126 @@ func expandIotStepFunctionsAction(tfList []interface{}) *iot.StepFunctionsAction return apiObject } +func expandIotKafkaAction(tfList []interface{}) *iot.KafkaAction { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + apiObject := &iot.KafkaAction{} + tfMap := tfList[0].(map[string]interface{}) + clientProperties := make(map[string]*string) + + if v, ok := tfMap["acks"].(string); ok && v != "" { + clientProperties["acks"] = aws.String(v) + } + + if v, ok := tfMap["bootstrap_servers"].(string); ok && v != "" { + clientProperties["bootstrap.servers"] = aws.String(v) + } + + if v, ok := tfMap["compression_type"].(string); ok && v != "" { + clientProperties["compression.type"] = aws.String(v) + } + + if v, ok := tfMap["destination_arn"].(string); ok && v != "" { + apiObject.DestinationArn = aws.String(v) + } + + if v, ok := tfMap["key"].(string); ok && v != "" { + apiObject.Key = aws.String(v) + } + + if v, ok := tfMap["key_serializer"].(string); ok && v != "" { + clientProperties["key.serializer"] = aws.String(v) + } + + if v, ok := tfMap["partition"].(string); ok && v != "" { + apiObject.Partition = aws.String(v) + } + + if sp, ok := tfMap["security_protocol"].(string); ok && sp != "" { + clientProperties["security.protocol"] = aws.String(sp) + + switch sp { + case "SSL": + if v, ok := tfMap["ssl_keystore"].(string); ok && v != "" { + clientProperties["ssl.keystore"] = aws.String(v) + } + + if v, ok := tfMap["ssl_keystore_password"].(string); ok && v != "" { + clientProperties["ssl.keystore.password"] = aws.String(v) + } + + if v, ok := tfMap["ssl_key_password"].(string); ok && v != "" { + clientProperties["ssl.key.password"] = aws.String(v) + } + case "SASL": + if mechanism, ok := tfMap["sasl_mechanism"].(string); ok && mechanism != "" { + clientProperties["sasl.mechanism"] = aws.String(mechanism) + + switch mechanism { + case "PLAIN": + if v, ok := tfMap["sasl_plain_username"].(string); ok && v != "" { + clientProperties["sasl.plain.username"] = aws.String(v) + } + + if v, ok := tfMap["sasl_plain_password"].(string); ok && v != "" { + clientProperties["sasl.plain.password"] = aws.String(v) + } + case "SCRAM-SHA-512": + if v, ok := tfMap["sasl_scram_username"].(string); ok && v != "" { + clientProperties["sasl.scram.username"] = aws.String(v) + } + + if v, ok := tfMap["sasl_scram_password"].(string); ok && v != "" { + clientProperties["sasl.scram.password"] = aws.String(v) + } + case "GSSAPI": + if v, ok := tfMap["sasl_kerberos_keytab"].(string); ok && v != "" { + clientProperties["sasl.kerberos.keytab"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_krb5_kdc"].(string); ok && v != "" { + clientProperties["sasl.kerberos.krb5.kdc"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_krb5_realm"].(string); ok && v != "" { + clientProperties["sasl.kerberos.krb5.realm"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_principal"].(string); ok && v != "" { + clientProperties["sasl.kerberos.principal"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_service_name"].(string); ok && v != "" { + clientProperties["sasl.kerberos.service.name"] = aws.String(v) + } + } + } + } + } + + if v, ok := tfMap["ssl_truststore"].(string); ok && v != "" { + clientProperties["ssl.truststore"] = aws.String(v) + } + + if v, ok := tfMap["ssl_truststore_password"].(string); ok && v != "" { + clientProperties["ssl.truststore.password"] = aws.String(v) + } + + if v, ok := tfMap["topic"].(string); ok && v != "" { + apiObject.Topic = aws.String(v) + } + + if v, ok := tfMap["value_serializer"].(string); ok && v != "" { + clientProperties["value.serializer"] = aws.String(v) + } + + apiObject.ClientProperties = clientProperties + + return apiObject +} + func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { var actions []*iot.Action @@ -1892,6 +2333,17 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { actions = append(actions, &iot.Action{IotEvents: action}) } + // Legacy root attribute handling + for _, tfMapRaw := range d.Get("kafka").(*schema.Set).List() { + action := expandIotKafkaAction([]interface{}{tfMapRaw}) + + if action == nil { + continue + } + + actions = append(actions, &iot.Action{Kafka: action}) + } + // Legacy root attribute handling for _, tfMapRaw := range d.Get("kinesis").(*schema.Set).List() { action := expandIotKinesisAction([]interface{}{tfMapRaw}) @@ -2070,6 +2522,16 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { iotErrorAction = &iot.Action{IotEvents: action} } + case "kafka": + for _, tfMapRaw := range v.([]interface{}) { + action := expandIotKafkaAction([]interface{}{tfMapRaw}) + + if action == nil { + continue + } + + iotErrorAction = &iot.Action{Kafka: action} + } case "kinesis": for _, tfMapRaw := range v.([]interface{}) { action := expandIotKinesisAction([]interface{}{tfMapRaw}) @@ -2802,6 +3264,164 @@ func flattenIotStepFunctionsActions(actions []*iot.Action) []interface{} { return results } +func flattenIotStepFunctionsAction(apiObject *iot.StepFunctionsAction) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := make(map[string]interface{}) + + if v := apiObject.ExecutionNamePrefix; v != nil { + tfMap["execution_name_prefix"] = aws.StringValue(v) + } + + if v := apiObject.StateMachineName; v != nil { + tfMap["state_machine_name"] = aws.StringValue(v) + } + + if v := apiObject.RoleArn; v != nil { + tfMap["role_arn"] = aws.StringValue(v) + } + + return []interface{}{tfMap} +} + +func flattenIotKafkaActions(actions []*iot.Action) []interface{} { + results := make([]interface{}, 0) + + for _, action := range actions { + if action == nil { + continue + } + + if v := action.Kafka; v != nil { + results = append(results, flattenIotKafkaAction(v)...) + } + } + + return results +} + +func flattenIotKafkaAction(apiObject *iot.KafkaAction) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := make(map[string]interface{}) + + if v := apiObject.DestinationArn; v != nil { + tfMap["destination_arn"] = aws.StringValue(v) + } + + if v := apiObject.Key; v != nil { + tfMap["key"] = aws.StringValue(v) + } + + if v := apiObject.Partition; v != nil { + tfMap["partition"] = aws.StringValue(v) + } + + if v := apiObject.Topic; v != nil { + tfMap["topic"] = aws.StringValue(v) + } + + if cp := apiObject.ClientProperties; cp != nil { + if v, ok := cp["acks"]; ok && v != nil { + tfMap["acks"] = aws.StringValue(v) + } + + if v, ok := cp["bootstrap.servers"]; ok && v != nil { + tfMap["bootstrap_servers"] = aws.StringValue(v) + } + + if v, ok := cp["compression.type"]; ok && v != nil { + tfMap["compression_type"] = aws.StringValue(v) + } + + if v, ok := cp["key.serializer"]; ok && v != nil { + tfMap["key_serializer"] = aws.StringValue(v) + } + + if v, ok := cp["value.serializer"]; ok && v != nil { + tfMap["value_serializer"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.truststore"]; ok && v != nil { + tfMap["ssl_truststore"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.truststore.password"]; ok && v != nil { + tfMap["ssl_truststore_password"] = aws.StringValue(v) + } + + if sp, ok := cp["security.protocol"]; ok && sp != nil { + protocol := aws.StringValue(sp) + tfMap["security_protocol"] = protocol + + switch protocol { + case "SSL": + if v, ok := cp["ssl.keystore"]; ok && v != nil { + tfMap["ssl_keystore"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.keystore.password"]; ok && v != nil { + tfMap["ssl_keystore_password"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.key.password"]; ok && v != nil { + tfMap["ssl_key_password"] = aws.StringValue(v) + } + case "SASL": + if m, ok := cp["sasl.mechanism"]; ok && m != nil { + mechanism := aws.StringValue(m) + tfMap["sasl_mechanism"] = mechanism + + switch mechanism { + case "PLAIN": + if v, ok := cp["sasl.plain.username"]; ok && v != nil { + tfMap["sasl_plain_username"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.plain.password"]; ok && v != nil { + tfMap["sasl_plain_password"] = aws.StringValue(v) + } + case "SCRAM-SHA-512": + if v, ok := cp["sasl.scram.username"]; ok && v != nil { + tfMap["sasl_scram_username"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.scram.password"]; ok && v != nil { + tfMap["sasl_scram_password"] = aws.StringValue(v) + } + case "GSSAPI": + if v, ok := cp["sasl.kerberos.keytab"]; ok && v != nil { + tfMap["sasl_kerberos_keytab"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.krb5.kdc"]; ok && v != nil { + tfMap["sasl_kerberos_krb5_kdc"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.krb5.realm"]; ok && v != nil { + tfMap["sasl_kerberos_krb5_realm"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.principal"]; ok && v != nil { + tfMap["sasl_kerberos_principal"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.service.name"]; ok && v != nil { + tfMap["sasl_kerberos_service_name"] = aws.StringValue(v) + } + } + } + } + } + } + + return []interface{}{tfMap} +} + func flattenIotErrorAction(errorAction *iot.Action) []map[string]interface{} { results := make([]map[string]interface{}, 0) @@ -2845,6 +3465,10 @@ func flattenIotErrorAction(errorAction *iot.Action) []map[string]interface{} { results = append(results, map[string]interface{}{"iot_events": flattenIotIotEventsActions(input)}) return results } + if errorAction.Kafka != nil { + results = append(results, map[string]interface{}{"kafka": flattenIotKafkaActions(input)}) + return results + } if errorAction.Kinesis != nil { results = append(results, map[string]interface{}{"kinesis": flattenIotKinesisActions(input)}) return results @@ -2876,25 +3500,3 @@ func flattenIotErrorAction(errorAction *iot.Action) []map[string]interface{} { return results } - -func flattenIotStepFunctionsAction(apiObject *iot.StepFunctionsAction) []interface{} { - if apiObject == nil { - return nil - } - - tfMap := make(map[string]interface{}) - - if v := apiObject.ExecutionNamePrefix; v != nil { - tfMap["execution_name_prefix"] = aws.StringValue(v) - } - - if v := apiObject.StateMachineName; v != nil { - tfMap["state_machine_name"] = aws.StringValue(v) - } - - if v := apiObject.RoleArn; v != nil { - tfMap["role_arn"] = aws.StringValue(v) - } - - return []interface{}{tfMap} -} From 4d501690b1ebe0e4b4b905330bd5fbab110522ce Mon Sep 17 00:00:00 2001 From: James Lavoy Date: Mon, 25 Apr 2022 09:03:32 -0600 Subject: [PATCH 19/87] adding tests --- internal/service/iot/topic_rule_test.go | 45 +++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index b2f3833312f..827d0f9a8be 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -592,6 +592,30 @@ func TestAccIoTTopicRule_updateKinesisErrorAction(t *testing.T) { }) } +func TestAccIoTTopicRule_kafka(t *testing.T) { + rName := sdkacctest.RandString(5) + resourceName := "aws_iot_topic_rule.rule" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, iot.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckTopicRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTopicRule_kafka(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckTopicRuleDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn @@ -904,6 +928,27 @@ resource "aws_iot_topic_rule" "rule" { `, rName, separator)) } +func testAccTopicRule_kafka(rName string) string { + return acctest.ConfigCompose( + testAccTopicRuleRole(rName), + fmt.Sprintf(` +resource "aws_iot_topic_rule" "rule" { + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + kafka { + destination_arn = "[vpc destination arn]" + topic = "fake_topic" + bootstrap_servers = "b-1.localhost:9094" + ssl_keystore = "$${get_secret('secret_name', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" + ssl_keystore_password = "password" + } +} +`, rName)) +} + func testAccTopicRule_kinesis(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRole(rName), From f2d0d7d4979418e67b46de78959b3cb9a1cc3f78 Mon Sep 17 00:00:00 2001 From: James Lavoy Date: Mon, 25 Apr 2022 09:37:07 -0600 Subject: [PATCH 20/87] adding changelog --- .changelog/24395.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/24395.txt diff --git a/.changelog/24395.txt b/.changelog/24395.txt new file mode 100644 index 00000000000..2c8b044d456 --- /dev/null +++ b/.changelog/24395.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_iot_topic_rule: Add `kafka` iot rule type +``` From f2d578d45ea5fa8ef3c199752988d38db79628a5 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 12:07:29 -0400 Subject: [PATCH 21/87] Revert "remove secret creation" This reverts commit 5f837a9cedd87a9f5bdc4e71bd0f8ea82a83320d. --- aws/resource_aws_iot_topic_rule_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 391d8cdb148..44ab5889e5e 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -281,6 +281,7 @@ func TestAccAWSIoTTopicRule_firehose_separator(t *testing.T) { func TestAccAWSIoTTopicRule_kafka(t *testing.T) { rName := acctest.RandString(5) + kName := acctest.RandomWithPrefix("secret_key") resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -290,7 +291,7 @@ func TestAccAWSIoTTopicRule_kafka(t *testing.T) { CheckDestroy: testAccCheckAWSIoTTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSIoTTopicRule_kafka(rName), + Config: testAccAWSIoTTopicRule_kafka(rName, kName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -886,8 +887,11 @@ resource "aws_iot_topic_rule" "rule" { `, rName, separator) } -func testAccAWSIoTTopicRule_kafka(rName string) string { +func testAccAWSIoTTopicRule_kafka(rName, kName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` +resource "aws_secretsmanager_secret" "%[2]s" { + name = "%[2]s" +} resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" description = "Example rule" @@ -898,11 +902,11 @@ resource "aws_iot_topic_rule" "rule" { destination_arn = "[vpc destination arn]" topic = "fake_topic" bootstrap_servers = "b-1.localhost:9094" - ssl_keystore = "$${get_secret('secret_name', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" + ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.%[2]s.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" ssl_keystore_password = "password" } } -`, rName) +`, rName, kName) } func testAccAWSIoTTopicRule_kinesis(rName string) string { From d90a7f5fa1c75efb41c9a5b6598d54b77ff798de Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 12:07:37 -0400 Subject: [PATCH 22/87] Revert "lint: fix spacing" This reverts commit 8b3392f7a93ad74ae6221662343cc0d0f41e9570. --- aws/resource_aws_iot_topic_rule_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 44ab5889e5e..8c835420ba5 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -890,7 +890,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccAWSIoTTopicRule_kafka(rName, kName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` resource "aws_secretsmanager_secret" "%[2]s" { - name = "%[2]s" + name = "%[2]s" } resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -899,11 +899,11 @@ resource "aws_iot_topic_rule" "rule" { sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" kafka { - destination_arn = "[vpc destination arn]" - topic = "fake_topic" - bootstrap_servers = "b-1.localhost:9094" - ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.%[2]s.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" - ssl_keystore_password = "password" + destination_arn = "[vpc destination arn]" + topic = "fake_topic" + bootstrap_servers = "b-1.localhost:9094" + ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.%[2]s.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" + ssl_keystore_password = "password" } } `, rName, kName) From 09944a89d78f531bea344be93467ef33ec0860ec Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 12:07:44 -0400 Subject: [PATCH 23/87] Revert "lint: TypeSet -> TypeList" This reverts commit 4716b20c50b9c04b039c9f320f82e1313b036a80. --- aws/resource_aws_iot_topic_rule.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_iot_topic_rule.go b/aws/resource_aws_iot_topic_rule.go index 4b03449e90c..d9e89cd044f 100644 --- a/aws/resource_aws_iot_topic_rule.go +++ b/aws/resource_aws_iot_topic_rule.go @@ -948,7 +948,7 @@ func resourceAwsIotTopicRule() *schema.Resource { }, }, "kafka": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, MaxItems: 1, Elem: &schema.Resource{ From 276f511f50cb7a8f8026eea38188a1a57cc65397 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 12:07:49 -0400 Subject: [PATCH 24/87] Revert "randomize secret name in test" This reverts commit 75db50436250350c7a36622e1728bfe8bbbf3590. --- aws/resource_aws_iot_topic_rule_test.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 8c835420ba5..3fc16e00c65 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -281,7 +281,6 @@ func TestAccAWSIoTTopicRule_firehose_separator(t *testing.T) { func TestAccAWSIoTTopicRule_kafka(t *testing.T) { rName := acctest.RandString(5) - kName := acctest.RandomWithPrefix("secret_key") resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -291,7 +290,7 @@ func TestAccAWSIoTTopicRule_kafka(t *testing.T) { CheckDestroy: testAccCheckAWSIoTTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSIoTTopicRule_kafka(rName, kName), + Config: testAccAWSIoTTopicRule_kafka(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -887,10 +886,13 @@ resource "aws_iot_topic_rule" "rule" { `, rName, separator) } -func testAccAWSIoTTopicRule_kafka(rName, kName string) string { +func testAccAWSIoTTopicRule_kafka(rName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` -resource "aws_secretsmanager_secret" "%[2]s" { - name = "%[2]s" +resource "aws_vpc" "iot_vpc" { + cidr_block = "10.0.0.0/16" +} +resource "aws_secretsmanager_secret" "keystore" { + name = "keystore" } resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -899,14 +901,14 @@ resource "aws_iot_topic_rule" "rule" { sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" kafka { - destination_arn = "[vpc destination arn]" + destination_arn = aws_vpc.iot_vpc.arn topic = "fake_topic" bootstrap_servers = "b-1.localhost:9094" - ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.%[2]s.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" + ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.keystore.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" ssl_keystore_password = "password" } } -`, rName, kName) +`, rName) } func testAccAWSIoTTopicRule_kinesis(rName string) string { From a28a6dcf436ae132461af5e9c840e2cb3183275c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 12:07:55 -0400 Subject: [PATCH 25/87] Revert "escape get_secret" This reverts commit d4712e18f87edd95bbcd2db3934fabf1bef3e54f. --- aws/resource_aws_iot_topic_rule_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 3fc16e00c65..f8aa3e7293f 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -901,10 +901,10 @@ resource "aws_iot_topic_rule" "rule" { sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" kafka { - destination_arn = aws_vpc.iot_vpc.arn - topic = "fake_topic" - bootstrap_servers = "b-1.localhost:9094" - ssl_keystore = "$${get_secret('${aws_secretsmanager_secret.keystore.arn}', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" + destination_arn = aws_vpc.iot_vpc.arn + topic = "fake_topic" + bootstrap_servers = "b-1.localhost:9094" + ssl_keystore = "${get_secret("aws_secretsmanager_secret.keystore.arn", "SecretBinary", "", "aws_iam_role.iot_role.arn")}" ssl_keystore_password = "password" } } From 7cf6c37d49e4f59246c5c76f00f33322d36e14b4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 12:08:01 -0400 Subject: [PATCH 26/87] Revert "add changelog" This reverts commit e06d81fa6380513018d980d7a7c6f50ff81e8e22. --- .changelog/18639.txt | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .changelog/18639.txt diff --git a/.changelog/18639.txt b/.changelog/18639.txt deleted file mode 100644 index 2c8b044d456..00000000000 --- a/.changelog/18639.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:enhancement -resource/aws_iot_topic_rule: Add `kafka` iot rule type -``` From e8db406ea6a3840efa5509a4facbb3f0b7f13c57 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 12:08:08 -0400 Subject: [PATCH 27/87] Revert "add kafka rule type to iot topic rules" This reverts commit 76dae68dcf61eae843491113ebf49582ccbe573a. --- aws/resource_aws_iot_topic_rule.go | 595 ------------------------ aws/resource_aws_iot_topic_rule_test.go | 50 -- 2 files changed, 645 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule.go b/aws/resource_aws_iot_topic_rule.go index d9e89cd044f..315815c0f1e 100644 --- a/aws/resource_aws_iot_topic_rule.go +++ b/aws/resource_aws_iot_topic_rule.go @@ -264,143 +264,6 @@ func resourceAwsIotTopicRule() *schema.Resource { }, }, }, - "kafka": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "acks": { - Type: schema.TypeInt, - Optional: true, - Default: 1, - ValidateFunc: validation.IntBetween(0, 1), - }, - "bootstrap_servers": { - Type: schema.TypeString, - Required: true, - }, - "compression_type": { - Type: schema.TypeString, - Optional: true, - Default: "none", - ValidateFunc: validation.StringInSlice([]string{ - "none", - "gzip", - "snappy", - "lz4", - "zstd", - }, false), - }, - "destination_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateArn, - }, - "key": { - Type: schema.TypeString, - Optional: true, - }, - "key_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.StringSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.StringSerializer", - }, false), - }, - "partition": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_keytab": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_krb5_kdc": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_krb5_realm": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_principal": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_service_name": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_mechanism": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "PLAIN", - "GSSAPI", - "SCRAM-SHA-512", - }, false), - }, - "sasl_plain_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_plain_password": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_password": { - Type: schema.TypeString, - Optional: true, - }, - "security_protocol": { - Type: schema.TypeString, - Optional: true, - Default: "SSL", - ValidateFunc: validation.StringInSlice([]string{ - "SSL", - "SASL_SSL", - }, false), - }, - "ssl_key_password": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_keystore": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_keystore_password": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_truststore": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_truststore_password": { - Type: schema.TypeString, - Optional: true, - }, - "topic": { - Type: schema.TypeString, - Required: true, - }, - "value_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.ByteBufferSerializer", - }, false), - }, - }, - }, - }, "kinesis": { Type: schema.TypeSet, Optional: true, @@ -600,7 +463,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -653,7 +515,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -726,7 +587,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -771,7 +631,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -820,7 +679,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -861,7 +719,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -897,7 +754,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -937,163 +793,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - }, - }, - "kafka": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "acks": { - Type: schema.TypeInt, - Optional: true, - Default: 1, - ValidateFunc: validation.IntBetween(0, 1), - }, - "bootstrap_servers": { - Type: schema.TypeString, - Required: true, - }, - "compression_type": { - Type: schema.TypeString, - Optional: true, - Default: "none", - ValidateFunc: validation.StringInSlice([]string{ - "none", - "gzip", - "snappy", - "lz4", - "zstd", - }, false), - }, - "destination_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateArn, - }, - "key": { - Type: schema.TypeString, - Optional: true, - }, - "key_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.StringSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.StringSerializer", - }, false), - }, - "partition": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_keytab": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_krb5_kdc": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_krb5_realm": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_principal": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_service_name": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_mechanism": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "PLAIN", - "GSSAPI", - "SCRAM-SHA-512", - }, false), - }, - "sasl_plain_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_plain_password": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_password": { - Type: schema.TypeString, - Optional: true, - }, - "security_protocol": { - Type: schema.TypeString, - Optional: true, - Default: "SSL", - ValidateFunc: validation.StringInSlice([]string{ - "SSL", - "SASL_SSL", - }, false), - }, - "ssl_key_password": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_keystore": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_keystore_password": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_truststore": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_truststore_password": { - Type: schema.TypeString, - Optional: true, - }, - "topic": { - Type: schema.TypeString, - Required: true, - }, - "value_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.ByteBufferSerializer", - }, false), - }, - }, - }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1133,7 +832,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1165,7 +863,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1207,7 +904,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1247,7 +943,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1287,7 +982,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1329,7 +1023,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1369,7 +1062,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.firehose", "error_action.0.iot_analytics", "error_action.0.iot_events", - "error_action.0.kafka", "error_action.0.kinesis", "error_action.0.lambda", "error_action.0.republish", @@ -1471,10 +1163,6 @@ func resourceAwsIotTopicRuleRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error setting iot_events: %w", err) } - if err := d.Set("kafka", flattenIotKafkaActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting kafka: %w", err) - } - if err := d.Set("kinesis", flattenIotKinesisActions(out.Rule.Actions)); err != nil { return fmt.Errorf("error setting kinesis: %w", err) } @@ -1524,7 +1212,6 @@ func resourceAwsIotTopicRuleUpdate(d *schema.ResourceData, meta interface{}) err "firehose", "iot_analytics", "iot_events", - "kafka", "kinesis", "lambda", "republish", @@ -1817,126 +1504,6 @@ func expandIotIotEventsAction(tfList []interface{}) *iot.IotEventsAction { return apiObject } -func expandIotKafkaAction(tfList []interface{}) *iot.KafkaAction { - if len(tfList) == 0 || tfList[0] == nil { - return nil - } - - apiObject := &iot.KafkaAction{} - tfMap := tfList[0].(map[string]interface{}) - clientProperties := make(map[string]*string) - - if v, ok := tfMap["acks"].(string); ok && v != "" { - clientProperties["acks"] = aws.String(v) - } - - if v, ok := tfMap["bootstrap_servers"].(string); ok && v != "" { - clientProperties["bootstrap.servers"] = aws.String(v) - } - - if v, ok := tfMap["compression_type"].(string); ok && v != "" { - clientProperties["compression.type"] = aws.String(v) - } - - if v, ok := tfMap["destination_arn"].(string); ok && v != "" { - apiObject.DestinationArn = aws.String(v) - } - - if v, ok := tfMap["key"].(string); ok && v != "" { - apiObject.Key = aws.String(v) - } - - if v, ok := tfMap["key_serializer"].(string); ok && v != "" { - clientProperties["key.serializer"] = aws.String(v) - } - - if v, ok := tfMap["partition"].(string); ok && v != "" { - apiObject.Partition = aws.String(v) - } - - if sp, ok := tfMap["security_protocol"].(string); ok && sp != "" { - clientProperties["security.protocol"] = aws.String(sp) - - switch sp { - case "SSL": - if v, ok := tfMap["ssl_keystore"].(string); ok && v != "" { - clientProperties["ssl.keystore"] = aws.String(v) - } - - if v, ok := tfMap["ssl_keystore_password"].(string); ok && v != "" { - clientProperties["ssl.keystore.password"] = aws.String(v) - } - - if v, ok := tfMap["ssl_key_password"].(string); ok && v != "" { - clientProperties["ssl.key.password"] = aws.String(v) - } - case "SASL": - if mechanism, ok := tfMap["sasl_mechanism"].(string); ok && mechanism != "" { - clientProperties["sasl.mechanism"] = aws.String(mechanism) - - switch mechanism { - case "PLAIN": - if v, ok := tfMap["sasl_plain_username"].(string); ok && v != "" { - clientProperties["sasl.plain.username"] = aws.String(v) - } - - if v, ok := tfMap["sasl_plain_password"].(string); ok && v != "" { - clientProperties["sasl.plain.password"] = aws.String(v) - } - case "SCRAM-SHA-512": - if v, ok := tfMap["sasl_scram_username"].(string); ok && v != "" { - clientProperties["sasl.scram.username"] = aws.String(v) - } - - if v, ok := tfMap["sasl_scram_password"].(string); ok && v != "" { - clientProperties["sasl.scram.password"] = aws.String(v) - } - case "GSSAPI": - if v, ok := tfMap["sasl_kerberos_keytab"].(string); ok && v != "" { - clientProperties["sasl.kerberos.keytab"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_krb5_kdc"].(string); ok && v != "" { - clientProperties["sasl.kerberos.krb5.kdc"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_krb5_realm"].(string); ok && v != "" { - clientProperties["sasl.kerberos.krb5.realm"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_principal"].(string); ok && v != "" { - clientProperties["sasl.kerberos.principal"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_service_name"].(string); ok && v != "" { - clientProperties["sasl.kerberos.service.name"] = aws.String(v) - } - } - } - } - } - - if v, ok := tfMap["ssl_truststore"].(string); ok && v != "" { - clientProperties["ssl.truststore"] = aws.String(v) - } - - if v, ok := tfMap["ssl_truststore_password"].(string); ok && v != "" { - clientProperties["ssl.truststore.password"] = aws.String(v) - } - - if v, ok := tfMap["topic"].(string); ok && v != "" { - apiObject.Topic = aws.String(v) - } - - if v, ok := tfMap["value_serializer"].(string); ok && v != "" { - clientProperties["value.serializer"] = aws.String(v) - } - - apiObject.ClientProperties = clientProperties - - return apiObject -} - func expandIotKinesisAction(tfList []interface{}) *iot.KinesisAction { if len(tfList) == 0 || tfList[0] == nil { return nil @@ -2181,17 +1748,6 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { actions = append(actions, &iot.Action{IotEvents: action}) } - // Legacy root attribute handling - for _, tfMapRaw := range d.Get("kafka").(*schema.Set).List() { - action := expandIotKafkaAction([]interface{}{tfMapRaw}) - - if action == nil { - continue - } - - actions = append(actions, &iot.Action{Kafka: action}) - } - // Legacy root attribute handling for _, tfMapRaw := range d.Get("kinesis").(*schema.Set).List() { action := expandIotKinesisAction([]interface{}{tfMapRaw}) @@ -2360,16 +1916,6 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { iotErrorAction = &iot.Action{IotEvents: action} } - case "kafka": - for _, tfMapRaw := range v.([]interface{}) { - action := expandIotKafkaAction([]interface{}{tfMapRaw}) - - if action == nil { - continue - } - - iotErrorAction = &iot.Action{Kafka: action} - } case "kinesis": for _, tfMapRaw := range v.([]interface{}) { action := expandIotKinesisAction([]interface{}{tfMapRaw}) @@ -2810,143 +2356,6 @@ func flattenIotIotEventsAction(apiObject *iot.IotEventsAction) []interface{} { return []interface{}{tfMap} } -// Legacy root attribute handling -func flattenIotKafkaActions(actions []*iot.Action) []interface{} { - results := make([]interface{}, 0) - - for _, action := range actions { - if action == nil { - continue - } - - if v := action.Kafka; v != nil { - results = append(results, flattenIotKafkaAction(v)...) - } - } - - return results -} - -func flattenIotKafkaAction(apiObject *iot.KafkaAction) []interface{} { - if apiObject == nil { - return nil - } - - tfMap := make(map[string]interface{}) - - if v := apiObject.DestinationArn; v != nil { - tfMap["destination_arn"] = aws.StringValue(v) - } - - if v := apiObject.Key; v != nil { - tfMap["key"] = aws.StringValue(v) - } - - if v := apiObject.Partition; v != nil { - tfMap["partition"] = aws.StringValue(v) - } - - if v := apiObject.Topic; v != nil { - tfMap["topic"] = aws.StringValue(v) - } - - if cp := apiObject.ClientProperties; cp != nil { - if v, ok := cp["acks"]; ok && v != nil { - tfMap["acks"] = aws.StringValue(v) - } - - if v, ok := cp["bootstrap.servers"]; ok && v != nil { - tfMap["bootstrap_servers"] = aws.StringValue(v) - } - - if v, ok := cp["compression.type"]; ok && v != nil { - tfMap["compression_type"] = aws.StringValue(v) - } - - if v, ok := cp["key.serializer"]; ok && v != nil { - tfMap["key_serializer"] = aws.StringValue(v) - } - - if v, ok := cp["value.serializer"]; ok && v != nil { - tfMap["value_serializer"] = aws.StringValue(v) - } - - if v, ok := cp["ssl.truststore"]; ok && v != nil { - tfMap["ssl_truststore"] = aws.StringValue(v) - } - - if v, ok := cp["ssl.truststore.password"]; ok && v != nil { - tfMap["ssl_truststore_password"] = aws.StringValue(v) - } - - if sp, ok := cp["security.protocol"]; ok && sp != nil { - protocol := aws.StringValue(sp) - tfMap["security_protocol"] = protocol - - switch protocol { - case "SSL": - if v, ok := cp["ssl.keystore"]; ok && v != nil { - tfMap["ssl_keystore"] = aws.StringValue(v) - } - - if v, ok := cp["ssl.keystore.password"]; ok && v != nil { - tfMap["ssl_keystore_password"] = aws.StringValue(v) - } - - if v, ok := cp["ssl.key.password"]; ok && v != nil { - tfMap["ssl_key_password"] = aws.StringValue(v) - } - case "SASL": - if m, ok := cp["sasl.mechanism"]; ok && m != nil { - mechanism := aws.StringValue(m) - tfMap["sasl_mechanism"] = mechanism - - switch mechanism { - case "PLAIN": - if v, ok := cp["sasl.plain.username"]; ok && v != nil { - tfMap["sasl_plain_username"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.plain.password"]; ok && v != nil { - tfMap["sasl_plain_password"] = aws.StringValue(v) - } - case "SCRAM-SHA-512": - if v, ok := cp["sasl.scram.username"]; ok && v != nil { - tfMap["sasl_scram_username"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.scram.password"]; ok && v != nil { - tfMap["sasl_scram_password"] = aws.StringValue(v) - } - case "GSSAPI": - if v, ok := cp["sasl.kerberos.keytab"]; ok && v != nil { - tfMap["sasl_kerberos_keytab"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.kerberos.krb5.kdc"]; ok && v != nil { - tfMap["sasl_kerberos_krb5_kdc"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.kerberos.krb5.realm"]; ok && v != nil { - tfMap["sasl_kerberos_krb5_realm"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.kerberos.principal"]; ok && v != nil { - tfMap["sasl_kerberos_principal"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.kerberos.service.name"]; ok && v != nil { - tfMap["sasl_kerberos_service_name"] = aws.StringValue(v) - } - } - } - } - } - } - - return []interface{}{tfMap} -} - // Legacy root attribute handling func flattenIotKinesisActions(actions []*iot.Action) []interface{} { results := make([]interface{}, 0) @@ -3243,10 +2652,6 @@ func flattenIotErrorAction(errorAction *iot.Action) []map[string]interface{} { results = append(results, map[string]interface{}{"iot_events": flattenIotIotEventsActions(input)}) return results } - if errorAction.Kafka != nil { - results = append(results, map[string]interface{}{"kafka": flattenIotKafkaActions(input)}) - return results - } if errorAction.Kinesis != nil { results = append(results, map[string]interface{}{"kinesis": flattenIotKinesisActions(input)}) return results diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index f8aa3e7293f..061162aab9d 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -279,31 +279,6 @@ func TestAccAWSIoTTopicRule_firehose_separator(t *testing.T) { }) } -func TestAccAWSIoTTopicRule_kafka(t *testing.T) { - rName := acctest.RandString(5) - resourceName := "aws_iot_topic_rule.rule" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, iot.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSIoTTopicRuleDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSIoTTopicRule_kafka(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - func TestAccAWSIoTTopicRule_kinesis(t *testing.T) { rName := acctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" @@ -886,31 +861,6 @@ resource "aws_iot_topic_rule" "rule" { `, rName, separator) } -func testAccAWSIoTTopicRule_kafka(rName string) string { - return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` -resource "aws_vpc" "iot_vpc" { - cidr_block = "10.0.0.0/16" -} -resource "aws_secretsmanager_secret" "keystore" { - name = "keystore" -} -resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" - enabled = true - sql = "SELECT * FROM 'topic/test'" - sql_version = "2015-10-08" - kafka { - destination_arn = aws_vpc.iot_vpc.arn - topic = "fake_topic" - bootstrap_servers = "b-1.localhost:9094" - ssl_keystore = "${get_secret("aws_secretsmanager_secret.keystore.arn", "SecretBinary", "", "aws_iam_role.iot_role.arn")}" - ssl_keystore_password = "password" - } -} -`, rName) -} - func testAccAWSIoTTopicRule_kinesis(rName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` resource "aws_iot_topic_rule" "rule" { From d58bec4e7d897f7f01f7c4adc8ad02800ad1103f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 13:31:51 -0400 Subject: [PATCH 28/87] Revert "fix formatting of test data" This reverts commit d4767b909e1b4d4ffa9bef0dfa864c2393c39c72. --- aws/resource_aws_iot_topic_rule_test.go | 52 ++++++++++++------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 9f3a6e58d03..af4e116ab55 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -893,7 +893,7 @@ resource "aws_iot_topic_rule" "rule" { sql_version = "2015-10-08" http { - url = "https://foo.bar/ingress" + url = "https://foo.bar/ingress" } } `, rName) @@ -909,8 +909,8 @@ resource "aws_iot_topic_rule" "rule" { sql_version = "2015-10-08" http { - url = "https://foo.bar/ingress" - confirmation_url = "https://foo.bar/" + url = "https://foo.bar/ingress" + confirmation_url = "https://foo.bar/" } } `, rName) @@ -926,15 +926,15 @@ resource "aws_iot_topic_rule" "rule" { sql_version = "2015-10-08" http { - url = "https://foo.bar/ingress" - http_header { - key = "foo" - value = "bar" - } - http_header { - key = "oof" - value = "rab" - } + url = "https://foo.bar/ingress" + http_header { + key = "foo" + value = "bar" + } + http_header { + key = "oof" + value = "rab" + } } } `, rName) @@ -943,21 +943,21 @@ resource "aws_iot_topic_rule" "rule" { func testAccAWSIoTTopicRule_http_errorAction(rName string) string { return fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" - enabled = true - sql = "SELECT * FROM 'topic/test'" - sql_version = "2015-10-08" - - http { - url = "https://foo.bar/ingress" - } - - error_action { - http { - url = "https://bar.foo/error-ingress" + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + http { + url = "https://foo.bar/ingress" } - } + + error_action { + http { + url = "https://bar.foo/error-ingress" + } + } } `, rName) } From 4db34c1c1c7b11cbaed6ddf51bb15815e55e7a32 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 13:31:56 -0400 Subject: [PATCH 29/87] Revert "update documentation for http action" This reverts commit 796742f83bdfc38e6ae05172724d55aa9d71cfa3. --- website/docs/r/iot_topic_rule.html.markdown | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/website/docs/r/iot_topic_rule.html.markdown b/website/docs/r/iot_topic_rule.html.markdown index c9c7b02cf42..221d63ecd0d 100644 --- a/website/docs/r/iot_topic_rule.html.markdown +++ b/website/docs/r/iot_topic_rule.html.markdown @@ -88,7 +88,7 @@ EOF * `enabled` - (Required) Specifies whether the rule is enabled. * `sql` - (Required) The SQL statement used to query the topic. For more information, see AWS IoT SQL Reference (http://docs.aws.amazon.com/iot/latest/developerguide/iot-rules.html#aws-iot-sql-reference) in the AWS IoT Developer Guide. * `sql_version` - (Required) The version of the SQL rules engine to use when evaluating the rule. -* `error_action` - (Optional) Configuration block with error action to be associated with the rule. See the documentation for `cloudwatch_alarm`, `cloudwatch_metric`, `dynamodb`, `dynamodbv2`, `elasticsearch`, `firehose`, `http`, `iot_analytics`, `iot_events`, `kinesis`, `lambda`, `republish`, `s3`, `step_functions`, `sns`, `sqs` configuration blocks for further configuration details. +* `error_action` - (Optional) Configuration block with error action to be associated with the rule. See the documentation for `cloudwatch_alarm`, `cloudwatch_metric`, `dynamodb`, `dynamodbv2`, `elasticsearch`, `firehose`, `iot_analytics`, `iot_events`, `kinesis`, `lambda`, `republish`, `s3`, `step_functions`, `sns`, `sqs` configuration blocks for further configuration details. * `tags` - (Optional) Key-value map of resource tags The `cloudwatch_alarm` object takes the following arguments: @@ -140,17 +140,6 @@ The `firehose` object takes the following arguments: * `role_arn` - (Required) The IAM role ARN that grants access to the Amazon Kinesis Firehose stream. * `separator` - (Optional) A character separator that is used to separate records written to the Firehose stream. Valid values are: '\n' (newline), '\t' (tab), '\r\n' (Windows newline), ',' (comma). -The `http` object takes the following arguments: - -* `url` - (Required) The HTTPS URL. -* `confirmation_url` - (Optional) The HTTPS URL used to verify ownership of `url`. -* `http_header` - (Optional) Custom HTTP header IoT Core should send. It is possible to define more than one custom header. - -The `http_header` object takes the following arguments: - -* `key` - (Required) The name of the HTTP header. -* `value` - (Required) The value of the HTTP header. - The `kinesis` object takes the following arguments: * `partition_key` - (Optional) The partition key. From 7aab3bb672feb02c1bf0b74e48f37c538fd45cda Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 13:32:02 -0400 Subject: [PATCH 30/87] Revert "add support for http error actions" This reverts commit 72a156daaed28a82006a2e3f61573f7ef6f819d9. --- aws/resource_aws_iot_topic_rule.go | 82 ------------------------- aws/resource_aws_iot_topic_rule_test.go | 28 --------- 2 files changed, 110 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule.go b/aws/resource_aws_iot_topic_rule.go index 026bc7fcd6c..07170896a32 100644 --- a/aws/resource_aws_iot_topic_rule.go +++ b/aws/resource_aws_iot_topic_rule.go @@ -495,7 +495,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -548,7 +547,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -621,7 +619,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -666,7 +663,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -715,7 +711,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -756,60 +751,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - }, - }, - "http": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "url": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.IsURLWithHTTPS, - }, - "confirmation_url": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.IsURLWithHTTPS, - }, - "http_header": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "key": { - Type: schema.TypeString, - Required: true, - }, - "value": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - }, - }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -845,7 +786,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -885,7 +825,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -925,7 +864,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -957,7 +895,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -999,7 +936,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -1039,7 +975,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -1079,7 +1014,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -1121,7 +1055,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -1161,7 +1094,6 @@ func resourceAwsIotTopicRule() *schema.Resource { "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", - "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kinesis", @@ -2050,16 +1982,6 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { iotErrorAction = &iot.Action{Firehose: action} } - case "http": - for _, tfMapRaw := range v.([]interface{}) { - action := expandIotHttpAction([]interface{}{tfMapRaw}) - - if action == nil { - continue - } - - iotErrorAction = &iot.Action{Http: action} - } case "iot_analytics": for _, tfMapRaw := range v.([]interface{}) { action := expandIotIotAnalyticsAction([]interface{}{tfMapRaw}) @@ -2808,10 +2730,6 @@ func flattenIotErrorAction(errorAction *iot.Action) []map[string]interface{} { results = append(results, map[string]interface{}{"firehose": flattenIotFirehoseActions(input)}) return results } - if errorAction.Http != nil { - results = append(results, map[string]interface{}{"http": flattenIotHttpActions(input)}) - return results - } if errorAction.IotAnalytics != nil { results = append(results, map[string]interface{}{"iot_analytics": flattenIotIotAnalyticsActions(input)}) return results diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index af4e116ab55..e6fdce13292 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -303,12 +303,6 @@ func TestAccAWSIoTTopicRule_http(t *testing.T) { testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), ), }, - { - Config: testAccAWSIoTTopicRule_http_errorAction(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), - ), - }, }, }) } @@ -940,28 +934,6 @@ resource "aws_iot_topic_rule" "rule" { `, rName) } -func testAccAWSIoTTopicRule_http_errorAction(rName string) string { - return fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" - enabled = true - sql = "SELECT * FROM 'topic/test'" - sql_version = "2015-10-08" - - http { - url = "https://foo.bar/ingress" - } - - error_action { - http { - url = "https://bar.foo/error-ingress" - } - } -} -`, rName) -} - func testAccAWSIoTTopicRule_kinesis(rName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` resource "aws_iot_topic_rule" "rule" { From 8230107a270e380ecaa749a603d8eefe3f7ec315 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 13:32:07 -0400 Subject: [PATCH 31/87] Revert "rename headers to http_header" This reverts commit a120e2cdd0f02c5e9f1ba22928f29da8f8fb4b8f. --- aws/resource_aws_iot_topic_rule.go | 6 +++--- aws/resource_aws_iot_topic_rule_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule.go b/aws/resource_aws_iot_topic_rule.go index 07170896a32..8223aa47196 100644 --- a/aws/resource_aws_iot_topic_rule.go +++ b/aws/resource_aws_iot_topic_rule.go @@ -241,7 +241,7 @@ func resourceAwsIotTopicRule() *schema.Resource { Optional: true, ValidateFunc: validation.IsURLWithHTTPS, }, - "http_header": { + "headers": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ @@ -1517,7 +1517,7 @@ func expandIotHttpAction(tfList []interface{}) *iot.HttpAction { apiObject.ConfirmationUrl = aws.String(v) } - if v, ok := tfMap["http_header"].([]interface{}); ok { + if v, ok := tfMap["headers"].([]interface{}); ok { headerObjs := []*iot.HttpActionHeader{} for _, val := range v { if m, ok := val.(map[string]interface{}); ok { @@ -2834,7 +2834,7 @@ func flattenIotHttpAction(apiObject *iot.HttpAction) []interface{} { } headers = append(headers, m) } - tfMap["http_header"] = headers + tfMap["headers"] = headers } return []interface{}{tfMap} diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index e6fdce13292..8bb4783d89c 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -921,11 +921,11 @@ resource "aws_iot_topic_rule" "rule" { http { url = "https://foo.bar/ingress" - http_header { + headers { key = "foo" value = "bar" } - http_header { + headers { key = "oof" value = "rab" } From c8bb3fa280710ab7757952f77b31ec3efe8ce984 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 13:32:15 -0400 Subject: [PATCH 32/87] Revert "added support for iot rule action "http"" This reverts commit 79edd37083955af5612bd5b935801ca654aff98f. --- aws/resource_aws_iot_topic_rule.go | 134 ------------------------ aws/resource_aws_iot_topic_rule_test.go | 93 ---------------- 2 files changed, 227 deletions(-) diff --git a/aws/resource_aws_iot_topic_rule.go b/aws/resource_aws_iot_topic_rule.go index 8223aa47196..2941ae57c22 100644 --- a/aws/resource_aws_iot_topic_rule.go +++ b/aws/resource_aws_iot_topic_rule.go @@ -226,40 +226,6 @@ func resourceAwsIotTopicRule() *schema.Resource { }, }, }, - "http": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "url": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.IsURLWithHTTPS, - }, - "confirmation_url": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.IsURLWithHTTPS, - }, - "headers": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "key": { - Type: schema.TypeString, - Required: true, - }, - "value": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - }, - }, - }, "iot_analytics": { Type: schema.TypeSet, Optional: true, @@ -1189,10 +1155,6 @@ func resourceAwsIotTopicRuleRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error setting firehose: %w", err) } - if err := d.Set("http", flattenIotHttpActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting http: %w", err) - } - if err := d.Set("iot_analytics", flattenIotIotAnalyticsActions(out.Rule.Actions)); err != nil { return fmt.Errorf("error setting iot_analytics: %w", err) } @@ -1248,7 +1210,6 @@ func resourceAwsIotTopicRuleUpdate(d *schema.ResourceData, meta interface{}) err "elasticsearch", "enabled", "firehose", - "http", "iot_analytics", "iot_events", "kinesis", @@ -1501,42 +1462,6 @@ func expandIotFirehoseAction(tfList []interface{}) *iot.FirehoseAction { return apiObject } -func expandIotHttpAction(tfList []interface{}) *iot.HttpAction { - if len(tfList) == 0 || tfList[0] == nil { - return nil - } - - apiObject := &iot.HttpAction{} - tfMap := tfList[0].(map[string]interface{}) - - if v, ok := tfMap["url"].(string); ok && v != "" { - apiObject.Url = aws.String(v) - } - - if v, ok := tfMap["confirmation_url"].(string); ok && v != "" { - apiObject.ConfirmationUrl = aws.String(v) - } - - if v, ok := tfMap["headers"].([]interface{}); ok { - headerObjs := []*iot.HttpActionHeader{} - for _, val := range v { - if m, ok := val.(map[string]interface{}); ok { - headerObj := &iot.HttpActionHeader{} - if v, ok := m["key"].(string); ok && v != "" { - headerObj.Key = aws.String(v) - } - if v, ok := m["value"].(string); ok && v != "" { - headerObj.Value = aws.String(v) - } - headerObjs = append(headerObjs, headerObj) - } - } - apiObject.Headers = headerObjs - } - - return apiObject -} - func expandIotIotAnalyticsAction(tfList []interface{}) *iot.IotAnalyticsAction { if len(tfList) == 0 || tfList[0] == nil { return nil @@ -1801,17 +1726,6 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { actions = append(actions, &iot.Action{Firehose: action}) } - // Legacy root attribute handling - for _, tfMapRaw := range d.Get("http").(*schema.Set).List() { - action := expandIotHttpAction([]interface{}{tfMapRaw}) - - if action == nil { - continue - } - - actions = append(actions, &iot.Action{Http: action}) - } - // Legacy root attribute handling for _, tfMapRaw := range d.Get("iot_analytics").(*schema.Set).List() { action := expandIotIotAnalyticsAction([]interface{}{tfMapRaw}) @@ -2791,51 +2705,3 @@ func flattenIotStepFunctionsAction(apiObject *iot.StepFunctionsAction) []interfa return []interface{}{tfMap} } - -// Legacy root attribute handling -func flattenIotHttpActions(actions []*iot.Action) []interface{} { - results := make([]interface{}, 0) - - for _, action := range actions { - if action == nil { - continue - } - - if v := action.Http; v != nil { - results = append(results, flattenIotHttpAction(v)...) - } - } - - return results -} - -func flattenIotHttpAction(apiObject *iot.HttpAction) []interface{} { - if apiObject == nil { - return nil - } - - tfMap := make(map[string]interface{}) - - if v := apiObject.Url; v != nil { - tfMap["url"] = aws.StringValue(v) - } - - if v := apiObject.ConfirmationUrl; v != nil { - tfMap["confirmation_url"] = aws.StringValue(v) - } - - if v := apiObject.Headers; v != nil { - headers := []map[string]string{} - - for _, h := range v { - m := map[string]string{ - "key": aws.StringValue(h.Key), - "value": aws.StringValue(h.Value), - } - headers = append(headers, m) - } - tfMap["headers"] = headers - } - - return []interface{}{tfMap} -} diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 8bb4783d89c..9a596fe3730 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -271,42 +271,6 @@ func TestAccAWSIoTTopicRule_firehose_separator(t *testing.T) { }) } -func TestAccAWSIoTTopicRule_http(t *testing.T) { - rName := acctest.RandString(5) - resourceName := "aws_iot_topic_rule.rule" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSIoTTopicRuleDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSIoTTopicRule_http(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccAWSIoTTopicRule_http_confirmation_url(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), - ), - }, - { - Config: testAccAWSIoTTopicRule_http_headers(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSIoTTopicRuleExists("aws_iot_topic_rule.rule"), - ), - }, - }, - }) -} - func TestAccAWSIoTTopicRule_kinesis(t *testing.T) { rName := acctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" @@ -877,63 +841,6 @@ resource "aws_iot_topic_rule" "rule" { `, rName, separator) } -func testAccAWSIoTTopicRule_http(rName string) string { - return fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" - enabled = true - sql = "SELECT * FROM 'topic/test'" - sql_version = "2015-10-08" - - http { - url = "https://foo.bar/ingress" - } -} -`, rName) -} - -func testAccAWSIoTTopicRule_http_confirmation_url(rName string) string { - return fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" - enabled = true - sql = "SELECT * FROM 'topic/test'" - sql_version = "2015-10-08" - - http { - url = "https://foo.bar/ingress" - confirmation_url = "https://foo.bar/" - } -} -`, rName) -} - -func testAccAWSIoTTopicRule_http_headers(rName string) string { - return fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" - enabled = true - sql = "SELECT * FROM 'topic/test'" - sql_version = "2015-10-08" - - http { - url = "https://foo.bar/ingress" - headers { - key = "foo" - value = "bar" - } - headers { - key = "oof" - value = "rab" - } - } -} -`, rName) -} - func testAccAWSIoTTopicRule_kinesis(rName string) string { return fmt.Sprintf(testAccAWSIoTTopicRuleRole+` resource "aws_iot_topic_rule" "rule" { From 7746d5f05db137741c2c09fbdc92b737bd06c930 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 13:37:27 -0400 Subject: [PATCH 33/87] Add CHANGELOG entry for #16087. --- .changelog/16087.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/16087.txt diff --git a/.changelog/16087.txt b/.changelog/16087.txt new file mode 100644 index 00000000000..999db16791e --- /dev/null +++ b/.changelog/16087.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_iot_topic_rule: Add `http` and `error_action.http` arguments +``` \ No newline at end of file From c312f923927b7ebd5e15989d62a8782a2e3192ee Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 13:38:44 -0400 Subject: [PATCH 34/87] Add CHANGELOG entry for #22337. --- .changelog/22337.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/22337.txt diff --git a/.changelog/22337.txt b/.changelog/22337.txt new file mode 100644 index 00000000000..375ae5a0304 --- /dev/null +++ b/.changelog/22337.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_iot_topic_rule: Add `timestream` and `error_action.timestream` arguments +``` \ No newline at end of file From e4d77e122027b166818d3de21212950df240579c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 13:39:34 -0400 Subject: [PATCH 35/87] Tweak CHANGELOG entry for #24395. --- .changelog/24395.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/24395.txt b/.changelog/24395.txt index 2c8b044d456..97652eb1ead 100644 --- a/.changelog/24395.txt +++ b/.changelog/24395.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_iot_topic_rule: Add `kafka` iot rule type +resource/aws_iot_topic_rule: Add `kafka` and `error_action.kafka` arguments ``` From a3e64aa425a7511bd2a26920dfef3b5a15a998cf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 14:15:56 -0400 Subject: [PATCH 36/87] r/aws_iot_topic_rule: Alphabetize attributes. --- internal/service/iot/topic_rule.go | 1788 ++++++++++++++-------------- 1 file changed, 894 insertions(+), 894 deletions(-) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index 11d826132a9..74cb95329b7 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -227,443 +227,301 @@ func ResourceTopicRule() *schema.Resource { Type: schema.TypeBool, Required: true, }, - "firehose": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "delivery_stream_name": { - Type: schema.TypeString, - Required: true, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "separator": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validTopicRuleFirehoseSeparator, - }, - }, - }, - }, - "iot_analytics": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "channel_name": { - Type: schema.TypeString, - Required: true, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - }, - }, - }, - "iot_events": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "input_name": { - Type: schema.TypeString, - Required: true, - }, - "message_id": { - Type: schema.TypeString, - Optional: true, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - }, - }, - }, - "kafka": { - Type: schema.TypeSet, + "error_action": { + Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "acks": { - Type: schema.TypeString, - Optional: true, - Default: 1, - ValidateFunc: validation.StringInSlice([]string{ - "0", - "1", - }, false), - }, - "bootstrap_servers": { - Type: schema.TypeString, - Required: true, - }, - "compression_type": { - Type: schema.TypeString, - Optional: true, - Default: "none", - ValidateFunc: validation.StringInSlice([]string{ - "none", - "gzip", - "snappy", - "lz4", - "zstd", - }, false), - }, - "destination_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "key": { - Type: schema.TypeString, - Optional: true, - }, - "key_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.StringSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.StringSerializer", - }, false), - }, - "partition": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_keytab": { - Type: schema.TypeString, + "cloudwatch_alarm": { + Type: schema.TypeList, Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "alarm_name": { + Type: schema.TypeString, + Required: true, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "state_reason": { + Type: schema.TypeString, + Required: true, + }, + "state_value": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validTopicRuleCloudWatchAlarmStateValue, + }, + }, + }, + ExactlyOneOf: []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_logs", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kafka", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.step_functions", + "error_action.0.sns", + "error_action.0.sqs", + "error_action.0.timestream", + }, }, - "sasl_kerberos_krb5_kdc": { - Type: schema.TypeString, + "cloudwatch_logs": { + Type: schema.TypeList, Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "log_group_name": { + Type: schema.TypeString, + Required: true, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + }, + }, + ExactlyOneOf: []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_logs", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kafka", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.step_functions", + "error_action.0.sns", + "error_action.0.sqs", + "error_action.0.timestream", + }, }, - "sasl_kerberos_krb5_realm": { - Type: schema.TypeString, + "cloudwatch_metric": { + Type: schema.TypeList, Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_name": { + Type: schema.TypeString, + Required: true, + }, + "metric_namespace": { + Type: schema.TypeString, + Required: true, + }, + "metric_timestamp": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidUTCTimestamp, + }, + "metric_unit": { + Type: schema.TypeString, + Required: true, + }, + "metric_value": { + Type: schema.TypeString, + Required: true, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + }, + }, + ExactlyOneOf: []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_logs", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kafka", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.step_functions", + "error_action.0.sns", + "error_action.0.sqs", + "error_action.0.timestream", + }, }, - "sasl_kerberos_principal": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_service_name": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_mechanism": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "PLAIN", - "GSSAPI", - "SCRAM-SHA-512", - }, false), - }, - "sasl_plain_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_plain_password": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_password": { - Type: schema.TypeString, - Optional: true, - }, - "security_protocol": { - Type: schema.TypeString, - Optional: true, - Default: "SSL", - ValidateFunc: validation.StringInSlice([]string{ - "SSL", - "SASL_SSL", - }, false), - }, - "ssl_key_password": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_keystore": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_keystore_password": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_truststore": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_truststore_password": { - Type: schema.TypeString, - Optional: true, - }, - "topic": { - Type: schema.TypeString, - Required: true, - }, - "value_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.ByteBufferSerializer", - }, false), - }, - }, - }, - }, - "kinesis": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "partition_key": { - Type: schema.TypeString, - Optional: true, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "stream_name": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - "lambda": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "function_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - }, - }, - }, - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validTopicRuleName, - }, - "republish": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "qos": { - Type: schema.TypeInt, - Optional: true, - Default: 0, - ValidateFunc: validation.IntBetween(0, 1), - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "topic": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - "s3": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "bucket_name": { - Type: schema.TypeString, - Required: true, - }, - "key": { - Type: schema.TypeString, - Required: true, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - }, - }, - }, - "step_functions": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "execution_name_prefix": { - Type: schema.TypeString, - Optional: true, - }, - "state_machine_name": { - Type: schema.TypeString, - Required: true, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - }, - }, - }, - "sns": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "message_format": { - Type: schema.TypeString, - Default: iot.MessageFormatRaw, - Optional: true, - }, - "target_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - }, - }, - }, - "sql": { - Type: schema.TypeString, - Required: true, - }, - "sql_version": { - Type: schema.TypeString, - Required: true, - }, - "sqs": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "queue_url": { - Type: schema.TypeString, - Required: true, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "use_base64": { - Type: schema.TypeBool, - Required: true, - }, - }, - }, - }, - "tags": tftags.TagsSchema(), - "tags_all": tftags.TagsSchemaComputed(), - "timestream": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "database_name": { - Type: schema.TypeString, - Required: true, - }, - "dimension": { - Type: schema.TypeSet, - Required: true, - Elem: timestreamDimensionResource, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "table_name": { - Type: schema.TypeString, - Required: true, - }, - "timestamp": { - Type: schema.TypeList, + "dynamodb": { + Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "unit": { + "hash_key_field": { + Type: schema.TypeString, + Required: true, + }, + "hash_key_value": { Type: schema.TypeString, Required: true, + }, + "hash_key_type": { + Type: schema.TypeString, + Optional: true, + }, + "operation": { + Type: schema.TypeString, + Optional: true, ValidateFunc: validation.StringInSlice([]string{ - "SECONDS", - "MILLISECONDS", - "MICROSECONDS", - "NANOSECONDS", + "DELETE", + "INSERT", + "UPDATE", }, false), }, - "value": { + "payload_field": { + Type: schema.TypeString, + Optional: true, + }, + "range_key_field": { + Type: schema.TypeString, + Optional: true, + }, + "range_key_value": { + Type: schema.TypeString, + Optional: true, + }, + "range_key_type": { + Type: schema.TypeString, + Optional: true, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "table_name": { Type: schema.TypeString, Required: true, }, }, }, + ExactlyOneOf: []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_logs", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kafka", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.step_functions", + "error_action.0.sns", + "error_action.0.sqs", + "error_action.0.timestream", + }, }, - }, - }, - }, - "error_action": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "cloudwatch_alarm": { + "dynamodbv2": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "alarm_name": { - Type: schema.TypeString, - Required: true, + "put_item": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "table_name": { + Type: schema.TypeString, + Required: true, + }, + }, + }, }, "role_arn": { Type: schema.TypeString, Required: true, ValidateFunc: verify.ValidARN, }, - "state_reason": { + }, + }, + ExactlyOneOf: []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_logs", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kafka", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.step_functions", + "error_action.0.sns", + "error_action.0.sqs", + "error_action.0.timestream", + }, + }, + "elasticsearch": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoint": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validTopicRuleElasticsearchEndpoint, + }, + "id": { Type: schema.TypeString, Required: true, }, - "state_value": { + "index": { + Type: schema.TypeString, + Required: true, + }, + "role_arn": { Type: schema.TypeString, Required: true, - ValidateFunc: validTopicRuleCloudWatchAlarmStateValue, + ValidateFunc: verify.ValidARN, + }, + "type": { + Type: schema.TypeString, + Required: true, }, }, }, @@ -688,13 +546,13 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.timestream", }, }, - "cloudwatch_logs": { + "firehose": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "log_group_name": { + "delivery_stream_name": { Type: schema.TypeString, Required: true, }, @@ -703,6 +561,11 @@ func ResourceTopicRule() *schema.Resource { Required: true, ValidateFunc: verify.ValidARN, }, + "separator": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validTopicRuleFirehoseSeparator, + }, }, }, ExactlyOneOf: []string{ @@ -726,32 +589,57 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.timestream", }, }, - "cloudwatch_metric": { + "iot_analytics": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "metric_name": { - Type: schema.TypeString, - Required: true, - }, - "metric_namespace": { + "channel_name": { Type: schema.TypeString, Required: true, }, - "metric_timestamp": { + "role_arn": { Type: schema.TypeString, - Optional: true, - ValidateFunc: verify.ValidUTCTimestamp, + Required: true, + ValidateFunc: verify.ValidARN, }, - "metric_unit": { + }, + }, + ExactlyOneOf: []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_logs", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kafka", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.step_functions", + "error_action.0.sns", + "error_action.0.sqs", + "error_action.0.timestream", + }, + }, + "iot_events": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "input_name": { Type: schema.TypeString, Required: true, }, - "metric_value": { + "message_id": { Type: schema.TypeString, - Required: true, + Optional: true, }, "role_arn": { Type: schema.TypeString, @@ -781,58 +669,144 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.timestream", }, }, - "dynamodb": { + "kafka": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "hash_key_field": { + "acks": { + Type: schema.TypeString, + Optional: true, + Default: 1, + ValidateFunc: validation.StringInSlice([]string{ + "0", + "1", + }, false), + }, + "bootstrap_servers": { + Type: schema.TypeString, + Required: true, + }, + "compression_type": { + Type: schema.TypeString, + Optional: true, + Default: "none", + ValidateFunc: validation.StringInSlice([]string{ + "none", + "gzip", + "snappy", + "lz4", + "zstd", + }, false), + }, + "destination_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "key": { + Type: schema.TypeString, + Optional: true, + }, + "key_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.StringSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.StringSerializer", + }, false), + }, + "partition": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_keytab": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_krb5_kdc": { Type: schema.TypeString, - Required: true, + Optional: true, }, - "hash_key_value": { + "sasl_kerberos_krb5_realm": { Type: schema.TypeString, - Required: true, + Optional: true, }, - "hash_key_type": { + "sasl_kerberos_principal": { Type: schema.TypeString, Optional: true, }, - "operation": { + "sasl_kerberos_service_name": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_mechanism": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{ - "DELETE", - "INSERT", - "UPDATE", + "PLAIN", + "GSSAPI", + "SCRAM-SHA-512", }, false), }, - "payload_field": { + "sasl_plain_username": { Type: schema.TypeString, Optional: true, }, - "range_key_field": { + "sasl_plain_password": { Type: schema.TypeString, Optional: true, }, - "range_key_value": { + "sasl_scram_username": { Type: schema.TypeString, Optional: true, }, - "range_key_type": { + "sasl_scram_password": { Type: schema.TypeString, Optional: true, }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "security_protocol": { + Type: schema.TypeString, + Optional: true, + Default: "SSL", + ValidateFunc: validation.StringInSlice([]string{ + "SSL", + "SASL_SSL", + }, false), }, - "table_name": { + "ssl_key_password": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_keystore": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_keystore_password": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_truststore": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_truststore_password": { + Type: schema.TypeString, + Optional: true, + }, + "topic": { Type: schema.TypeString, Required: true, }, + "value_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.ByteBufferSerializer", + }, false), + }, }, }, ExactlyOneOf: []string{ @@ -856,30 +830,25 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.timestream", }, }, - "dynamodbv2": { + "kinesis": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "put_item": { - Type: schema.TypeList, + "partition_key": { + Type: schema.TypeString, Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "table_name": { - Type: schema.TypeString, - Required: true, - }, - }, - }, }, "role_arn": { Type: schema.TypeString, Required: true, ValidateFunc: verify.ValidARN, }, + "stream_name": { + Type: schema.TypeString, + Required: true, + }, }, }, ExactlyOneOf: []string{ @@ -903,34 +872,17 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.timestream", }, }, - "elasticsearch": { + "lambda": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "endpoint": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validTopicRuleElasticsearchEndpoint, - }, - "id": { - Type: schema.TypeString, - Required: true, - }, - "index": { - Type: schema.TypeString, - Required: true, - }, - "role_arn": { + "function_arn": { Type: schema.TypeString, Required: true, ValidateFunc: verify.ValidARN, }, - "type": { - Type: schema.TypeString, - Required: true, - }, }, }, ExactlyOneOf: []string{ @@ -954,25 +906,26 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.timestream", }, }, - "firehose": { + "republish": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "delivery_stream_name": { - Type: schema.TypeString, - Required: true, + "qos": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntBetween(0, 1), }, "role_arn": { Type: schema.TypeString, Required: true, ValidateFunc: verify.ValidARN, }, - "separator": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validTopicRuleFirehoseSeparator, + "topic": { + Type: schema.TypeString, + Required: true, }, }, }, @@ -997,13 +950,17 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.timestream", }, }, - "iot_analytics": { + "s3": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "channel_name": { + "bucket_name": { + Type: schema.TypeString, + Required: true, + }, + "key": { Type: schema.TypeString, Required: true, }, @@ -1035,18 +992,15 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.timestream", }, }, - "iot_events": { + "sns": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "input_name": { - Type: schema.TypeString, - Required: true, - }, - "message_id": { + "message_format": { Type: schema.TypeString, + Default: iot.MessageFormatRaw, Optional: true, }, "role_arn": { @@ -1054,6 +1008,11 @@ func ResourceTopicRule() *schema.Resource { Required: true, ValidateFunc: verify.ValidARN, }, + "target_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, ExactlyOneOf: []string{ @@ -1077,144 +1036,67 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.timestream", }, }, - "kafka": { + "sqs": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "acks": { - Type: schema.TypeString, - Optional: true, - Default: 1, - ValidateFunc: validation.StringInSlice([]string{ - "0", - "1", - }, false), - }, - "bootstrap_servers": { + "queue_url": { Type: schema.TypeString, Required: true, }, - "compression_type": { - Type: schema.TypeString, - Optional: true, - Default: "none", - ValidateFunc: validation.StringInSlice([]string{ - "none", - "gzip", - "snappy", - "lz4", - "zstd", - }, false), - }, - "destination_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "key": { - Type: schema.TypeString, - Optional: true, - }, - "key_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.StringSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.StringSerializer", - }, false), - }, - "partition": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_keytab": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_krb5_kdc": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_krb5_realm": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_principal": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_service_name": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_mechanism": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "PLAIN", - "GSSAPI", - "SCRAM-SHA-512", - }, false), - }, - "sasl_plain_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_plain_password": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_password": { - Type: schema.TypeString, - Optional: true, - }, - "security_protocol": { - Type: schema.TypeString, - Optional: true, - Default: "SSL", - ValidateFunc: validation.StringInSlice([]string{ - "SSL", - "SASL_SSL", - }, false), - }, - "ssl_key_password": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_keystore": { - Type: schema.TypeString, - Optional: true, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, }, - "ssl_keystore_password": { - Type: schema.TypeString, - Optional: true, + "use_base64": { + Type: schema.TypeBool, + Required: true, }, - "ssl_truststore": { + }, + }, + ExactlyOneOf: []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_logs", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kafka", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.step_functions", + "error_action.0.sns", + "error_action.0.sqs", + "error_action.0.timestream", + }, + }, + "step_functions": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "execution_name_prefix": { Type: schema.TypeString, Optional: true, }, - "ssl_truststore_password": { - Type: schema.TypeString, - Optional: true, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, }, - "topic": { + "state_machine_name": { Type: schema.TypeString, Required: true, }, - "value_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.ByteBufferSerializer", - }, false), - }, }, }, ExactlyOneOf: []string{ @@ -1238,25 +1120,53 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.timestream", }, }, - "kinesis": { + "timestream": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "partition_key": { + "database_name": { Type: schema.TypeString, - Optional: true, + Required: true, + }, + "dimension": { + Type: schema.TypeSet, + Required: true, + Elem: timestreamDimensionResource, }, "role_arn": { Type: schema.TypeString, Required: true, ValidateFunc: verify.ValidARN, }, - "stream_name": { + "table_name": { Type: schema.TypeString, Required: true, }, + "timestamp": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "SECONDS", + "MILLISECONDS", + "MICROSECONDS", + "NANOSECONDS", + }, false), + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, }, }, ExactlyOneOf: []string{ @@ -1280,323 +1190,413 @@ func ResourceTopicRule() *schema.Resource { "error_action.0.timestream", }, }, - "lambda": { - Type: schema.TypeList, + }, + }, + }, + "firehose": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "delivery_stream_name": { + Type: schema.TypeString, + Required: true, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "separator": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validTopicRuleFirehoseSeparator, + }, + }, + }, + }, + "iot_analytics": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "channel_name": { + Type: schema.TypeString, + Required: true, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + }, + }, + }, + "iot_events": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "input_name": { + Type: schema.TypeString, + Required: true, + }, + "message_id": { + Type: schema.TypeString, + Optional: true, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + }, + }, + }, + "kafka": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "acks": { + Type: schema.TypeString, + Optional: true, + Default: 1, + ValidateFunc: validation.StringInSlice([]string{ + "0", + "1", + }, false), + }, + "bootstrap_servers": { + Type: schema.TypeString, + Required: true, + }, + "compression_type": { + Type: schema.TypeString, + Optional: true, + Default: "none", + ValidateFunc: validation.StringInSlice([]string{ + "none", + "gzip", + "snappy", + "lz4", + "zstd", + }, false), + }, + "destination_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "key": { + Type: schema.TypeString, + Optional: true, + }, + "key_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.StringSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.StringSerializer", + }, false), + }, + "partition": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_keytab": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_krb5_kdc": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_krb5_realm": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_principal": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_kerberos_service_name": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_mechanism": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "PLAIN", + "GSSAPI", + "SCRAM-SHA-512", + }, false), + }, + "sasl_plain_username": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_plain_password": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_scram_username": { + Type: schema.TypeString, + Optional: true, + }, + "sasl_scram_password": { + Type: schema.TypeString, + Optional: true, + }, + "security_protocol": { + Type: schema.TypeString, + Optional: true, + Default: "SSL", + ValidateFunc: validation.StringInSlice([]string{ + "SSL", + "SASL_SSL", + }, false), + }, + "ssl_key_password": { + Type: schema.TypeString, Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "function_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - }, - }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, }, - "republish": { - Type: schema.TypeList, + "ssl_keystore": { + Type: schema.TypeString, Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "qos": { - Type: schema.TypeInt, - Optional: true, - Default: 0, - ValidateFunc: validation.IntBetween(0, 1), - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "topic": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, }, - "s3": { - Type: schema.TypeList, + "ssl_keystore_password": { + Type: schema.TypeString, Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "bucket_name": { - Type: schema.TypeString, - Required: true, - }, - "key": { - Type: schema.TypeString, - Required: true, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - }, - }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, }, - "step_functions": { - Type: schema.TypeList, + "ssl_truststore": { + Type: schema.TypeString, Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "execution_name_prefix": { - Type: schema.TypeString, - Optional: true, - }, - "state_machine_name": { - Type: schema.TypeString, - Required: true, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - }, - }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, }, - "sns": { - Type: schema.TypeList, + "ssl_truststore_password": { + Type: schema.TypeString, + Optional: true, + }, + "topic": { + Type: schema.TypeString, + Required: true, + }, + "value_serializer": { + Type: schema.TypeString, + Optional: true, + Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", + ValidateFunc: validation.StringInSlice([]string{ + "org.apache.kafka.common.serialization.ByteBufferSerializer", + }, false), + }, + }, + }, + }, + "kinesis": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "partition_key": { + Type: schema.TypeString, + Optional: true, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "stream_name": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "lambda": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "function_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validTopicRuleName, + }, + "republish": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "qos": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntBetween(0, 1), + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "topic": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "s3": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bucket_name": { + Type: schema.TypeString, + Required: true, + }, + "key": { + Type: schema.TypeString, + Required: true, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + }, + }, + }, + "sns": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "message_format": { + Type: schema.TypeString, Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "message_format": { - Type: schema.TypeString, - Default: iot.MessageFormatRaw, - Optional: true, - }, - "target_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - }, - }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + Default: iot.MessageFormatRaw, }, - "sqs": { - Type: schema.TypeList, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "target_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + }, + }, + }, + "sql": { + Type: schema.TypeString, + Required: true, + }, + "sql_version": { + Type: schema.TypeString, + Required: true, + }, + "sqs": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "queue_url": { + Type: schema.TypeString, + Required: true, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "use_base64": { + Type: schema.TypeBool, + Required: true, + }, + }, + }, + }, + "step_functions": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "execution_name_prefix": { + Type: schema.TypeString, Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "queue_url": { - Type: schema.TypeString, - Required: true, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "use_base64": { - Type: schema.TypeBool, - Required: true, - }, - }, - }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, }, - "timestream": { + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "state_machine_name": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "tags": tftags.TagsSchema(), + "tags_all": tftags.TagsSchemaComputed(), + "timestream": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "database_name": { + Type: schema.TypeString, + Required: true, + }, + "dimension": { + Type: schema.TypeSet, + Required: true, + Elem: timestreamDimensionResource, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "table_name": { + Type: schema.TypeString, + Required: true, + }, + "timestamp": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "database_name": { + "unit": { Type: schema.TypeString, Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "SECONDS", + "MILLISECONDS", + "MICROSECONDS", + "NANOSECONDS", + }, false), }, - "dimension": { - Type: schema.TypeSet, - Required: true, - Elem: timestreamDimensionResource, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "table_name": { + "value": { Type: schema.TypeString, Required: true, }, - "timestamp": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - "SECONDS", - "MILLISECONDS", - "MICROSECONDS", - "NANOSECONDS", - }, false), - }, - "value": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, }, }, }, From 25d6423602f62501ebd643b746b1954dc17ca53e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 14:20:39 -0400 Subject: [PATCH 37/87] r/aws_iot_topic_rule: Add and use 'topicRuleErrorActionExactlyOneOf'. --- internal/service/iot/topic_rule.go | 399 +++-------------------------- 1 file changed, 39 insertions(+), 360 deletions(-) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index 74cb95329b7..b2982fa8ddc 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -259,26 +259,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "cloudwatch_logs": { Type: schema.TypeList, @@ -297,26 +278,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "cloudwatch_metric": { Type: schema.TypeList, @@ -352,26 +314,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "dynamodb": { Type: schema.TypeList, @@ -427,26 +370,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "dynamodbv2": { Type: schema.TypeList, @@ -474,26 +398,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "elasticsearch": { Type: schema.TypeList, @@ -525,26 +430,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "firehose": { Type: schema.TypeList, @@ -568,26 +454,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "iot_analytics": { Type: schema.TypeList, @@ -606,26 +473,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "iot_events": { Type: schema.TypeList, @@ -648,26 +496,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "kafka": { Type: schema.TypeList, @@ -809,26 +638,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "kinesis": { Type: schema.TypeList, @@ -851,26 +661,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "lambda": { Type: schema.TypeList, @@ -885,26 +676,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "republish": { Type: schema.TypeList, @@ -929,26 +701,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "s3": { Type: schema.TypeList, @@ -971,26 +724,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "sns": { Type: schema.TypeList, @@ -1015,26 +749,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "sqs": { Type: schema.TypeList, @@ -1057,26 +772,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "step_functions": { Type: schema.TypeList, @@ -1099,26 +795,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, "timestream": { Type: schema.TypeList, @@ -1169,26 +846,7 @@ func ResourceTopicRule() *schema.Resource { }, }, }, - ExactlyOneOf: []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.step_functions", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.timestream", - }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, }, }, @@ -1607,6 +1265,27 @@ func ResourceTopicRule() *schema.Resource { } } +var topicRuleErrorActionExactlyOneOf = []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_logs", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kafka", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.sns", + "error_action.0.sqs", + "error_action.0.step_functions", + "error_action.0.timestream", +} + var timestreamDimensionResource *schema.Resource = &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { From 4115831e9bc85ca7fd33457e48bed21a0253b5a1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 14:27:49 -0400 Subject: [PATCH 38/87] More consistent order of expanders. --- internal/service/iot/topic_rule.go | 242 ++++++++++++++--------------- 1 file changed, 121 insertions(+), 121 deletions(-) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index b2982fa8ddc..154d4c0f0ba 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -1791,6 +1791,126 @@ func expandIotIotEventsAction(tfList []interface{}) *iot.IotEventsAction { return apiObject } +func expandIotKafkaAction(tfList []interface{}) *iot.KafkaAction { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + apiObject := &iot.KafkaAction{} + tfMap := tfList[0].(map[string]interface{}) + clientProperties := make(map[string]*string) + + if v, ok := tfMap["acks"].(string); ok && v != "" { + clientProperties["acks"] = aws.String(v) + } + + if v, ok := tfMap["bootstrap_servers"].(string); ok && v != "" { + clientProperties["bootstrap.servers"] = aws.String(v) + } + + if v, ok := tfMap["compression_type"].(string); ok && v != "" { + clientProperties["compression.type"] = aws.String(v) + } + + if v, ok := tfMap["destination_arn"].(string); ok && v != "" { + apiObject.DestinationArn = aws.String(v) + } + + if v, ok := tfMap["key"].(string); ok && v != "" { + apiObject.Key = aws.String(v) + } + + if v, ok := tfMap["key_serializer"].(string); ok && v != "" { + clientProperties["key.serializer"] = aws.String(v) + } + + if v, ok := tfMap["partition"].(string); ok && v != "" { + apiObject.Partition = aws.String(v) + } + + if sp, ok := tfMap["security_protocol"].(string); ok && sp != "" { + clientProperties["security.protocol"] = aws.String(sp) + + switch sp { + case "SSL": + if v, ok := tfMap["ssl_keystore"].(string); ok && v != "" { + clientProperties["ssl.keystore"] = aws.String(v) + } + + if v, ok := tfMap["ssl_keystore_password"].(string); ok && v != "" { + clientProperties["ssl.keystore.password"] = aws.String(v) + } + + if v, ok := tfMap["ssl_key_password"].(string); ok && v != "" { + clientProperties["ssl.key.password"] = aws.String(v) + } + case "SASL": + if mechanism, ok := tfMap["sasl_mechanism"].(string); ok && mechanism != "" { + clientProperties["sasl.mechanism"] = aws.String(mechanism) + + switch mechanism { + case "PLAIN": + if v, ok := tfMap["sasl_plain_username"].(string); ok && v != "" { + clientProperties["sasl.plain.username"] = aws.String(v) + } + + if v, ok := tfMap["sasl_plain_password"].(string); ok && v != "" { + clientProperties["sasl.plain.password"] = aws.String(v) + } + case "SCRAM-SHA-512": + if v, ok := tfMap["sasl_scram_username"].(string); ok && v != "" { + clientProperties["sasl.scram.username"] = aws.String(v) + } + + if v, ok := tfMap["sasl_scram_password"].(string); ok && v != "" { + clientProperties["sasl.scram.password"] = aws.String(v) + } + case "GSSAPI": + if v, ok := tfMap["sasl_kerberos_keytab"].(string); ok && v != "" { + clientProperties["sasl.kerberos.keytab"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_krb5_kdc"].(string); ok && v != "" { + clientProperties["sasl.kerberos.krb5.kdc"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_krb5_realm"].(string); ok && v != "" { + clientProperties["sasl.kerberos.krb5.realm"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_principal"].(string); ok && v != "" { + clientProperties["sasl.kerberos.principal"] = aws.String(v) + } + + if v, ok := tfMap["sasl_kerberos_service_name"].(string); ok && v != "" { + clientProperties["sasl.kerberos.service.name"] = aws.String(v) + } + } + } + } + } + + if v, ok := tfMap["ssl_truststore"].(string); ok && v != "" { + clientProperties["ssl.truststore"] = aws.String(v) + } + + if v, ok := tfMap["ssl_truststore_password"].(string); ok && v != "" { + clientProperties["ssl.truststore.password"] = aws.String(v) + } + + if v, ok := tfMap["topic"].(string); ok && v != "" { + apiObject.Topic = aws.String(v) + } + + if v, ok := tfMap["value_serializer"].(string); ok && v != "" { + clientProperties["value.serializer"] = aws.String(v) + } + + apiObject.ClientProperties = clientProperties + + return apiObject +} + func expandIotKinesisAction(tfList []interface{}) *iot.KinesisAction { if len(tfList) == 0 || tfList[0] == nil { return nil @@ -1944,126 +2064,6 @@ func expandIotStepFunctionsAction(tfList []interface{}) *iot.StepFunctionsAction return apiObject } -func expandIotKafkaAction(tfList []interface{}) *iot.KafkaAction { - if len(tfList) == 0 || tfList[0] == nil { - return nil - } - - apiObject := &iot.KafkaAction{} - tfMap := tfList[0].(map[string]interface{}) - clientProperties := make(map[string]*string) - - if v, ok := tfMap["acks"].(string); ok && v != "" { - clientProperties["acks"] = aws.String(v) - } - - if v, ok := tfMap["bootstrap_servers"].(string); ok && v != "" { - clientProperties["bootstrap.servers"] = aws.String(v) - } - - if v, ok := tfMap["compression_type"].(string); ok && v != "" { - clientProperties["compression.type"] = aws.String(v) - } - - if v, ok := tfMap["destination_arn"].(string); ok && v != "" { - apiObject.DestinationArn = aws.String(v) - } - - if v, ok := tfMap["key"].(string); ok && v != "" { - apiObject.Key = aws.String(v) - } - - if v, ok := tfMap["key_serializer"].(string); ok && v != "" { - clientProperties["key.serializer"] = aws.String(v) - } - - if v, ok := tfMap["partition"].(string); ok && v != "" { - apiObject.Partition = aws.String(v) - } - - if sp, ok := tfMap["security_protocol"].(string); ok && sp != "" { - clientProperties["security.protocol"] = aws.String(sp) - - switch sp { - case "SSL": - if v, ok := tfMap["ssl_keystore"].(string); ok && v != "" { - clientProperties["ssl.keystore"] = aws.String(v) - } - - if v, ok := tfMap["ssl_keystore_password"].(string); ok && v != "" { - clientProperties["ssl.keystore.password"] = aws.String(v) - } - - if v, ok := tfMap["ssl_key_password"].(string); ok && v != "" { - clientProperties["ssl.key.password"] = aws.String(v) - } - case "SASL": - if mechanism, ok := tfMap["sasl_mechanism"].(string); ok && mechanism != "" { - clientProperties["sasl.mechanism"] = aws.String(mechanism) - - switch mechanism { - case "PLAIN": - if v, ok := tfMap["sasl_plain_username"].(string); ok && v != "" { - clientProperties["sasl.plain.username"] = aws.String(v) - } - - if v, ok := tfMap["sasl_plain_password"].(string); ok && v != "" { - clientProperties["sasl.plain.password"] = aws.String(v) - } - case "SCRAM-SHA-512": - if v, ok := tfMap["sasl_scram_username"].(string); ok && v != "" { - clientProperties["sasl.scram.username"] = aws.String(v) - } - - if v, ok := tfMap["sasl_scram_password"].(string); ok && v != "" { - clientProperties["sasl.scram.password"] = aws.String(v) - } - case "GSSAPI": - if v, ok := tfMap["sasl_kerberos_keytab"].(string); ok && v != "" { - clientProperties["sasl.kerberos.keytab"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_krb5_kdc"].(string); ok && v != "" { - clientProperties["sasl.kerberos.krb5.kdc"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_krb5_realm"].(string); ok && v != "" { - clientProperties["sasl.kerberos.krb5.realm"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_principal"].(string); ok && v != "" { - clientProperties["sasl.kerberos.principal"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_service_name"].(string); ok && v != "" { - clientProperties["sasl.kerberos.service.name"] = aws.String(v) - } - } - } - } - } - - if v, ok := tfMap["ssl_truststore"].(string); ok && v != "" { - clientProperties["ssl.truststore"] = aws.String(v) - } - - if v, ok := tfMap["ssl_truststore_password"].(string); ok && v != "" { - clientProperties["ssl.truststore.password"] = aws.String(v) - } - - if v, ok := tfMap["topic"].(string); ok && v != "" { - apiObject.Topic = aws.String(v) - } - - if v, ok := tfMap["value_serializer"].(string); ok && v != "" { - clientProperties["value.serializer"] = aws.String(v) - } - - apiObject.ClientProperties = clientProperties - - return apiObject -} - func expandIotTimestreamAction(tfList []interface{}) *iot.TimestreamAction { if len(tfList) == 0 || tfList[0] == nil { return nil @@ -2539,9 +2539,9 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { Actions: actions, AwsIotSqlVersion: aws.String(d.Get("sql_version").(string)), Description: aws.String(d.Get("description").(string)), + ErrorAction: iotErrorAction, RuleDisabled: aws.Bool(!d.Get("enabled").(bool)), Sql: aws.String(d.Get("sql").(string)), - ErrorAction: iotErrorAction, } } From c7b1a81ee59e8a5b8b8a4d6dab1127c4764aa4fd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 14:31:42 -0400 Subject: [PATCH 39/87] More consistent order of flatteners. --- internal/service/iot/topic_rule.go | 409 +++++++++++++++-------------- 1 file changed, 205 insertions(+), 204 deletions(-) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index 154d4c0f0ba..c9f42e7fa56 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -1366,23 +1366,6 @@ func resourceTopicRuleRead(d *schema.ResourceData, meta interface{}) error { d.Set("sql", out.Rule.Sql) d.Set("sql_version", out.Rule.AwsIotSqlVersion) - tags, err := ListTags(conn, aws.StringValue(out.RuleArn)) - - if err != nil { - return fmt.Errorf("error listing tags for IoT Topic Rule (%s): %w", aws.StringValue(out.RuleArn), err) - } - - tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) - - //lintignore:AWSR002 - if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %w", err) - } - - if err := d.Set("tags_all", tags.Map()); err != nil { - return fmt.Errorf("error setting tags_all: %w", err) - } - if err := d.Set("cloudwatch_alarm", flattenIotCloudWatchAlarmActions(out.Rule.Actions)); err != nil { return fmt.Errorf("error setting cloudwatch_alarm: %w", err) } @@ -1419,6 +1402,10 @@ func resourceTopicRuleRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error setting iot_events: %w", err) } + if err := d.Set("kafka", flattenIotKafkaActions(out.Rule.Actions)); err != nil { + return fmt.Errorf("error setting kafka: %w", err) + } + if err := d.Set("kinesis", flattenIotKinesisActions(out.Rule.Actions)); err != nil { return fmt.Errorf("error setting kinesis: %w", err) } @@ -1447,10 +1434,6 @@ func resourceTopicRuleRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error setting step_functions: %w", err) } - if err := d.Set("kafka", flattenIotKafkaActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting kafka: %w", err) - } - if err := d.Set("timestream", flattenIotTimestreamActions(out.Rule.Actions)); err != nil { return fmt.Errorf("error setting timestream: %w", err) } @@ -1459,6 +1442,23 @@ func resourceTopicRuleRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error setting error_action: %w", err) } + tags, err := ListTags(conn, aws.StringValue(out.RuleArn)) + + if err != nil { + return fmt.Errorf("error listing tags for IoT Topic Rule (%s): %w", aws.StringValue(out.RuleArn), err) + } + + tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) + + //lintignore:AWSR002 + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + + if err := d.Set("tags_all", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) + } + return nil } @@ -2936,6 +2936,143 @@ func flattenIotIotEventsAction(apiObject *iot.IotEventsAction) []interface{} { return []interface{}{tfMap} } +// Legacy root attribute handling +func flattenIotKafkaActions(actions []*iot.Action) []interface{} { + results := make([]interface{}, 0) + + for _, action := range actions { + if action == nil { + continue + } + + if v := action.Kafka; v != nil { + results = append(results, flattenIotKafkaAction(v)...) + } + } + + return results +} + +func flattenIotKafkaAction(apiObject *iot.KafkaAction) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := make(map[string]interface{}) + + if v := apiObject.DestinationArn; v != nil { + tfMap["destination_arn"] = aws.StringValue(v) + } + + if v := apiObject.Key; v != nil { + tfMap["key"] = aws.StringValue(v) + } + + if v := apiObject.Partition; v != nil { + tfMap["partition"] = aws.StringValue(v) + } + + if v := apiObject.Topic; v != nil { + tfMap["topic"] = aws.StringValue(v) + } + + if cp := apiObject.ClientProperties; cp != nil { + if v, ok := cp["acks"]; ok && v != nil { + tfMap["acks"] = aws.StringValue(v) + } + + if v, ok := cp["bootstrap.servers"]; ok && v != nil { + tfMap["bootstrap_servers"] = aws.StringValue(v) + } + + if v, ok := cp["compression.type"]; ok && v != nil { + tfMap["compression_type"] = aws.StringValue(v) + } + + if v, ok := cp["key.serializer"]; ok && v != nil { + tfMap["key_serializer"] = aws.StringValue(v) + } + + if v, ok := cp["value.serializer"]; ok && v != nil { + tfMap["value_serializer"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.truststore"]; ok && v != nil { + tfMap["ssl_truststore"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.truststore.password"]; ok && v != nil { + tfMap["ssl_truststore_password"] = aws.StringValue(v) + } + + if sp, ok := cp["security.protocol"]; ok && sp != nil { + protocol := aws.StringValue(sp) + tfMap["security_protocol"] = protocol + + switch protocol { + case "SSL": + if v, ok := cp["ssl.keystore"]; ok && v != nil { + tfMap["ssl_keystore"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.keystore.password"]; ok && v != nil { + tfMap["ssl_keystore_password"] = aws.StringValue(v) + } + + if v, ok := cp["ssl.key.password"]; ok && v != nil { + tfMap["ssl_key_password"] = aws.StringValue(v) + } + case "SASL": + if m, ok := cp["sasl.mechanism"]; ok && m != nil { + mechanism := aws.StringValue(m) + tfMap["sasl_mechanism"] = mechanism + + switch mechanism { + case "PLAIN": + if v, ok := cp["sasl.plain.username"]; ok && v != nil { + tfMap["sasl_plain_username"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.plain.password"]; ok && v != nil { + tfMap["sasl_plain_password"] = aws.StringValue(v) + } + case "SCRAM-SHA-512": + if v, ok := cp["sasl.scram.username"]; ok && v != nil { + tfMap["sasl_scram_username"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.scram.password"]; ok && v != nil { + tfMap["sasl_scram_password"] = aws.StringValue(v) + } + case "GSSAPI": + if v, ok := cp["sasl.kerberos.keytab"]; ok && v != nil { + tfMap["sasl_kerberos_keytab"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.krb5.kdc"]; ok && v != nil { + tfMap["sasl_kerberos_krb5_kdc"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.krb5.realm"]; ok && v != nil { + tfMap["sasl_kerberos_krb5_realm"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.principal"]; ok && v != nil { + tfMap["sasl_kerberos_principal"] = aws.StringValue(v) + } + + if v, ok := cp["sasl.kerberos.service.name"]; ok && v != nil { + tfMap["sasl_kerberos_service_name"] = aws.StringValue(v) + } + } + } + } + } + } + + return []interface{}{tfMap} +} + // Legacy root attribute handling func flattenIotKinesisActions(actions []*iot.Action) []interface{} { results := make([]interface{}, 0) @@ -3215,7 +3352,8 @@ func flattenIotStepFunctionsAction(apiObject *iot.StepFunctionsAction) []interfa return []interface{}{tfMap} } -func flattenIotKafkaActions(actions []*iot.Action) []interface{} { +// Legacy root attribute handling +func flattenIotTimestreamActions(actions []*iot.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { @@ -3223,129 +3361,83 @@ func flattenIotKafkaActions(actions []*iot.Action) []interface{} { continue } - if v := action.Kafka; v != nil { - results = append(results, flattenIotKafkaAction(v)...) + if v := action.Timestream; v != nil { + results = append(results, flattenIotTimestreamAction(v)...) } } return results } -func flattenIotKafkaAction(apiObject *iot.KafkaAction) []interface{} { +func flattenIotTimestreamAction(apiObject *iot.TimestreamAction) []interface{} { if apiObject == nil { return nil } tfMap := make(map[string]interface{}) - if v := apiObject.DestinationArn; v != nil { - tfMap["destination_arn"] = aws.StringValue(v) + if v := apiObject.DatabaseName; v != nil { + tfMap["database_name"] = aws.StringValue(v) } - if v := apiObject.Key; v != nil { - tfMap["key"] = aws.StringValue(v) + if v := apiObject.Dimensions; v != nil { + tfMap["dimension"] = flattenIotTimestreamDimensions(v) } - if v := apiObject.Partition; v != nil { - tfMap["partition"] = aws.StringValue(v) + if v := apiObject.RoleArn; v != nil { + tfMap["role_arn"] = aws.StringValue(v) } - if v := apiObject.Topic; v != nil { - tfMap["topic"] = aws.StringValue(v) + if v := apiObject.TableName; v != nil { + tfMap["table_name"] = aws.StringValue(v) } - if cp := apiObject.ClientProperties; cp != nil { - if v, ok := cp["acks"]; ok && v != nil { - tfMap["acks"] = aws.StringValue(v) - } - - if v, ok := cp["bootstrap.servers"]; ok && v != nil { - tfMap["bootstrap_servers"] = aws.StringValue(v) - } - - if v, ok := cp["compression.type"]; ok && v != nil { - tfMap["compression_type"] = aws.StringValue(v) - } - - if v, ok := cp["key.serializer"]; ok && v != nil { - tfMap["key_serializer"] = aws.StringValue(v) - } - - if v, ok := cp["value.serializer"]; ok && v != nil { - tfMap["value_serializer"] = aws.StringValue(v) - } - - if v, ok := cp["ssl.truststore"]; ok && v != nil { - tfMap["ssl_truststore"] = aws.StringValue(v) - } + if v := apiObject.Timestamp; v != nil { + tfMap["timestamp"] = flattenIotTimestreamTimestamp(v) + } - if v, ok := cp["ssl.truststore.password"]; ok && v != nil { - tfMap["ssl_truststore_password"] = aws.StringValue(v) - } + return []interface{}{tfMap} +} - if sp, ok := cp["security.protocol"]; ok && sp != nil { - protocol := aws.StringValue(sp) - tfMap["security_protocol"] = protocol +func flattenIotTimestreamDimensions(apiObjects []*iot.TimestreamDimension) *schema.Set { + if apiObjects == nil { + return nil + } - switch protocol { - case "SSL": - if v, ok := cp["ssl.keystore"]; ok && v != nil { - tfMap["ssl_keystore"] = aws.StringValue(v) - } + tfSet := schema.NewSet(schema.HashResource(timestreamDimensionResource), []interface{}{}) - if v, ok := cp["ssl.keystore.password"]; ok && v != nil { - tfMap["ssl_keystore_password"] = aws.StringValue(v) - } + for _, apiObject := range apiObjects { + if apiObject != nil { + tfMap := make(map[string]interface{}) - if v, ok := cp["ssl.key.password"]; ok && v != nil { - tfMap["ssl_key_password"] = aws.StringValue(v) - } - case "SASL": - if m, ok := cp["sasl.mechanism"]; ok && m != nil { - mechanism := aws.StringValue(m) - tfMap["sasl_mechanism"] = mechanism + if v := apiObject.Name; v != nil { + tfMap["name"] = aws.StringValue(v) + } - switch mechanism { - case "PLAIN": - if v, ok := cp["sasl.plain.username"]; ok && v != nil { - tfMap["sasl_plain_username"] = aws.StringValue(v) - } + if v := apiObject.Value; v != nil { + tfMap["value"] = aws.StringValue(v) + } - if v, ok := cp["sasl.plain.password"]; ok && v != nil { - tfMap["sasl_plain_password"] = aws.StringValue(v) - } - case "SCRAM-SHA-512": - if v, ok := cp["sasl.scram.username"]; ok && v != nil { - tfMap["sasl_scram_username"] = aws.StringValue(v) - } + tfSet.Add(tfMap) + } + } - if v, ok := cp["sasl.scram.password"]; ok && v != nil { - tfMap["sasl_scram_password"] = aws.StringValue(v) - } - case "GSSAPI": - if v, ok := cp["sasl.kerberos.keytab"]; ok && v != nil { - tfMap["sasl_kerberos_keytab"] = aws.StringValue(v) - } + return tfSet +} - if v, ok := cp["sasl.kerberos.krb5.kdc"]; ok && v != nil { - tfMap["sasl_kerberos_krb5_kdc"] = aws.StringValue(v) - } +func flattenIotTimestreamTimestamp(apiObject *iot.TimestreamTimestamp) []interface{} { + if apiObject == nil { + return nil + } - if v, ok := cp["sasl.kerberos.krb5.realm"]; ok && v != nil { - tfMap["sasl_kerberos_krb5_realm"] = aws.StringValue(v) - } + tfMap := make(map[string]interface{}) - if v, ok := cp["sasl.kerberos.principal"]; ok && v != nil { - tfMap["sasl_kerberos_principal"] = aws.StringValue(v) - } + if v := apiObject.Unit; v != nil { + tfMap["unit"] = aws.StringValue(v) + } - if v, ok := cp["sasl.kerberos.service.name"]; ok && v != nil { - tfMap["sasl_kerberos_service_name"] = aws.StringValue(v) - } - } - } - } - } + if v := apiObject.Value; v != nil { + tfMap["value"] = aws.StringValue(v) } return []interface{}{tfMap} @@ -3433,94 +3525,3 @@ func flattenIotErrorAction(errorAction *iot.Action) []map[string]interface{} { return results } - -// Legacy root attribute handling -func flattenIotTimestreamActions(actions []*iot.Action) []interface{} { - results := make([]interface{}, 0) - - for _, action := range actions { - if action == nil { - continue - } - - if v := action.Timestream; v != nil { - results = append(results, flattenIotTimestreamAction(v)...) - } - } - - return results -} - -func flattenIotTimestreamAction(apiObject *iot.TimestreamAction) []interface{} { - if apiObject == nil { - return nil - } - - tfMap := make(map[string]interface{}) - - if v := apiObject.DatabaseName; v != nil { - tfMap["database_name"] = aws.StringValue(v) - } - - if v := apiObject.Dimensions; v != nil { - tfMap["dimension"] = flattenIotTimestreamDimensions(v) - } - - if v := apiObject.RoleArn; v != nil { - tfMap["role_arn"] = aws.StringValue(v) - } - - if v := apiObject.TableName; v != nil { - tfMap["table_name"] = aws.StringValue(v) - } - - if v := apiObject.Timestamp; v != nil { - tfMap["timestamp"] = flattenIotTimestreamTimestamp(v) - } - - return []interface{}{tfMap} -} - -func flattenIotTimestreamDimensions(apiObjects []*iot.TimestreamDimension) *schema.Set { - if apiObjects == nil { - return nil - } - - tfSet := schema.NewSet(schema.HashResource(timestreamDimensionResource), []interface{}{}) - - for _, apiObject := range apiObjects { - if apiObject != nil { - tfMap := make(map[string]interface{}) - - if v := apiObject.Name; v != nil { - tfMap["name"] = aws.StringValue(v) - } - - if v := apiObject.Value; v != nil { - tfMap["value"] = aws.StringValue(v) - } - - tfSet.Add(tfMap) - } - } - - return tfSet -} - -func flattenIotTimestreamTimestamp(apiObject *iot.TimestreamTimestamp) []interface{} { - if apiObject == nil { - return nil - } - - tfMap := make(map[string]interface{}) - - if v := apiObject.Unit; v != nil { - tfMap["unit"] = aws.StringValue(v) - } - - if v := apiObject.Value; v != nil { - tfMap["value"] = aws.StringValue(v) - } - - return []interface{}{tfMap} -} From e134af24fb8afdbab7e0ec885e0dbed42bd75229 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 14:41:19 -0400 Subject: [PATCH 40/87] More consistent order of acceptance tests. --- internal/service/iot/topic_rule_test.go | 348 ++++++++++++------------ 1 file changed, 174 insertions(+), 174 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index bd2409ac704..15be50c1617 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -44,6 +44,50 @@ func TestAccIoTTopicRule_basic(t *testing.T) { }) } +func TestAccIoTTopicRule_tags(t *testing.T) { + rName := sdkacctest.RandString(5) + resourceName := "aws_iot_topic_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, iot.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckTopicRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTopicRuleTags1(rName, "key1", "user@example"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "user@example"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccTopicRuleTags2(rName, "key1", "user@example", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "user@example"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccTopicRuleTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + func TestAccIoTTopicRule_cloudWatchAlarm(t *testing.T) { rName := sdkacctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" @@ -250,9 +294,8 @@ func TestAccIoTTopicRule_Firehose_separator(t *testing.T) { }) } -func TestAccIoTTopicRule_kinesis(t *testing.T) { +func TestAccIoTTopicRule_IoT_analytics(t *testing.T) { rName := sdkacctest.RandString(5) - resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -261,23 +304,17 @@ func TestAccIoTTopicRule_kinesis(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_kinesis(rName), + Config: testAccTopicRule_iot_analytics(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, }, }) } -func TestAccIoTTopicRule_lambda(t *testing.T) { +func TestAccIoTTopicRule_IoT_events(t *testing.T) { rName := sdkacctest.RandString(5) - resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -286,24 +323,18 @@ func TestAccIoTTopicRule_lambda(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_lambda(rName), + Config: testAccTopicRule_iot_events(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, }, }) } -func TestAccIoTTopicRule_republish(t *testing.T) { +func TestAccIoTTopicRule_kafka(t *testing.T) { rName := sdkacctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, iot.EndpointsID), @@ -311,7 +342,7 @@ func TestAccIoTTopicRule_republish(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_republish(rName), + Config: testAccTopicRule_kafka(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -325,7 +356,7 @@ func TestAccIoTTopicRule_republish(t *testing.T) { }) } -func TestAccIoTTopicRule_republishWithQos(t *testing.T) { +func TestAccIoTTopicRule_kinesis(t *testing.T) { rName := sdkacctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" @@ -336,7 +367,7 @@ func TestAccIoTTopicRule_republishWithQos(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_republish_with_qos(rName), + Config: testAccTopicRule_kinesis(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -350,7 +381,7 @@ func TestAccIoTTopicRule_republishWithQos(t *testing.T) { }) } -func TestAccIoTTopicRule_s3(t *testing.T) { +func TestAccIoTTopicRule_lambda(t *testing.T) { rName := sdkacctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" @@ -361,7 +392,7 @@ func TestAccIoTTopicRule_s3(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_s3(rName), + Config: testAccTopicRule_lambda(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -375,7 +406,7 @@ func TestAccIoTTopicRule_s3(t *testing.T) { }) } -func TestAccIoTTopicRule_sns(t *testing.T) { +func TestAccIoTTopicRule_republish(t *testing.T) { rName := sdkacctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" @@ -386,7 +417,7 @@ func TestAccIoTTopicRule_sns(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_sns(rName), + Config: testAccTopicRule_republish(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -400,7 +431,7 @@ func TestAccIoTTopicRule_sns(t *testing.T) { }) } -func TestAccIoTTopicRule_sqs(t *testing.T) { +func TestAccIoTTopicRule_republishWithQos(t *testing.T) { rName := sdkacctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" @@ -411,7 +442,7 @@ func TestAccIoTTopicRule_sqs(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_sqs(rName), + Config: testAccTopicRule_republish_with_qos(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -425,7 +456,7 @@ func TestAccIoTTopicRule_sqs(t *testing.T) { }) } -func TestAccIoTTopicRule_Step_functions(t *testing.T) { +func TestAccIoTTopicRule_s3(t *testing.T) { rName := sdkacctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" @@ -436,7 +467,7 @@ func TestAccIoTTopicRule_Step_functions(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_step_functions(rName), + Config: testAccTopicRule_s3(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -450,7 +481,7 @@ func TestAccIoTTopicRule_Step_functions(t *testing.T) { }) } -func TestAccIoTTopicRule_Timestream(t *testing.T) { +func TestAccIoTTopicRule_sns(t *testing.T) { rName := sdkacctest.RandString(5) resourceName := "aws_iot_topic_rule.rule" @@ -461,7 +492,7 @@ func TestAccIoTTopicRule_Timestream(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_timestream(rName), + Config: testAccTopicRule_sns(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -475,8 +506,9 @@ func TestAccIoTTopicRule_Timestream(t *testing.T) { }) } -func TestAccIoTTopicRule_IoT_analytics(t *testing.T) { +func TestAccIoTTopicRule_sqs(t *testing.T) { rName := sdkacctest.RandString(5) + resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -485,17 +517,23 @@ func TestAccIoTTopicRule_IoT_analytics(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_iot_analytics(rName), + Config: testAccTopicRule_sqs(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } -func TestAccIoTTopicRule_IoT_events(t *testing.T) { +func TestAccIoTTopicRule_Step_functions(t *testing.T) { rName := sdkacctest.RandString(5) + resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -504,18 +542,23 @@ func TestAccIoTTopicRule_IoT_events(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_iot_events(rName), + Config: testAccTopicRule_step_functions(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } -func TestAccIoTTopicRule_tags(t *testing.T) { +func TestAccIoTTopicRule_Timestream(t *testing.T) { rName := sdkacctest.RandString(5) - resourceName := "aws_iot_topic_rule.test" + resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -524,11 +567,9 @@ func TestAccIoTTopicRule_tags(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRuleTags1(rName, "key1", "user@example"), + Config: testAccTopicRule_timestream(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "user@example"), + testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), }, { @@ -536,23 +577,6 @@ func TestAccIoTTopicRule_tags(t *testing.T) { ImportState: true, ImportStateVerify: true, }, - { - Config: testAccTopicRuleTags2(rName, "key1", "user@example", "key2", "value2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "user@example"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), - ), - }, - { - Config: testAccTopicRuleTags1(rName, "key2", "value2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), - ), - }, }, }) } @@ -617,30 +641,6 @@ func TestAccIoTTopicRule_updateKinesisErrorAction(t *testing.T) { }) } -func TestAccIoTTopicRule_kafka(t *testing.T) { - rName := sdkacctest.RandString(5) - resourceName := "aws_iot_topic_rule.rule" - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, iot.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckTopicRuleDestroy, - Steps: []resource.TestStep{ - { - Config: testAccTopicRule_kafka(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - func testAccCheckTopicRuleDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn @@ -758,6 +758,37 @@ resource "aws_iot_topic_rule" "rule" { `, rName) } +func testAccTopicRuleTags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_iot_topic_rule" "test" { + name = "test_rule_%[1]s" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccTopicRuleTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_iot_topic_rule" "test" { + name = "test_rule_%[1]s" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} + func testAccTopicRule_cloudWatchalarm(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRole(rName), @@ -820,28 +851,6 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_dynamoDBv2(rName string) string { - return acctest.ConfigCompose( - testAccTopicRuleRole(rName), - fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" - enabled = true - sql = "SELECT field as column_name FROM 'topic/test'" - sql_version = "2015-10-08" - - dynamodbv2 { - put_item { - table_name = "test" - } - - role_arn = aws_iam_role.iot_role.arn - } -} -`, rName)) -} - func testAccTopicRule_dynamoDB(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRole(rName), @@ -890,6 +899,28 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } +func testAccTopicRule_dynamoDBv2(rName string) string { + return acctest.ConfigCompose( + testAccTopicRuleRole(rName), + fmt.Sprintf(` +resource "aws_iot_topic_rule" "rule" { + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT field as column_name FROM 'topic/test'" + sql_version = "2015-10-08" + + dynamodbv2 { + put_item { + table_name = "test" + } + + role_arn = aws_iam_role.iot_role.arn + } +} +`, rName)) +} + func testAccTopicRule_elasticSearch(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRole(rName), @@ -953,6 +984,45 @@ resource "aws_iot_topic_rule" "rule" { `, rName, separator)) } +func testAccTopicRule_iot_analytics(rName string) string { + return acctest.ConfigCompose( + testAccTopicRuleRole(rName), + fmt.Sprintf(` +resource "aws_iot_topic_rule" "rule" { + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + iot_analytics { + channel_name = "fakedata" + role_arn = aws_iam_role.iot_role.arn + } +} +`, rName)) +} + +func testAccTopicRule_iot_events(rName string) string { + return acctest.ConfigCompose( + testAccTopicRuleRole(rName), + fmt.Sprintf(` +resource "aws_iot_topic_rule" "rule" { + name = "test_rule_%[1]s" + description = "Example rule" + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + iot_events { + input_name = "fake_input_name" + role_arn = aws_iam_role.iot_role.arn + message_id = "fake_message_id" + } +} +`, rName)) +} + func testAccTopicRule_kafka(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRole(rName), @@ -1163,76 +1233,6 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_iot_analytics(rName string) string { - return acctest.ConfigCompose( - testAccTopicRuleRole(rName), - fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" - enabled = true - sql = "SELECT * FROM 'topic/test'" - sql_version = "2015-10-08" - - iot_analytics { - channel_name = "fakedata" - role_arn = aws_iam_role.iot_role.arn - } -} -`, rName)) -} - -func testAccTopicRule_iot_events(rName string) string { - return acctest.ConfigCompose( - testAccTopicRuleRole(rName), - fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" - enabled = true - sql = "SELECT * FROM 'topic/test'" - sql_version = "2015-10-08" - - iot_events { - input_name = "fake_input_name" - role_arn = aws_iam_role.iot_role.arn - message_id = "fake_message_id" - } -} -`, rName)) -} - -func testAccTopicRuleTags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -resource "aws_iot_topic_rule" "test" { - name = "test_rule_%[1]s" - enabled = true - sql = "SELECT * FROM 'topic/test'" - sql_version = "2015-10-08" - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1) -} - -func testAccTopicRuleTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return fmt.Sprintf(` -resource "aws_iot_topic_rule" "test" { - name = "test_rule_%[1]s" - enabled = true - sql = "SELECT * FROM 'topic/test'" - sql_version = "2015-10-08" - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) -} - func testAccTopicRule_errorAction(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRole(rName), From fd50f263a4325bbff79a320fb55c25e593892b1a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 15:29:28 -0400 Subject: [PATCH 41/87] r/aws_iot_topic_rule: Add and use 'FindTopicRuleByName'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_basic\|TestAccIoTTopicRule_disappears' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_basic\|TestAccIoTTopicRule_disappears -timeout 180m === RUN TestAccIoTTopicRule_basic === PAUSE TestAccIoTTopicRule_basic === RUN TestAccIoTTopicRule_disappears === PAUSE TestAccIoTTopicRule_disappears === CONT TestAccIoTTopicRule_basic === CONT TestAccIoTTopicRule_disappears --- PASS: TestAccIoTTopicRule_disappears (17.70s) --- PASS: TestAccIoTTopicRule_basic (23.33s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 30.117s --- internal/service/iot/find.go | 51 ++++++++ internal/service/iot/topic_rule.go | 109 ++++++++--------- internal/service/iot/topic_rule_test.go | 152 +++++++++++++++--------- 3 files changed, 202 insertions(+), 110 deletions(-) diff --git a/internal/service/iot/find.go b/internal/service/iot/find.go index 3920659acbe..504b698662d 100644 --- a/internal/service/iot/find.go +++ b/internal/service/iot/find.go @@ -119,3 +119,54 @@ func FindThingGroupMembership(conn *iot.IoT, thingGroupName, thingName string) e return nil } + +func FindTopicRuleByName(conn *iot.IoT, name string) (*iot.GetTopicRuleOutput, error) { + // GetTopicRule returns unhelpful errors such as + // "An error occurred (UnauthorizedException) when calling the GetTopicRule operation: Access to topic rule 'xxxxxxxx' was denied" + // when querying for a rule that doesn't exist. + var rule *iot.TopicRuleListItem + + err := conn.ListTopicRulesPages(&iot.ListTopicRulesInput{}, func(page *iot.ListTopicRulesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.Rules { + if v == nil { + continue + } + + if aws.StringValue(v.RuleName) == name { + rule = v + + return false + } + } + + return !lastPage + }) + + if err != nil { + return nil, err + } + + if rule == nil { + return nil, tfresource.NewEmptyResultError(name) + } + + input := &iot.GetTopicRuleInput{ + RuleName: aws.String(name), + } + + output, err := conn.GetTopicRule(input) + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index c9f42e7fa56..990fbf00c10 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -2,6 +2,7 @@ package iot import ( "fmt" + "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/iot" @@ -1349,114 +1350,116 @@ func resourceTopicRuleRead(d *schema.ResourceData, meta interface{}) error { defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - input := &iot.GetTopicRuleInput{ - RuleName: aws.String(d.Id()), - } + output, err := FindTopicRuleByName(conn, d.Id()) - out, err := conn.GetTopicRule(input) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN]IoT Topic Rule %s not found, removing from state", d.Id()) + d.SetId("") + return nil + } if err != nil { - return fmt.Errorf("error getting IoT Topic Rule (%s): %w", d.Id(), err) + return fmt.Errorf("reading IoT Topic Rule (%s): %w", d.Id(), err) } - d.Set("arn", out.RuleArn) - d.Set("name", out.Rule.RuleName) - d.Set("description", out.Rule.Description) - d.Set("enabled", !aws.BoolValue(out.Rule.RuleDisabled)) - d.Set("sql", out.Rule.Sql) - d.Set("sql_version", out.Rule.AwsIotSqlVersion) + d.Set("arn", output.RuleArn) + d.Set("name", output.Rule.RuleName) + d.Set("description", output.Rule.Description) + d.Set("enabled", !aws.BoolValue(output.Rule.RuleDisabled)) + d.Set("sql", output.Rule.Sql) + d.Set("sql_version", output.Rule.AwsIotSqlVersion) - if err := d.Set("cloudwatch_alarm", flattenIotCloudWatchAlarmActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting cloudwatch_alarm: %w", err) + if err := d.Set("cloudwatch_alarm", flattenIotCloudWatchAlarmActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting cloudwatch_alarm: %w", err) } - if err := d.Set("cloudwatch_logs", flattenIotCloudWatchLogsActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting cloudwatch_logs: %w", err) + if err := d.Set("cloudwatch_logs", flattenIotCloudWatchLogsActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting cloudwatch_logs: %w", err) } - if err := d.Set("cloudwatch_metric", flattenIotCloudwatchMetricActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting cloudwatch_metric: %w", err) + if err := d.Set("cloudwatch_metric", flattenIotCloudwatchMetricActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting cloudwatch_metric: %w", err) } - if err := d.Set("dynamodb", flattenIotDynamoDbActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting dynamodb: %w", err) + if err := d.Set("dynamodb", flattenIotDynamoDbActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting dynamodb: %w", err) } - if err := d.Set("dynamodbv2", flattenIotDynamoDbv2Actions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting dynamodbv2: %w", err) + if err := d.Set("dynamodbv2", flattenIotDynamoDbv2Actions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting dynamodbv2: %w", err) } - if err := d.Set("elasticsearch", flattenIotElasticsearchActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting elasticsearch: %w", err) + if err := d.Set("elasticsearch", flattenIotElasticsearchActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting elasticsearch: %w", err) } - if err := d.Set("firehose", flattenIotFirehoseActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting firehose: %w", err) + if err := d.Set("firehose", flattenIotFirehoseActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting firehose: %w", err) } - if err := d.Set("iot_analytics", flattenIotIotAnalyticsActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting iot_analytics: %w", err) + if err := d.Set("iot_analytics", flattenIotIotAnalyticsActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting iot_analytics: %w", err) } - if err := d.Set("iot_events", flattenIotIotEventsActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting iot_events: %w", err) + if err := d.Set("iot_events", flattenIotIotEventsActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting iot_events: %w", err) } - if err := d.Set("kafka", flattenIotKafkaActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting kafka: %w", err) + if err := d.Set("kafka", flattenIotKafkaActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting kafka: %w", err) } - if err := d.Set("kinesis", flattenIotKinesisActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting kinesis: %w", err) + if err := d.Set("kinesis", flattenIotKinesisActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting kinesis: %w", err) } - if err := d.Set("lambda", flattenIotLambdaActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting lambda: %w", err) + if err := d.Set("lambda", flattenIotLambdaActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting lambda: %w", err) } - if err := d.Set("republish", flattenIotRepublishActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting republish: %w", err) + if err := d.Set("republish", flattenIotRepublishActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting republish: %w", err) } - if err := d.Set("s3", flattenIotS3Actions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting s3: %w", err) + if err := d.Set("s3", flattenIotS3Actions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting s3: %w", err) } - if err := d.Set("sns", flattenIotSnsActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting sns: %w", err) + if err := d.Set("sns", flattenIotSnsActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting sns: %w", err) } - if err := d.Set("sqs", flattenIotSqsActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting sqs: %w", err) + if err := d.Set("sqs", flattenIotSqsActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting sqs: %w", err) } - if err := d.Set("step_functions", flattenIotStepFunctionsActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting step_functions: %w", err) + if err := d.Set("step_functions", flattenIotStepFunctionsActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting step_functions: %w", err) } - if err := d.Set("timestream", flattenIotTimestreamActions(out.Rule.Actions)); err != nil { - return fmt.Errorf("error setting timestream: %w", err) + if err := d.Set("timestream", flattenIotTimestreamActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting timestream: %w", err) } - if err := d.Set("error_action", flattenIotErrorAction(out.Rule.ErrorAction)); err != nil { - return fmt.Errorf("error setting error_action: %w", err) + if err := d.Set("error_action", flattenIotErrorAction(output.Rule.ErrorAction)); err != nil { + return fmt.Errorf("setting error_action: %w", err) } - tags, err := ListTags(conn, aws.StringValue(out.RuleArn)) + tags, err := ListTags(conn, aws.StringValue(output.RuleArn)) if err != nil { - return fmt.Errorf("error listing tags for IoT Topic Rule (%s): %w", aws.StringValue(out.RuleArn), err) + return fmt.Errorf("listing tags for IoT Topic Rule (%s): %w", aws.StringValue(output.RuleArn), err) } tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %w", err) + return fmt.Errorf("setting tags: %w", err) } if err := d.Set("tags_all", tags.Map()); err != nil { - return fmt.Errorf("error setting tags_all: %w", err) + return fmt.Errorf("setting tags_all: %w", err) } return nil diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 15be50c1617..a652f547d1c 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -4,17 +4,18 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/iot" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfiot "github.com/hashicorp/terraform-provider-aws/internal/service/iot" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func TestAccIoTTopicRule_basic(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -24,15 +25,35 @@ func TestAccIoTTopicRule_basic(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_basic(rName), + Config: testAccTopicRuleConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), - resource.TestCheckResourceAttr("aws_iot_topic_rule.rule", "name", fmt.Sprintf("test_rule_%s", rName)), - resource.TestCheckResourceAttr("aws_iot_topic_rule.rule", "description", "Example rule"), - resource.TestCheckResourceAttr("aws_iot_topic_rule.rule", "enabled", "true"), - resource.TestCheckResourceAttr("aws_iot_topic_rule.rule", "sql", "SELECT * FROM 'topic/test'"), - resource.TestCheckResourceAttr("aws_iot_topic_rule.rule", "sql_version", "2015-10-08"), - resource.TestCheckResourceAttr("aws_iot_topic_rule.rule", "tags.%", "0"), + testAccCheckTopicRuleExists(resourceName), + acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "iot", fmt.Sprintf("rule/%s", rName)), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sql", "SELECT * FROM 'topic/test'"), + resource.TestCheckResourceAttr(resourceName, "sql_version", "2015-10-08"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -44,6 +65,28 @@ func TestAccIoTTopicRule_basic(t *testing.T) { }) } +func TestAccIoTTopicRule_disappears(t *testing.T) { + rName := testAccTopicRuleName() + resourceName := "aws_iot_topic_rule.rule" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, iot.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckTopicRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTopicRuleConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleExists(resourceName), + acctest.CheckResourceDisappears(acctest.Provider, tfiot.ResourceTopicRule(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func TestAccIoTTopicRule_tags(t *testing.T) { rName := sdkacctest.RandString(5) resourceName := "aws_iot_topic_rule.test" @@ -649,52 +692,50 @@ func testAccCheckTopicRuleDestroy(s *terraform.State) error { continue } - input := &iot.ListTopicRulesInput{} + _, err := tfiot.FindTopicRuleByName(conn, rs.Primary.ID) - out, err := conn.ListTopicRules(input) + if tfresource.NotFound(err) { + continue + } if err != nil { return err } - for _, r := range out.Rules { - if *r.RuleName == rs.Primary.ID { - return fmt.Errorf("IoT topic rule still exists:\n%s", r) - } - } - + return fmt.Errorf("IoT Topic Rule %s still exists", rs.Primary.ID) } return nil } -func testAccCheckTopicRuleExists(name string) resource.TestCheckFunc { +func testAccCheckTopicRuleExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", name) + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No IoT Topic Rule ID is set") } conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn - input := &iot.ListTopicRulesInput{} - output, err := conn.ListTopicRules(input) + _, err := tfiot.FindTopicRuleByName(conn, rs.Primary.ID) if err != nil { return err } - for _, rule := range output.Rules { - if aws.StringValue(rule.RuleName) == rs.Primary.ID { - return nil - } - } - - return fmt.Errorf("IoT Topic Rule (%s) not found", rs.Primary.ID) + return nil } } -func testAccTopicRuleRole(rName string) string { +func testAccTopicRuleName() string { + return fmt.Sprintf("tf_acc_test_%[1]s", sdkacctest.RandString(20)) +} + +func testAccTopicRuleRoleConfig(rName string) string { return fmt.Sprintf(` data "aws_partition" "current" {} @@ -715,7 +756,6 @@ resource "aws_iam_role" "iot_role" { ] } EOF - } resource "aws_iam_policy" "policy" { @@ -735,7 +775,6 @@ resource "aws_iam_policy" "policy" { ] } EOF - } resource "aws_iam_policy_attachment" "attach_policy" { @@ -746,11 +785,10 @@ resource "aws_iam_policy_attachment" "attach_policy" { `, rName) } -func testAccTopicRule_basic(rName string) string { +func testAccTopicRuleConfig(rName string) string { return fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" @@ -791,7 +829,7 @@ resource "aws_iot_topic_rule" "test" { func testAccTopicRule_cloudWatchalarm(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -812,7 +850,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccIoTTopicRule_cloudWatchLogs(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -831,7 +869,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_cloudWatchmetric(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -853,7 +891,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_dynamoDB(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -875,7 +913,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_dynamoDB_rangekeys(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -901,7 +939,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_dynamoDBv2(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -923,7 +961,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_elasticSearch(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` data "aws_region" "current" {} @@ -947,7 +985,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_firehose(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -966,7 +1004,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_firehose_separator(rName, separator string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -986,7 +1024,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_iot_analytics(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -1005,7 +1043,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_iot_events(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -1025,7 +1063,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_kafka(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -1046,7 +1084,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_kinesis(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -1085,7 +1123,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_republish(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -1104,7 +1142,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_republish_with_qos(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -1124,7 +1162,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_s3(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -1144,7 +1182,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_sns(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` data "aws_region" "current" {} @@ -1165,7 +1203,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_sqs(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -1185,7 +1223,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_step_functions(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -1205,7 +1243,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_timestream(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" @@ -1235,7 +1273,7 @@ resource "aws_iot_topic_rule" "rule" { func testAccTopicRule_errorAction(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRole(rName), + testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = "test_rule_%[1]s" From ccd2a2fd45de243488cb1ae7e795d4663fc7c63d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 15:31:25 -0400 Subject: [PATCH 42/87] r/aws_iot_topic_rule: Tidy up resource Delete. --- internal/service/iot/topic_rule.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index 990fbf00c10..74ad575c99b 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -1519,14 +1519,13 @@ func resourceTopicRuleUpdate(d *schema.ResourceData, meta interface{}) error { func resourceTopicRuleDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).IoTConn - input := &iot.DeleteTopicRuleInput{ + log.Printf("[INFO] Deleting IoT Topic Rule: %s", d.Id()) + _, err := conn.DeleteTopicRule(&iot.DeleteTopicRuleInput{ RuleName: aws.String(d.Id()), - } - - _, err := conn.DeleteTopicRule(input) + }) if err != nil { - return fmt.Errorf("error deleting IoT Topic Rule (%s): %w", d.Id(), err) + return fmt.Errorf("deleting IoT Topic Rule (%s): %w", d.Id(), err) } return nil From 732e8141cfc1133d324d95a4a7c5093d248b4b9e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 15:33:04 -0400 Subject: [PATCH 43/87] r/aws_iot_topic_rule: Tidy up resource Update. --- internal/service/iot/topic_rule.go | 31 ++++-------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index 74ad575c99b..fd7a12f7f4e 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -1468,40 +1468,17 @@ func resourceTopicRuleRead(d *schema.ResourceData, meta interface{}) error { func resourceTopicRuleUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).IoTConn - if d.HasChanges( - "cloudwatch_alarm", - "cloudwatch_logs", - "cloudwatch_metric", - "description", - "dynamodb", - "dynamodbv2", - "elasticsearch", - "enabled", - "error_action", - "firehose", - "iot_analytics", - "iot_events", - "kafka", - "kinesis", - "lambda", - "republish", - "s3", - "step_functions", - "sns", - "sql", - "sql_version", - "sqs", - "timestream", - ) { + if d.HasChangesExcept("tags", "tags_all") { input := &iot.ReplaceTopicRuleInput{ RuleName: aws.String(d.Get("name").(string)), TopicRulePayload: expandIotTopicRulePayload(d), } + log.Printf("[INFO] Replacing IoT Topic Rule: %s", input) _, err := conn.ReplaceTopicRule(input) if err != nil { - return fmt.Errorf("error updating IoT Topic Rule (%s): %w", d.Id(), err) + return fmt.Errorf("replacing IoT Topic Rule (%s): %w", d.Id(), err) } } @@ -1509,7 +1486,7 @@ func resourceTopicRuleUpdate(d *schema.ResourceData, meta interface{}) error { o, n := d.GetChange("tags_all") if err := UpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating tags: %s", err) + return fmt.Errorf("updating tags: %w", err) } } From 556066aa3101e38e6da38d21233c53339b435889 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 15:37:39 -0400 Subject: [PATCH 44/87] r/aws_iot_topic_rule: Tidy up resource Create. --- internal/service/iot/topic_rule.go | 32 ++++++------------------------ 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index fd7a12f7f4e..f85e9da3a3d 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -6,8 +6,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -1306,38 +1304,20 @@ func resourceTopicRuleCreate(d *schema.ResourceData, meta interface{}) error { tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) ruleName := d.Get("name").(string) - input := &iot.CreateTopicRuleInput{ RuleName: aws.String(ruleName), Tags: aws.String(tags.IgnoreAWS().UrlQueryString()), TopicRulePayload: expandIotTopicRulePayload(d), } - err := resource.Retry(tfiam.PropagationTimeout, func() *resource.RetryError { - var err error - _, err = conn.CreateTopicRule(input) - - if tfawserr.ErrMessageContains(err, iot.ErrCodeInvalidRequestException, "unable to perform: sts:AssumeRole on resource") { - return resource.RetryableError(err) - } - - if tfawserr.ErrMessageContains(err, iot.ErrCodeInvalidRequestException, "unable to assume role (sts:AssumeRole) on resource") { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } - - return nil - }) - - if tfresource.TimedOut(err) { - _, err = conn.CreateTopicRule(input) - } + _, err := tfresource.RetryWhenAWSErrMessageContains(tfiam.PropagationTimeout, + func() (interface{}, error) { + return conn.CreateTopicRule(input) + }, + iot.ErrCodeInvalidRequestException, "sts:AssumeRole") if err != nil { - return fmt.Errorf("error creating IoT Topic Rule (%s): %w", ruleName, err) + return fmt.Errorf("creating IoT Topic Rule (%s): %w", ruleName, err) } d.SetId(ruleName) From e1f2737bfe5f2d73242e8040c62fd9e9226cf10e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 15:41:20 -0400 Subject: [PATCH 45/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_tags'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_tags' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_tags -timeout 180m === RUN TestAccIoTTopicRule_tags === PAUSE TestAccIoTTopicRule_tags === CONT TestAccIoTTopicRule_tags --- PASS: TestAccIoTTopicRule_tags (50.03s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 56.418s --- internal/service/iot/topic_rule_test.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index a652f547d1c..90509113b3a 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -88,7 +88,7 @@ func TestAccIoTTopicRule_disappears(t *testing.T) { } func TestAccIoTTopicRule_tags(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ @@ -98,11 +98,11 @@ func TestAccIoTTopicRule_tags(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRuleTags1(rName, "key1", "user@example"), + Config: testAccTopicRuleConfigTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "user@example"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, { @@ -111,16 +111,16 @@ func TestAccIoTTopicRule_tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccTopicRuleTags2(rName, "key1", "user@example", "key2", "value2"), + Config: testAccTopicRuleConfigTags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "user@example"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, { - Config: testAccTopicRuleTags1(rName, "key2", "value2"), + Config: testAccTopicRuleConfigTags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), @@ -796,10 +796,10 @@ resource "aws_iot_topic_rule" "rule" { `, rName) } -func testAccTopicRuleTags1(rName, tagKey1, tagValue1 string) string { +func testAccTopicRuleConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_iot_topic_rule" "test" { - name = "test_rule_%[1]s" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" @@ -811,10 +811,10 @@ resource "aws_iot_topic_rule" "test" { `, rName, tagKey1, tagValue1) } -func testAccTopicRuleTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { +func testAccTopicRuleConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_iot_topic_rule" "test" { - name = "test_rule_%[1]s" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" From 3cf854c79c47fcac958c3c23104ecb7ddf16703c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 16:26:21 -0400 Subject: [PATCH 46/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_cloudWatchAlarm'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_cloudWatchAlarm' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_cloudWatchAlarm -timeout 180m === RUN TestAccIoTTopicRule_cloudWatchAlarm === PAUSE TestAccIoTTopicRule_cloudWatchAlarm === CONT TestAccIoTTopicRule_cloudWatchAlarm --- PASS: TestAccIoTTopicRule_cloudWatchAlarm (27.10s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 30.985s --- internal/service/iot/topic_rule_test.go | 35 +++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 90509113b3a..d4919b2af12 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -132,7 +132,7 @@ func TestAccIoTTopicRule_tags(t *testing.T) { } func TestAccIoTTopicRule_cloudWatchAlarm(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -142,9 +142,34 @@ func TestAccIoTTopicRule_cloudWatchAlarm(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_cloudWatchalarm(rName), + Config: testAccTopicRuleCloudWatchAlarmConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "cloudwatch_alarm.*", map[string]string{ + "alarm_name": "myalarm", + "state_reason": "test", + "state_value": "OK", + }), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "description", "Example rule"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -827,12 +852,12 @@ resource "aws_iot_topic_rule" "test" { `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } -func testAccTopicRule_cloudWatchalarm(rName string) string { +func testAccTopicRuleCloudWatchAlarmConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" + name = %[1]q description = "Example rule" enabled = true sql = "SELECT * FROM 'topic/test'" From db4f75112d2e01acafbb2d6ae9eda92545b22de2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 16:33:12 -0400 Subject: [PATCH 47/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_cloudWatchLogs'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_cloudWatchLogs' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_cloudWatchLogs -timeout 180m === RUN TestAccIoTTopicRule_cloudWatchLogs === PAUSE TestAccIoTTopicRule_cloudWatchLogs === CONT TestAccIoTTopicRule_cloudWatchLogs --- PASS: TestAccIoTTopicRule_cloudWatchLogs (31.40s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 34.916s --- internal/service/iot/topic_rule_test.go | 46 ++++++++++++++++++++----- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index d4919b2af12..11df386fc62 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -182,7 +182,7 @@ func TestAccIoTTopicRule_cloudWatchAlarm(t *testing.T) { } func TestAccIoTTopicRule_cloudWatchLogs(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -192,9 +192,35 @@ func TestAccIoTTopicRule_cloudWatchLogs(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccIoTTopicRule_cloudWatchLogs(rName), + Config: testAccTopicRuleCloudWatchLogsConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "cloudwatch_logs.*", map[string]string{ + "log_group_name": "mylogs1", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "cloudwatch_logs.*", map[string]string{ + "log_group_name": "mylogs2", + }), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -873,19 +899,23 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccIoTTopicRule_cloudWatchLogs(rName string) string { +func testAccTopicRuleCloudWatchLogsConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" - enabled = true + name = %[1]q + enabled = false sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" cloudwatch_logs { - log_group_name = "mylogs" + log_group_name = "mylogs1" + role_arn = aws_iam_role.iot_role.arn + } + + cloudwatch_logs { + log_group_name = "mylogs2" role_arn = aws_iam_role.iot_role.arn } } From 8f5f9f41241be6e5b6b445f7cbdc1811792dfc92 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 16:39:33 -0400 Subject: [PATCH 48/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_cloudWatchMetric'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_cloudWatchMetric' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_cloudWatchMetric -timeout 180m === RUN TestAccIoTTopicRule_cloudWatchMetric === PAUSE TestAccIoTTopicRule_cloudWatchMetric === CONT TestAccIoTTopicRule_cloudWatchMetric --- PASS: TestAccIoTTopicRule_cloudWatchMetric (35.33s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 39.030s --- internal/service/iot/topic_rule_test.go | 44 +++++++++++++++++++------ 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 11df386fc62..632758567dc 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -233,7 +233,7 @@ func TestAccIoTTopicRule_cloudWatchLogs(t *testing.T) { } func TestAccIoTTopicRule_cloudWatchMetric(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -243,9 +243,34 @@ func TestAccIoTTopicRule_cloudWatchMetric(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_cloudWatchmetric(rName), + Config: testAccTopicRuleCloudWatchMetricConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "cloudwatch_metric.*", map[string]string{ + "metric_name": "TestName", + "metric_namespace": "TestNS", + "metric_unit": "s", + "metric_value": "10", + }), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -922,22 +947,21 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_cloudWatchmetric(rName string) string { +func testAccTopicRuleCloudWatchMetricConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" cloudwatch_metric { - metric_name = "FakeData" - metric_namespace = "FakeData" - metric_value = "FakeData" - metric_unit = "FakeData" + metric_name = "TestName" + metric_namespace = "TestNS" + metric_value = "10" + metric_unit = "s" role_arn = aws_iam_role.iot_role.arn } } From 4245c5b2cd193139695c6dc57e6f8afce8b0fadf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 16:53:46 -0400 Subject: [PATCH 49/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_dynamoDB'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_dynamoDB' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_dynamoDB -timeout 180m === RUN TestAccIoTTopicRule_dynamoDB === PAUSE TestAccIoTTopicRule_dynamoDB === RUN TestAccIoTTopicRule_dynamoDBv2 === PAUSE TestAccIoTTopicRule_dynamoDBv2 === CONT TestAccIoTTopicRule_dynamoDB === CONT TestAccIoTTopicRule_dynamoDBv2 --- PASS: TestAccIoTTopicRule_dynamoDBv2 (28.58s) --- PASS: TestAccIoTTopicRule_dynamoDB (46.00s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 50.209s --- internal/service/iot/topic_rule_test.go | 133 +++++++++++++++++++----- 1 file changed, 106 insertions(+), 27 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 632758567dc..95c16eef8b9 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -283,7 +283,7 @@ func TestAccIoTTopicRule_cloudWatchMetric(t *testing.T) { } func TestAccIoTTopicRule_dynamoDB(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -293,9 +293,35 @@ func TestAccIoTTopicRule_dynamoDB(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_dynamoDB(rName), + Config: testAccTopicRuleDynamoDBConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "description", "Description1"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "dynamodb.*", map[string]string{ + "hash_key_field": "hkf", + "hash_key_value": "hkv", + "payload_field": "pf", + "table_name": "tn", + }), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -304,9 +330,39 @@ func TestAccIoTTopicRule_dynamoDB(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccTopicRule_dynamoDB_rangekeys(rName), + Config: testAccTopicRuleDynamoDBRangeKeyConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "description", "Description2"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "dynamodb.*", map[string]string{ + "hash_key_field": "hkf", + "hash_key_value": "hkv", + "operation": "INSERT", + "payload_field": "pf", + "range_key_field": "rkf", + "range_key_type": "STRING", + "range_key_value": "rkv", + "table_name": "tn", + }), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, }, @@ -314,7 +370,8 @@ func TestAccIoTTopicRule_dynamoDB(t *testing.T) { } func TestAccIoTTopicRule_dynamoDBv2(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() + resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -323,9 +380,32 @@ func TestAccIoTTopicRule_dynamoDBv2(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_dynamoDBv2(rName), + Config: testAccTopicRuleDynamoDBv2Config(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "dynamodbv2.*", map[string]string{ + "put_item.#": "1", + "put_item.0.table_name": "test", + }), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, }, @@ -968,61 +1048,60 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_dynamoDB(rName string) string { +func testAccTopicRuleDynamoDBConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q + description = "Description1" enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" dynamodb { - hash_key_field = "hash_key_field" - hash_key_value = "hash_key_value" - payload_field = "payload_field" + hash_key_field = "hkf" + hash_key_value = "hkv" + payload_field = "pf" role_arn = aws_iam_role.iot_role.arn - table_name = "table_name" + table_name = "tn" } } `, rName)) } -func testAccTopicRule_dynamoDB_rangekeys(rName string) string { +func testAccTopicRuleDynamoDBRangeKeyConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q + description = "Description2" enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" dynamodb { - hash_key_field = "hash_key_field" - hash_key_value = "hash_key_value" - payload_field = "payload_field" - range_key_field = "range_key_field" - range_key_value = "range_key_value" + hash_key_field = "hkf" + hash_key_value = "hkv" + payload_field = "pf" + range_key_field = "rkf" + range_key_value = "rkv" range_key_type = "STRING" role_arn = aws_iam_role.iot_role.arn - table_name = "table_name" + table_name = "tn" operation = "INSERT" } } `, rName)) } -func testAccTopicRule_dynamoDBv2(rName string) string { +func testAccTopicRuleDynamoDBv2Config(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT field as column_name FROM 'topic/test'" sql_version = "2015-10-08" From c0e99762c3d48cffa18b6814f46d3af2374ede53 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 16:58:33 -0400 Subject: [PATCH 50/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_elasticSearch'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_elasticSearch' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_elasticSearch -timeout 180m === RUN TestAccIoTTopicRule_elasticSearch === PAUSE TestAccIoTTopicRule_elasticSearch === CONT TestAccIoTTopicRule_elasticSearch --- PASS: TestAccIoTTopicRule_elasticSearch (27.94s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 31.929s --- internal/service/iot/topic_rule_test.go | 35 ++++++++++++++++++++----- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 95c16eef8b9..413df6471e4 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -413,7 +413,7 @@ func TestAccIoTTopicRule_dynamoDBv2(t *testing.T) { } func TestAccIoTTopicRule_elasticSearch(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -423,9 +423,33 @@ func TestAccIoTTopicRule_elasticSearch(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_elasticSearch(rName), + Config: testAccTopicRuleElasticsearchConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "elasticsearch.*", map[string]string{ + "id": "myIdentifier", + "index": "myindex", + "type": "mydocument", + }), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -1117,15 +1141,14 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_elasticSearch(rName string) string { +func testAccTopicRuleElasticsearchConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` data "aws_region" "current" {} resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" From c23f11a7d9bdbd289a2c4df159149a2aac61d115 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 17:02:21 -0400 Subject: [PATCH 51/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_firehose'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_firehose' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_firehose -timeout 180m === RUN TestAccIoTTopicRule_firehose === PAUSE TestAccIoTTopicRule_firehose === CONT TestAccIoTTopicRule_firehose --- PASS: TestAccIoTTopicRule_firehose (27.76s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 31.499s --- internal/service/iot/topic_rule_test.go | 51 +++++++++++++++++++++---- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 413df6471e4..ff474289084 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -462,7 +462,7 @@ func TestAccIoTTopicRule_elasticSearch(t *testing.T) { } func TestAccIoTTopicRule_firehose(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -472,9 +472,37 @@ func TestAccIoTTopicRule_firehose(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_firehose(rName), + Config: testAccTopicRuleFirehoseConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "3"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "firehose.*", map[string]string{ + "delivery_stream_name": "mystream1", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "firehose.*", map[string]string{ + "delivery_stream_name": "mystream2", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "firehose.*", map[string]string{ + "delivery_stream_name": "mystream3", + }), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -1164,19 +1192,28 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_firehose(rName string) string { +func testAccTopicRuleFirehoseConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" firehose { - delivery_stream_name = "mystream" + delivery_stream_name = "mystream1" + role_arn = aws_iam_role.iot_role.arn + } + + firehose { + delivery_stream_name = "mystream2" + role_arn = aws_iam_role.iot_role.arn + } + + firehose { + delivery_stream_name = "mystream3" role_arn = aws_iam_role.iot_role.arn } } From 11a470916d1432eb08ebb5068992c6dbe5e7df90 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 May 2022 17:08:01 -0400 Subject: [PATCH 52/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_Firehose_separator'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_Firehose_separator' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_Firehose_separator -timeout 180m === RUN TestAccIoTTopicRule_Firehose_separator === PAUSE TestAccIoTTopicRule_Firehose_separator === CONT TestAccIoTTopicRule_Firehose_separator --- PASS: TestAccIoTTopicRule_Firehose_separator (39.73s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 43.373s --- internal/service/iot/topic_rule_test.go | 37 ++++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index ff474289084..a42ae98d27e 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -515,7 +515,7 @@ func TestAccIoTTopicRule_firehose(t *testing.T) { } func TestAccIoTTopicRule_Firehose_separator(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -525,9 +525,32 @@ func TestAccIoTTopicRule_Firehose_separator(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_firehose_separator(rName, "\n"), + Config: testAccTopicRuleFirehoseSeparatorConfig(rName, "\n"), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "firehose.*", map[string]string{ + "delivery_stream_name": "mystream", + "separator": "\n", + }), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -536,7 +559,7 @@ func TestAccIoTTopicRule_Firehose_separator(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccTopicRule_firehose_separator(rName, ","), + Config: testAccTopicRuleFirehoseSeparatorConfig(rName, ","), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), ), @@ -1220,12 +1243,12 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_firehose_separator(rName, separator string) string { +func testAccTopicRuleFirehoseSeparatorConfig(rName, separator string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" + name = %[1]q description = "Example rule" enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1234,7 +1257,7 @@ resource "aws_iot_topic_rule" "rule" { firehose { delivery_stream_name = "mystream" role_arn = aws_iam_role.iot_role.arn - separator = %q + separator = %[2]q } } `, rName, separator)) From b4fcc6140f26b58aa805c95ca4290d9aaa0594ff Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 08:15:59 -0400 Subject: [PATCH 53/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_IoT_analytics'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_IoT_analytics' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_IoT_analytics -timeout 180m === RUN TestAccIoTTopicRule_IoT_analytics === PAUSE TestAccIoTTopicRule_IoT_analytics === CONT TestAccIoTTopicRule_IoT_analytics --- PASS: TestAccIoTTopicRule_IoT_analytics (25.67s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 29.653s --- internal/service/iot/topic_rule_test.go | 33 +++++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index a42ae98d27e..1ebaa29e411 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -569,7 +569,8 @@ func TestAccIoTTopicRule_Firehose_separator(t *testing.T) { } func TestAccIoTTopicRule_IoT_analytics(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() + resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -578,9 +579,31 @@ func TestAccIoTTopicRule_IoT_analytics(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_iot_analytics(rName), + Config: testAccTopicRuleIoTAnalyticsConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "iot_analytics.*", map[string]string{ + "channel_name": "fakedata", + }), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, }, @@ -1263,12 +1286,12 @@ resource "aws_iot_topic_rule" "rule" { `, rName, separator)) } -func testAccTopicRule_iot_analytics(rName string) string { +func testAccTopicRuleIoTAnalyticsConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" + name = %[1]q description = "Example rule" enabled = true sql = "SELECT * FROM 'topic/test'" From 8e036fb970215fa9bbd8440d1a1cf3beb65cb6f7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 08:19:06 -0400 Subject: [PATCH 54/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_IoT_events'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_IoT_events' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_IoT_events -timeout 180m === RUN TestAccIoTTopicRule_IoT_events === PAUSE TestAccIoTTopicRule_IoT_events === CONT TestAccIoTTopicRule_IoT_events --- PASS: TestAccIoTTopicRule_IoT_events (33.75s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 37.569s --- internal/service/iot/topic_rule_test.go | 36 ++++++++++++++++++++----- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 1ebaa29e411..fc566583eea 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -611,7 +611,8 @@ func TestAccIoTTopicRule_IoT_analytics(t *testing.T) { } func TestAccIoTTopicRule_IoT_events(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() + resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -620,9 +621,32 @@ func TestAccIoTTopicRule_IoT_events(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_iot_events(rName), + Config: testAccTopicRuleIoTEventsConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "iot_events.*", map[string]string{ + "input_name": "fake_input_name", + "message_id": "fake_message_id", + }), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, }, @@ -1292,7 +1316,6 @@ func testAccTopicRuleIoTAnalyticsConfig(rName string) string { fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { name = %[1]q - description = "Example rule" enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" @@ -1305,13 +1328,12 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_iot_events(rName string) string { +func testAccTopicRuleIoTEventsConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" From ae90793a894a5698f98439bd2d7dbda70ada1ae1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 09:04:22 -0400 Subject: [PATCH 55/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_kafka'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_kafka' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_kafka -timeout 180m === RUN TestAccIoTTopicRule_kafka === PAUSE TestAccIoTTopicRule_kafka === CONT TestAccIoTTopicRule_kafka topic_rule_test.go:660: Step 1/2 error: Error running apply: exit status 1 Error: creating IoT Topic Rule (tf_acc_test_1bnm6szi43rc3u28f6qd): InvalidRequestException: Invalid destination arn 'arn:aws:kafka:us-west-2:123456789012:topic/test'. with aws_iot_topic_rule.rule, on terraform_plugin_test.tf line 50, in resource "aws_iot_topic_rule" "rule": 50: resource "aws_iot_topic_rule" "rule" { --- FAIL: TestAccIoTTopicRule_kafka (17.32s) FAIL FAIL github.com/hashicorp/terraform-provider-aws/internal/service/iot 20.920s FAIL make: *** [testacc] Error 1 Requires new 'aws_topic_rule_destination' resource. --- internal/service/iot/topic_rule_test.go | 42 ++++++++++++++++++++----- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index fc566583eea..0da4da567d3 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -654,8 +654,9 @@ func TestAccIoTTopicRule_IoT_events(t *testing.T) { } func TestAccIoTTopicRule_kafka(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, iot.EndpointsID), @@ -663,9 +664,34 @@ func TestAccIoTTopicRule_kafka(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_kafka(rName), + Config: testAccTopicRuleKafkaConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "kafka.*", map[string]string{ + "bootstrap_servers": "b-1.localhost:9094", + "ssl_keystore": "$${get_secret('secret_name', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}", + "ssl_keystore_password": "password", + "topic": "fake_topic", + }), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -1347,18 +1373,20 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_kafka(rName string) string { +func testAccTopicRuleKafkaConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` +data "aws_region" "current" {} + resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" + kafka { - destination_arn = "[vpc destination arn]" + destination_arn = "arn:${data.aws_partition.current.partition}:kafka:${data.aws_region.current.name}:123456789012:topic/test" topic = "fake_topic" bootstrap_servers = "b-1.localhost:9094" ssl_keystore = "$${get_secret('secret_name', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}" From 4105e063f634d06c24331f13b94e5f9428400813 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 09:21:53 -0400 Subject: [PATCH 56/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_kinesis'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_kinesis' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_kinesis -timeout 180m === RUN TestAccIoTTopicRule_kinesis === PAUSE TestAccIoTTopicRule_kinesis === CONT TestAccIoTTopicRule_kinesis --- PASS: TestAccIoTTopicRule_kinesis (26.73s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 30.509s --- internal/service/iot/topic_rule_test.go | 35 ++++++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 0da4da567d3..d9fef009993 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -704,7 +704,7 @@ func TestAccIoTTopicRule_kafka(t *testing.T) { } func TestAccIoTTopicRule_kinesis(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -714,9 +714,31 @@ func TestAccIoTTopicRule_kinesis(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_kinesis(rName), + Config: testAccTopicRuleKinesisConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "kinesis.*", map[string]string{ + "stream_name": "mystream", + }), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -965,7 +987,7 @@ func TestAccIoTTopicRule_updateKinesisErrorAction(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_kinesis(rName), + Config: testAccTopicRuleKinesisConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), @@ -1396,13 +1418,12 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_kinesis(rName string) string { +func testAccTopicRuleKinesisConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" From 1f259af498577c4d5649406198105927e1dbeb4c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 09:26:53 -0400 Subject: [PATCH 57/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_lambda'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_lambda' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_lambda -timeout 180m === RUN TestAccIoTTopicRule_lambda === PAUSE TestAccIoTTopicRule_lambda === CONT TestAccIoTTopicRule_lambda --- PASS: TestAccIoTTopicRule_lambda (16.61s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 20.630s --- internal/service/iot/topic_rule_test.go | 30 ++++++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index d9fef009993..bf05f4f376d 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -751,7 +751,7 @@ func TestAccIoTTopicRule_kinesis(t *testing.T) { } func TestAccIoTTopicRule_lambda(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -761,9 +761,28 @@ func TestAccIoTTopicRule_lambda(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_lambda(rName), + Config: testAccTopicRuleLambdaConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "1"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -1436,15 +1455,14 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_lambda(rName string) string { +func testAccTopicRuleLambdaConfig(rName string) string { return fmt.Sprintf(` data "aws_region" "current" {} data "aws_partition" "current" {} resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" From c623a03d2a0a3a2510f4654784a1a35e5972fef5 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 09:59:23 -0400 Subject: [PATCH 58/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_republish'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_republish' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_republish -timeout 180m === RUN TestAccIoTTopicRule_republish === PAUSE TestAccIoTTopicRule_republish === RUN TestAccIoTTopicRule_republishWithQos === PAUSE TestAccIoTTopicRule_republishWithQos === CONT TestAccIoTTopicRule_republish === CONT TestAccIoTTopicRule_republishWithQos --- PASS: TestAccIoTTopicRule_republishWithQos (36.97s) --- PASS: TestAccIoTTopicRule_republish (37.02s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 41.296s --- internal/service/iot/topic_rule_test.go | 68 ++++++++++++++++++++----- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index bf05f4f376d..23c9191fc9d 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -795,7 +795,7 @@ func TestAccIoTTopicRule_lambda(t *testing.T) { } func TestAccIoTTopicRule_republish(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -805,9 +805,32 @@ func TestAccIoTTopicRule_republish(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_republish(rName), + Config: testAccTopicRuleRepublishConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "republish.*", map[string]string{ + "qos": "0", + "topic": "mytopic", + }), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -820,7 +843,7 @@ func TestAccIoTTopicRule_republish(t *testing.T) { } func TestAccIoTTopicRule_republishWithQos(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -830,9 +853,32 @@ func TestAccIoTTopicRule_republishWithQos(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_republish_with_qos(rName), + Config: testAccTopicRuleRepublishWithQoSConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "republish.*", map[string]string{ + "qos": "1", + "topic": "mytopic", + }), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -1474,13 +1520,12 @@ resource "aws_iot_topic_rule" "rule" { `, rName) } -func testAccTopicRule_republish(rName string) string { +func testAccTopicRuleRepublishConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" @@ -1493,13 +1538,12 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_republish_with_qos(rName string) string { +func testAccTopicRuleRepublishWithQoSConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" From ef0091a8a7f1d5af99d7f6c831291043e0b39105 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 11:12:43 -0400 Subject: [PATCH 59/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_s3'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_s3' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_s3 -timeout 180m === RUN TestAccIoTTopicRule_s3 === PAUSE TestAccIoTTopicRule_s3 === CONT TestAccIoTTopicRule_s3 --- PASS: TestAccIoTTopicRule_s3 (30.07s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 33.835s --- internal/service/iot/topic_rule_test.go | 34 ++++++++++++++++++++----- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 23c9191fc9d..72264793a96 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -891,7 +891,7 @@ func TestAccIoTTopicRule_republishWithQos(t *testing.T) { } func TestAccIoTTopicRule_s3(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -901,9 +901,32 @@ func TestAccIoTTopicRule_s3(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_s3(rName), + Config: testAccTopicRuleS3Config(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "s3.*", map[string]string{ + "bucket_name": "mybucket", + "key": "mykey", + }), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -1557,13 +1580,12 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_s3(rName string) string { +func testAccTopicRuleS3Config(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" From 8195d0c2021f7ec544400a178160914ffc207349 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 11:15:26 -0400 Subject: [PATCH 60/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_sns'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_sns' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_sns -timeout 180m === RUN TestAccIoTTopicRule_sns === PAUSE TestAccIoTTopicRule_sns === CONT TestAccIoTTopicRule_sns --- PASS: TestAccIoTTopicRule_sns (35.70s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 39.313s --- internal/service/iot/topic_rule_test.go | 30 ++++++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 72264793a96..ae4ede0664a 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -939,7 +939,7 @@ func TestAccIoTTopicRule_s3(t *testing.T) { } func TestAccIoTTopicRule_sns(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -949,9 +949,28 @@ func TestAccIoTTopicRule_sns(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_sns(rName), + Config: testAccTopicRuleSNSConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -1599,15 +1618,14 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_sns(rName string) string { +func testAccTopicRuleSNSConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` data "aws_region" "current" {} resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" From 2f378bf47a9b3d5ffe7445c2ec013755bfcb9107 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 11:21:26 -0400 Subject: [PATCH 61/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_sqs'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_sqs' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_sqs -timeout 180m === RUN TestAccIoTTopicRule_sqs === PAUSE TestAccIoTTopicRule_sqs === CONT TestAccIoTTopicRule_sqs --- PASS: TestAccIoTTopicRule_sqs (35.02s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 38.706s --- internal/service/iot/topic_rule_test.go | 34 ++++++++++++++++++++----- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index ae4ede0664a..c44ced1ae69 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -983,7 +983,7 @@ func TestAccIoTTopicRule_sns(t *testing.T) { } func TestAccIoTTopicRule_sqs(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -993,9 +993,32 @@ func TestAccIoTTopicRule_sqs(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_sqs(rName), + Config: testAccTopicRuleSQSConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "sqs.*", map[string]string{ + "queue_url": "fakedata", + "use_base64": "false", + }), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -1638,13 +1661,12 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_sqs(rName string) string { +func testAccTopicRuleSQSConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" From adf3f7904b6b1281adece4dd5df579bc2f81b513 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 11:24:36 -0400 Subject: [PATCH 62/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_Step_functions'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_Step_functions' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_Step_functions -timeout 180m === RUN TestAccIoTTopicRule_Step_functions === PAUSE TestAccIoTTopicRule_Step_functions === CONT TestAccIoTTopicRule_Step_functions --- PASS: TestAccIoTTopicRule_Step_functions (35.58s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 39.100s --- internal/service/iot/topic_rule_test.go | 34 ++++++++++++++++++++----- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index c44ced1ae69..79dd545dac3 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -1031,7 +1031,7 @@ func TestAccIoTTopicRule_sqs(t *testing.T) { } func TestAccIoTTopicRule_Step_functions(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -1041,9 +1041,32 @@ func TestAccIoTTopicRule_Step_functions(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_step_functions(rName), + Config: testAccTopicRuleStepFunctionsConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "step_functions.*", map[string]string{ + "execution_name_prefix": "myprefix", + "state_machine_name": "mystatemachine", + }), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -1680,13 +1703,12 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_step_functions(rName string) string { +func testAccTopicRuleStepFunctionsConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" From f8e06319dbf9f4b237fac94988133f843f580acb Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 11:45:06 -0400 Subject: [PATCH 63/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_Timestream'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_Timestream' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_Timestream -timeout 180m === RUN TestAccIoTTopicRule_Timestream === PAUSE TestAccIoTTopicRule_Timestream === CONT TestAccIoTTopicRule_Timestream --- PASS: TestAccIoTTopicRule_Timestream (35.94s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 39.999s --- internal/service/iot/topic_rule_test.go | 42 +++++++++++++++++++++---- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 79dd545dac3..b43868b0fef 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -1079,7 +1079,7 @@ func TestAccIoTTopicRule_Step_functions(t *testing.T) { } func TestAccIoTTopicRule_Timestream(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -1089,9 +1089,40 @@ func TestAccIoTTopicRule_Timestream(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_timestream(rName), + Config: testAccTopicRuleTimestreamConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "timestream.*", map[string]string{ + "database_name": "TestDB", + "dimension.#": "1", + "table_name": "test_table", + "timestamp.#": "1", + "timestamp.0.unit": "MILLISECONDS", + "timestamp.0.value": "${time}", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "timestream.*.dimension.*", map[string]string{ + "name": "dim", + "value": "${dim}", + }), ), }, { @@ -1722,13 +1753,12 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_timestream(rName string) string { +func testAccTopicRuleTimestreamConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" From fd0a964a85be4dfd9594cc23b6a393fa79320114 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 11:52:40 -0400 Subject: [PATCH 64/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_errorAction'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_errorAction' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_errorAction -timeout 180m === RUN TestAccIoTTopicRule_errorAction === PAUSE TestAccIoTTopicRule_errorAction === CONT TestAccIoTTopicRule_errorAction --- PASS: TestAccIoTTopicRule_errorAction (27.91s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 31.410s --- internal/service/iot/topic_rule_test.go | 58 +++++++++++++++++++++---- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index b43868b0fef..934f6e74903 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -1135,7 +1135,7 @@ func TestAccIoTTopicRule_Timestream(t *testing.T) { } func TestAccIoTTopicRule_errorAction(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -1145,9 +1145,50 @@ func TestAccIoTTopicRule_errorAction(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRule_errorAction(rName), + Config: testAccTopicRuleErrorActionConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.kinesis.#", "1"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.kinesis.0.stream_name", "mystream2"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.timestream.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "kinesis.*", map[string]string{ + "stream_name": "mystream1", + }), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { @@ -1179,7 +1220,7 @@ func TestAccIoTTopicRule_updateKinesisErrorAction(t *testing.T) { }, { - Config: testAccTopicRule_errorAction(rName), + Config: testAccTopicRuleErrorActionConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "1"), @@ -1782,25 +1823,24 @@ resource "aws_iot_topic_rule" "rule" { `, rName)) } -func testAccTopicRule_errorAction(rName string) string { +func testAccTopicRuleErrorActionConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` resource "aws_iot_topic_rule" "rule" { - name = "test_rule_%[1]s" - description = "Example rule" + name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" sql_version = "2015-10-08" kinesis { - stream_name = "mystream" + stream_name = "mystream1" role_arn = aws_iam_role.iot_role.arn } error_action { kinesis { - stream_name = "mystream" + stream_name = "mystream2" role_arn = aws_iam_role.iot_role.arn } } From 77ef936da565d20170b75a067e3864f35dd8452c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 11:57:43 -0400 Subject: [PATCH 65/87] r/aws_iot_topic_rule: Tidy up 'TestAccIoTTopicRule_updateKinesisErrorAction'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_updateKinesisErrorAction' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_updateKinesisErrorAction -timeout 180m === RUN TestAccIoTTopicRule_updateKinesisErrorAction === PAUSE TestAccIoTTopicRule_updateKinesisErrorAction === CONT TestAccIoTTopicRule_updateKinesisErrorAction --- PASS: TestAccIoTTopicRule_updateKinesisErrorAction (47.29s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 50.700s --- internal/service/iot/topic_rule_test.go | 68 +++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 934f6e74903..40d816f4a26 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -1202,7 +1202,7 @@ func TestAccIoTTopicRule_errorAction(t *testing.T) { // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/16115 func TestAccIoTTopicRule_updateKinesisErrorAction(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.rule" resource.ParallelTest(t, resource.TestCase{ @@ -1214,16 +1214,76 @@ func TestAccIoTTopicRule_updateKinesisErrorAction(t *testing.T) { { Config: testAccTopicRuleKinesisConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "kinesis.*", map[string]string{ + "stream_name": "mystream", + }), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, - { Config: testAccTopicRuleErrorActionConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.kinesis.#", "1"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.kinesis.0.stream_name", "mystream2"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.timestream.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "kinesis.*", map[string]string{ + "stream_name": "mystream1", + }), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, { From 14edd186daa3572172237aa58d0151ec349f1529 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 12:00:22 -0400 Subject: [PATCH 66/87] 'aws_iot_topic_rule.rule' -> 'aws_iot_topic_rule.test'. --- internal/service/iot/topic_rule_test.go | 94 ++++++++++++------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 40d816f4a26..57dc6076d1b 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -16,7 +16,7 @@ import ( func TestAccIoTTopicRule_basic(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -67,7 +67,7 @@ func TestAccIoTTopicRule_basic(t *testing.T) { func TestAccIoTTopicRule_disappears(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -133,7 +133,7 @@ func TestAccIoTTopicRule_tags(t *testing.T) { func TestAccIoTTopicRule_cloudWatchAlarm(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -183,7 +183,7 @@ func TestAccIoTTopicRule_cloudWatchAlarm(t *testing.T) { func TestAccIoTTopicRule_cloudWatchLogs(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -234,7 +234,7 @@ func TestAccIoTTopicRule_cloudWatchLogs(t *testing.T) { func TestAccIoTTopicRule_cloudWatchMetric(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -284,7 +284,7 @@ func TestAccIoTTopicRule_cloudWatchMetric(t *testing.T) { func TestAccIoTTopicRule_dynamoDB(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -371,7 +371,7 @@ func TestAccIoTTopicRule_dynamoDB(t *testing.T) { func TestAccIoTTopicRule_dynamoDBv2(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -414,7 +414,7 @@ func TestAccIoTTopicRule_dynamoDBv2(t *testing.T) { func TestAccIoTTopicRule_elasticSearch(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -463,7 +463,7 @@ func TestAccIoTTopicRule_elasticSearch(t *testing.T) { func TestAccIoTTopicRule_firehose(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -516,7 +516,7 @@ func TestAccIoTTopicRule_firehose(t *testing.T) { func TestAccIoTTopicRule_Firehose_separator(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -570,7 +570,7 @@ func TestAccIoTTopicRule_Firehose_separator(t *testing.T) { func TestAccIoTTopicRule_IoT_analytics(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -612,7 +612,7 @@ func TestAccIoTTopicRule_IoT_analytics(t *testing.T) { func TestAccIoTTopicRule_IoT_events(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -655,7 +655,7 @@ func TestAccIoTTopicRule_IoT_events(t *testing.T) { func TestAccIoTTopicRule_kafka(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -705,7 +705,7 @@ func TestAccIoTTopicRule_kafka(t *testing.T) { func TestAccIoTTopicRule_kinesis(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -752,7 +752,7 @@ func TestAccIoTTopicRule_kinesis(t *testing.T) { func TestAccIoTTopicRule_lambda(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -796,7 +796,7 @@ func TestAccIoTTopicRule_lambda(t *testing.T) { func TestAccIoTTopicRule_republish(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -844,7 +844,7 @@ func TestAccIoTTopicRule_republish(t *testing.T) { func TestAccIoTTopicRule_republishWithQos(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -892,7 +892,7 @@ func TestAccIoTTopicRule_republishWithQos(t *testing.T) { func TestAccIoTTopicRule_s3(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -940,7 +940,7 @@ func TestAccIoTTopicRule_s3(t *testing.T) { func TestAccIoTTopicRule_sns(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -984,7 +984,7 @@ func TestAccIoTTopicRule_sns(t *testing.T) { func TestAccIoTTopicRule_sqs(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -1032,7 +1032,7 @@ func TestAccIoTTopicRule_sqs(t *testing.T) { func TestAccIoTTopicRule_Step_functions(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -1080,7 +1080,7 @@ func TestAccIoTTopicRule_Step_functions(t *testing.T) { func TestAccIoTTopicRule_Timestream(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -1136,7 +1136,7 @@ func TestAccIoTTopicRule_Timestream(t *testing.T) { func TestAccIoTTopicRule_errorAction(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -1203,7 +1203,7 @@ func TestAccIoTTopicRule_errorAction(t *testing.T) { // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/16115 func TestAccIoTTopicRule_updateKinesisErrorAction(t *testing.T) { rName := testAccTopicRuleName() - resourceName := "aws_iot_topic_rule.rule" + resourceName := "aws_iot_topic_rule.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -1398,7 +1398,7 @@ resource "aws_iam_policy_attachment" "attach_policy" { func testAccTopicRuleConfig(rName string) string { return fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1442,7 +1442,7 @@ func testAccTopicRuleCloudWatchAlarmConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q description = "Example rule" enabled = true @@ -1463,7 +1463,7 @@ func testAccTopicRuleCloudWatchLogsConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = false sql = "SELECT * FROM 'topic/test'" @@ -1486,7 +1486,7 @@ func testAccTopicRuleCloudWatchMetricConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1507,7 +1507,7 @@ func testAccTopicRuleDynamoDBConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q description = "Description1" enabled = true @@ -1529,7 +1529,7 @@ func testAccTopicRuleDynamoDBRangeKeyConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q description = "Description2" enabled = true @@ -1555,7 +1555,7 @@ func testAccTopicRuleDynamoDBv2Config(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT field as column_name FROM 'topic/test'" @@ -1578,7 +1578,7 @@ func testAccTopicRuleElasticsearchConfig(rName string) string { fmt.Sprintf(` data "aws_region" "current" {} -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1599,7 +1599,7 @@ func testAccTopicRuleFirehoseConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1627,7 +1627,7 @@ func testAccTopicRuleFirehoseSeparatorConfig(rName, separator string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q description = "Example rule" enabled = true @@ -1647,7 +1647,7 @@ func testAccTopicRuleIoTAnalyticsConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1665,7 +1665,7 @@ func testAccTopicRuleIoTEventsConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1686,7 +1686,7 @@ func testAccTopicRuleKafkaConfig(rName string) string { fmt.Sprintf(` data "aws_region" "current" {} -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1707,7 +1707,7 @@ func testAccTopicRuleKinesisConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1727,7 +1727,7 @@ data "aws_region" "current" {} data "aws_partition" "current" {} -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1744,7 +1744,7 @@ func testAccTopicRuleRepublishConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1762,7 +1762,7 @@ func testAccTopicRuleRepublishWithQoSConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1781,7 +1781,7 @@ func testAccTopicRuleS3Config(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1802,7 +1802,7 @@ func testAccTopicRuleSNSConfig(rName string) string { fmt.Sprintf(` data "aws_region" "current" {} -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1820,7 +1820,7 @@ func testAccTopicRuleSQSConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1839,7 +1839,7 @@ func testAccTopicRuleStepFunctionsConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1858,7 +1858,7 @@ func testAccTopicRuleTimestreamConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" @@ -1887,7 +1887,7 @@ func testAccTopicRuleErrorActionConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), fmt.Sprintf(` -resource "aws_iot_topic_rule" "rule" { +resource "aws_iot_topic_rule" "test" { name = %[1]q enabled = true sql = "SELECT * FROM 'topic/test'" From 2b8b7ffcb31277ca10ba7bd18b4b062763b9201e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 12:10:49 -0400 Subject: [PATCH 67/87] 'aws_iam_role.iot_role.arn' -> 'aws_iam_role.test.arn'. --- internal/service/iot/topic_rule_test.go | 98 ++++++++++++------------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 57dc6076d1b..6625669e97c 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -680,7 +680,7 @@ func TestAccIoTTopicRule_kafka(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "kafka.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "kafka.*", map[string]string{ "bootstrap_servers": "b-1.localhost:9094", - "ssl_keystore": "$${get_secret('secret_name', 'SecretBinary', '', '${aws_iam_role.iot_role.arn}')}", + "ssl_keystore": "$${get_secret('secret_name', 'SecretBinary', '', '${aws_iam_role.test.arn}')}", "ssl_keystore_password": "password", "topic": "fake_topic", }), @@ -1350,48 +1350,44 @@ func testAccTopicRuleRoleConfig(rName string) string { return fmt.Sprintf(` data "aws_partition" "current" {} -resource "aws_iam_role" "iot_role" { - name = "test_role_%[1]s" +resource "aws_iam_role" "test" { + name = %[1]q assume_role_policy = < Date: Wed, 4 May 2022 12:16:17 -0400 Subject: [PATCH 68/87] r/aws_iot_topic_rule: Tidy up documentation. --- website/docs/r/iot_topic_rule.html.markdown | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/website/docs/r/iot_topic_rule.html.markdown b/website/docs/r/iot_topic_rule.html.markdown index 4ec08882ff2..319760c7a52 100644 --- a/website/docs/r/iot_topic_rule.html.markdown +++ b/website/docs/r/iot_topic_rule.html.markdown @@ -145,6 +145,17 @@ The `firehose` object takes the following arguments: * `role_arn` - (Required) The IAM role ARN that grants access to the Amazon Kinesis Firehose stream. * `separator` - (Optional) A character separator that is used to separate records written to the Firehose stream. Valid values are: '\n' (newline), '\t' (tab), '\r\n' (Windows newline), ',' (comma). +The `iot_analytics` object takes the following arguments: + +* `channel_name` - (Required) Name of AWS IOT Analytics channel. +* `role_arn` - (Required) The ARN of the IAM role that grants access. + +The `iot_events` object takes the following arguments: + +* `input_name` - (Required) The name of the AWS IoT Events input. +* `role_arn` - (Required) The ARN of the IAM role that grants access. +* `message_id` - (Optional) Use this to ensure that only one input (message) with a given messageId is processed by an AWS IoT Events detector. + The `kinesis` object takes the following arguments: * `partition_key` - (Optional) The partition key. @@ -197,17 +208,6 @@ The `timestream` object takes the following arguments: * `unit` - (Required) The precision of the timestamp value that results from the expression described in value. Valid values: `SECONDS`, `MILLISECONDS`, `MICROSECONDS`, `NANOSECONDS`. * `value` - (Required) An expression that returns a long epoch time value. -The `iot_analytics` object takes the following arguments: - -* `channel_name` - (Required) Name of AWS IOT Analytics channel. -* `role_arn` - (Required) The ARN of the IAM role that grants access. - -The `iot_events` object takes the following arguments: - -* `input_name` - (Required) The name of the AWS IoT Events input. -* `role_arn` - (Required) The ARN of the IAM role that grants access. -* `message_id` - (Optional) Use this to ensure that only one input (message) with a given messageId is processed by an AWS IoT Events detector. - ## Attributes Reference In addition to all arguments above, the following attributes are exported: From b149e37b0b7160e1c3dbcf8d77be060d9b3f8579 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 13:15:16 -0400 Subject: [PATCH 69/87] r/aws_iot_topic_rule: Add 'http' and 'error_action.http'. --- internal/service/iot/topic_rule.go | 184 +++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index f85e9da3a3d..6b4ab82eba2 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -455,6 +455,42 @@ func ResourceTopicRule() *schema.Resource { }, ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, + "http": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "confirmation_url": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + "http_header": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + }, + }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, + }, "iot_analytics": { Type: schema.TypeList, Optional: true, @@ -872,6 +908,40 @@ func ResourceTopicRule() *schema.Resource { }, }, }, + "http": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "confirmation_url": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + "http_header": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + }, + }, + }, "iot_analytics": { Type: schema.TypeSet, Optional: true, @@ -1272,6 +1342,7 @@ var topicRuleErrorActionExactlyOneOf = []string{ "error_action.0.dynamodbv2", "error_action.0.elasticsearch", "error_action.0.firehose", + "error_action.0.http", "error_action.0.iot_analytics", "error_action.0.iot_events", "error_action.0.kafka", @@ -1377,6 +1448,10 @@ func resourceTopicRuleRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("setting firehose: %w", err) } + if err := d.Set("http", flattenIotHttpActions(output.Rule.Actions)); err != nil { + return fmt.Errorf("setting http: %w", err) + } + if err := d.Set("iot_analytics", flattenIotIotAnalyticsActions(output.Rule.Actions)); err != nil { return fmt.Errorf("setting iot_analytics: %w", err) } @@ -1708,6 +1783,42 @@ func expandIotFirehoseAction(tfList []interface{}) *iot.FirehoseAction { return apiObject } +func expandIotHttpAction(tfList []interface{}) *iot.HttpAction { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + apiObject := &iot.HttpAction{} + tfMap := tfList[0].(map[string]interface{}) + + if v, ok := tfMap["url"].(string); ok && v != "" { + apiObject.Url = aws.String(v) + } + + if v, ok := tfMap["confirmation_url"].(string); ok && v != "" { + apiObject.ConfirmationUrl = aws.String(v) + } + + if v, ok := tfMap["http_header"].([]interface{}); ok { + headerObjs := []*iot.HttpActionHeader{} + for _, val := range v { + if m, ok := val.(map[string]interface{}); ok { + headerObj := &iot.HttpActionHeader{} + if v, ok := m["key"].(string); ok && v != "" { + headerObj.Key = aws.String(v) + } + if v, ok := m["value"].(string); ok && v != "" { + headerObj.Value = aws.String(v) + } + headerObjs = append(headerObjs, headerObj) + } + } + apiObject.Headers = headerObjs + } + + return apiObject +} + func expandIotIotAnalyticsAction(tfList []interface{}) *iot.IotAnalyticsAction { if len(tfList) == 0 || tfList[0] == nil { return nil @@ -2178,6 +2289,17 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { actions = append(actions, &iot.Action{Firehose: action}) } + // Legacy root attribute handling + for _, tfMapRaw := range d.Get("http").(*schema.Set).List() { + action := expandIotHttpAction([]interface{}{tfMapRaw}) + + if action == nil { + continue + } + + actions = append(actions, &iot.Action{Http: action}) + } + // Legacy root attribute handling for _, tfMapRaw := range d.Get("iot_analytics").(*schema.Set).List() { action := expandIotIotAnalyticsAction([]interface{}{tfMapRaw}) @@ -2380,6 +2502,16 @@ func expandIotTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { iotErrorAction = &iot.Action{Firehose: action} } + case "http": + for _, tfMapRaw := range v.([]interface{}) { + action := expandIotHttpAction([]interface{}{tfMapRaw}) + + if action == nil { + continue + } + + iotErrorAction = &iot.Action{Http: action} + } case "iot_analytics": for _, tfMapRaw := range v.([]interface{}) { action := expandIotIotAnalyticsAction([]interface{}{tfMapRaw}) @@ -2821,6 +2953,54 @@ func flattenIotFirehoseAction(apiObject *iot.FirehoseAction) []interface{} { return []interface{}{tfMap} } +// Legacy root attribute handling +func flattenIotHttpActions(actions []*iot.Action) []interface{} { + results := make([]interface{}, 0) + + for _, action := range actions { + if action == nil { + continue + } + + if v := action.Http; v != nil { + results = append(results, flattenIotHttpAction(v)...) + } + } + + return results +} + +func flattenIotHttpAction(apiObject *iot.HttpAction) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := make(map[string]interface{}) + + if v := apiObject.Url; v != nil { + tfMap["url"] = aws.StringValue(v) + } + + if v := apiObject.ConfirmationUrl; v != nil { + tfMap["confirmation_url"] = aws.StringValue(v) + } + + if v := apiObject.Headers; v != nil { + headers := []map[string]string{} + + for _, h := range v { + m := map[string]string{ + "key": aws.StringValue(h.Key), + "value": aws.StringValue(h.Value), + } + headers = append(headers, m) + } + tfMap["http_header"] = headers + } + + return []interface{}{tfMap} +} + // Legacy root attribute handling func flattenIotIotAnalyticsActions(actions []*iot.Action) []interface{} { results := make([]interface{}, 0) @@ -3437,6 +3617,10 @@ func flattenIotErrorAction(errorAction *iot.Action) []map[string]interface{} { results = append(results, map[string]interface{}{"firehose": flattenIotFirehoseActions(input)}) return results } + if errorAction.Http != nil { + results = append(results, map[string]interface{}{"http": flattenIotHttpActions(input)}) + return results + } if errorAction.IotAnalytics != nil { results = append(results, map[string]interface{}{"iot_analytics": flattenIotIotAnalyticsActions(input)}) return results From 349c98519a3c998f4d1300692841801120cecbb9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 13:16:45 -0400 Subject: [PATCH 70/87] r/aws_iot_topic_rule: Add 'http' and 'error_action.http' to documentation. --- website/docs/r/iot_topic_rule.html.markdown | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/website/docs/r/iot_topic_rule.html.markdown b/website/docs/r/iot_topic_rule.html.markdown index 319760c7a52..5a06b1d0c28 100644 --- a/website/docs/r/iot_topic_rule.html.markdown +++ b/website/docs/r/iot_topic_rule.html.markdown @@ -88,7 +88,7 @@ EOF * `enabled` - (Required) Specifies whether the rule is enabled. * `sql` - (Required) The SQL statement used to query the topic. For more information, see AWS IoT SQL Reference (http://docs.aws.amazon.com/iot/latest/developerguide/iot-rules.html#aws-iot-sql-reference) in the AWS IoT Developer Guide. * `sql_version` - (Required) The version of the SQL rules engine to use when evaluating the rule. -* `error_action` - (Optional) Configuration block with error action to be associated with the rule. See the documentation for `cloudwatch_alarm`, `cloudwatch_logs`, `cloudwatch_metric`, `dynamodb`, `dynamodbv2`, `elasticsearch`, `firehose`, `iot_analytics`, `iot_events`, `kinesis`, `lambda`, `republish`, `s3`, `step_functions`, `sns`, `sqs`, `timestream` configuration blocks for further configuration details. +* `error_action` - (Optional) Configuration block with error action to be associated with the rule. See the documentation for `cloudwatch_alarm`, `cloudwatch_logs`, `cloudwatch_metric`, `dynamodb`, `dynamodbv2`, `elasticsearch`, `firehose`, `http`, `iot_analytics`, `iot_events`, `kinesis`, `lambda`, `republish`, `s3`, `sns`, `sqs`, `step_functions`, `timestream` configuration blocks for further configuration details. * `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. The `cloudwatch_alarm` object takes the following arguments: @@ -145,6 +145,17 @@ The `firehose` object takes the following arguments: * `role_arn` - (Required) The IAM role ARN that grants access to the Amazon Kinesis Firehose stream. * `separator` - (Optional) A character separator that is used to separate records written to the Firehose stream. Valid values are: '\n' (newline), '\t' (tab), '\r\n' (Windows newline), ',' (comma). +The `http` object takes the following arguments: + +* `url` - (Required) The HTTPS URL. +* `confirmation_url` - (Optional) The HTTPS URL used to verify ownership of `url`. +* `http_header` - (Optional) Custom HTTP header IoT Core should send. It is possible to define more than one custom header. + +The `http_header` object takes the following arguments: + +* `key` - (Required) The name of the HTTP header. +* `value` - (Required) The value of the HTTP header. + The `iot_analytics` object takes the following arguments: * `channel_name` - (Required) Name of AWS IOT Analytics channel. From 84319d5ef137666d23235d026ffed75bd1c4e19e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 13:38:17 -0400 Subject: [PATCH 71/87] r/aws_iot_topic_rule: Add 'TestAccIoTTopicRule_http'. Acceptance test output: % make testacc TESTARGS='-run=TestAccIoTTopicRule_http' PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run=TestAccIoTTopicRule_http -timeout 180m === RUN TestAccIoTTopicRule_http === PAUSE TestAccIoTTopicRule_http === CONT TestAccIoTTopicRule_http --- PASS: TestAccIoTTopicRule_http (51.44s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 55.018s --- internal/service/iot/topic_rule_test.go | 297 +++++++++++++++++++++++- 1 file changed, 296 insertions(+), 1 deletion(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 6625669e97c..188f15f57a5 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -39,6 +39,7 @@ func TestAccIoTTopicRule_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "enabled", "true"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -159,6 +160,7 @@ func TestAccIoTTopicRule_cloudWatchAlarm(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -210,6 +212,7 @@ func TestAccIoTTopicRule_cloudWatchLogs(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "enabled", "false"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -260,6 +263,7 @@ func TestAccIoTTopicRule_cloudWatchMetric(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -311,6 +315,7 @@ func TestAccIoTTopicRule_dynamoDB(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -352,6 +357,7 @@ func TestAccIoTTopicRule_dynamoDB(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -395,6 +401,7 @@ func TestAccIoTTopicRule_dynamoDBv2(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -439,6 +446,7 @@ func TestAccIoTTopicRule_elasticSearch(t *testing.T) { }), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -492,6 +500,7 @@ func TestAccIoTTopicRule_firehose(t *testing.T) { resource.TestCheckTypeSetElemNestedAttrs(resourceName, "firehose.*", map[string]string{ "delivery_stream_name": "mystream3", }), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -540,6 +549,7 @@ func TestAccIoTTopicRule_Firehose_separator(t *testing.T) { "delivery_stream_name": "mystream", "separator": "\n", }), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -561,7 +571,198 @@ func TestAccIoTTopicRule_Firehose_separator(t *testing.T) { { Config: testAccTopicRuleFirehoseSeparatorConfig(rName, ","), Check: resource.ComposeTestCheckFunc( - testAccCheckTopicRuleExists("aws_iot_topic_rule.rule"), + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "firehose.*", map[string]string{ + "delivery_stream_name": "mystream", + "separator": ",", + }), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), + ), + }, + }, + }) +} + +func TestAccIoTTopicRule_http(t *testing.T) { + rName := testAccTopicRuleName() + resourceName := "aws_iot_topic_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, iot.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckTopicRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTopicRuleHTTPConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "http.*", map[string]string{ + "confirmation_url": "", + "http_header.#": "0", + "url": "https://example.com/ingress", + }), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccTopicRuleHTTPConfirmationURLConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "http.*", map[string]string{ + "confirmation_url": "https://example.com/", + "http_header.#": "0", + "url": "https://example.com/ingress", + }), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), + ), + }, + { + Config: testAccTopicRuleHTTPHeadersConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "http.*", map[string]string{ + "confirmation_url": "", + "http_header.#": "2", + "http_header.0.key": "X-Header-1", + "http_header.0.value": "v1", + "http_header.1.key": "X-Header-2", + "http_header.1.value": "v2", + "url": "https://example.com/ingress", + }), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), + ), + }, + { + Config: testAccTopicRuleHTTPErrorActionConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.cloudwatch_alarm.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.cloudwatch_logs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.cloudwatch_metric.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.dynamodb.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.dynamodbv2.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.elasticsearch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.http.#", "1"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.http.0.url", "https://example.com/error-ingress"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.timestream.#", "0"), + resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "http.*", map[string]string{ + "confirmation_url": "", + "http_header.#": "0", + "url": "https://example.com/ingress", + }), + resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), + resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), + resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), + resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), + resource.TestCheckResourceAttr(resourceName, "republish.#", "0"), + resource.TestCheckResourceAttr(resourceName, "s3.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "sqs.#", "0"), + resource.TestCheckResourceAttr(resourceName, "step_functions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "timestream.#", "0"), ), }, }, @@ -590,6 +791,7 @@ func TestAccIoTTopicRule_IoT_analytics(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "iot_analytics.*", map[string]string{ "channel_name": "fakedata", @@ -632,6 +834,7 @@ func TestAccIoTTopicRule_IoT_events(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "iot_events.*", map[string]string{ @@ -677,6 +880,7 @@ func TestAccIoTTopicRule_kafka(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "kafka.*", map[string]string{ "bootstrap_servers": "b-1.localhost:9094", @@ -725,6 +929,7 @@ func TestAccIoTTopicRule_kinesis(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -772,6 +977,7 @@ func TestAccIoTTopicRule_lambda(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -816,6 +1022,7 @@ func TestAccIoTTopicRule_republish(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -864,6 +1071,7 @@ func TestAccIoTTopicRule_republishWithQos(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -912,6 +1120,7 @@ func TestAccIoTTopicRule_s3(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -960,6 +1169,7 @@ func TestAccIoTTopicRule_sns(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -1004,6 +1214,7 @@ func TestAccIoTTopicRule_sqs(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -1052,6 +1263,7 @@ func TestAccIoTTopicRule_Step_functions(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -1100,6 +1312,7 @@ func TestAccIoTTopicRule_Timestream(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -1162,6 +1375,7 @@ func TestAccIoTTopicRule_errorAction(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "error_action.0.dynamodbv2.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.http.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.kafka.#", "0"), @@ -1175,6 +1389,7 @@ func TestAccIoTTopicRule_errorAction(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "error_action.0.step_functions.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.timestream.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -1223,6 +1438,7 @@ func TestAccIoTTopicRule_updateKinesisErrorAction(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -1257,6 +1473,7 @@ func TestAccIoTTopicRule_updateKinesisErrorAction(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "error_action.0.dynamodbv2.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.elasticsearch.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "error_action.0.http.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.kafka.#", "0"), @@ -1270,6 +1487,7 @@ func TestAccIoTTopicRule_updateKinesisErrorAction(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "error_action.0.step_functions.#", "0"), resource.TestCheckResourceAttr(resourceName, "error_action.0.timestream.#", "0"), resource.TestCheckResourceAttr(resourceName, "firehose.#", "0"), + resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_analytics.#", "0"), resource.TestCheckResourceAttr(resourceName, "iot_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "0"), @@ -1639,6 +1857,83 @@ resource "aws_iot_topic_rule" "test" { `, rName, separator)) } +func testAccTopicRuleHTTPConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_iot_topic_rule" "test" { + name = %[1]q + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + http { + url = "https://example.com/ingress" + } +} +`, rName) +} + +func testAccTopicRuleHTTPConfirmationURLConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_iot_topic_rule" "test" { + name = %[1]q + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + http { + url = "https://example.com/ingress" + confirmation_url = "https://example.com/" + } +} +`, rName) +} + +func testAccTopicRuleHTTPHeadersConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_iot_topic_rule" "test" { + name = %[1]q + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + http { + url = "https://example.com/ingress" + + http_header { + key = "X-Header-1" + value = "v1" + } + + http_header { + key = "X-Header-2" + value = "v2" + } + } +} +`, rName) +} + +func testAccTopicRuleHTTPErrorActionConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_iot_topic_rule" "test" { + name = %[1]q + enabled = true + sql = "SELECT * FROM 'topic/test'" + sql_version = "2015-10-08" + + http { + url = "https://example.com/ingress" + } + + error_action { + http { + url = "https://example.com/error-ingress" + } + } +} +`, rName) +} + func testAccTopicRuleIoTAnalyticsConfig(rName string) string { return acctest.ConfigCompose( testAccTopicRuleRoleConfig(rName), From 909eb0f1d2c19014a24c9ebb3fcefd48f788104b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 15:15:20 -0400 Subject: [PATCH 72/87] r/aws_iot_topic_rule_destination: New resource. --- .changelog/24395.txt | 4 + internal/provider/provider.go | 1 + internal/service/iot/find.go | 20 ++ internal/service/iot/topic_rule.go | 3 +- .../service/iot/topic_rule_destination.go | 320 ++++++++++++++++++ 5 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 internal/service/iot/topic_rule_destination.go diff --git a/.changelog/24395.txt b/.changelog/24395.txt index 97652eb1ead..53e26f57ab3 100644 --- a/.changelog/24395.txt +++ b/.changelog/24395.txt @@ -1,3 +1,7 @@ ```release-note:enhancement resource/aws_iot_topic_rule: Add `kafka` and `error_action.kafka` arguments ``` + +```release-note:new-resource +aws_iot_topic_rule_destination +``` \ No newline at end of file diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 42c9e97e499..06d4094666c 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1530,6 +1530,7 @@ func Provider() *schema.Provider { "aws_iot_thing_principal_attachment": iot.ResourceThingPrincipalAttachment(), "aws_iot_thing_type": iot.ResourceThingType(), "aws_iot_topic_rule": iot.ResourceTopicRule(), + "aws_iot_topic_rule_destination": iot.ResourceTopicRuleDestination(), "aws_msk_cluster": kafka.ResourceCluster(), "aws_msk_configuration": kafka.ResourceConfiguration(), diff --git a/internal/service/iot/find.go b/internal/service/iot/find.go index 504b698662d..be6e2ff5a33 100644 --- a/internal/service/iot/find.go +++ b/internal/service/iot/find.go @@ -1,6 +1,8 @@ package iot import ( + "context" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/iot" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" @@ -170,3 +172,21 @@ func FindTopicRuleByName(conn *iot.IoT, name string) (*iot.GetTopicRuleOutput, e return output, nil } + +func FindTopicRuleDestinationByARN(ctx context.Context, conn *iot.IoT, arn string) (*iot.TopicRuleDestination, error) { + input := &iot.GetTopicRuleDestinationInput{ + Arn: aws.String(arn), + } + + output, err := conn.GetTopicRuleDestinationWithContext(ctx, input) + + if err != nil { + return nil, err + } + + if output == nil || output.TopicRuleDestination == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.TopicRuleDestination, nil +} diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index 6b4ab82eba2..7172eb6a4ab 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -1381,6 +1381,7 @@ func resourceTopicRuleCreate(d *schema.ResourceData, meta interface{}) error { TopicRulePayload: expandIotTopicRulePayload(d), } + log.Printf("[INFO] Creating IoT Topic Rule: %s", input) _, err := tfresource.RetryWhenAWSErrMessageContains(tfiam.PropagationTimeout, func() (interface{}, error) { return conn.CreateTopicRule(input) @@ -1404,7 +1405,7 @@ func resourceTopicRuleRead(d *schema.ResourceData, meta interface{}) error { output, err := FindTopicRuleByName(conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { - log.Printf("[WARN]IoT Topic Rule %s not found, removing from state", d.Id()) + log.Printf("[WARN] IoT Topic Rule %s not found, removing from state", d.Id()) d.SetId("") return nil } diff --git a/internal/service/iot/topic_rule_destination.go b/internal/service/iot/topic_rule_destination.go new file mode 100644 index 00000000000..0b773800cc3 --- /dev/null +++ b/internal/service/iot/topic_rule_destination.go @@ -0,0 +1,320 @@ +package iot + +import ( + "context" + "errors" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iot" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/flex" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func ResourceTopicRuleDestination() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceTopicRuleDestinationCreate, + ReadWithoutTimeout: resourceTopicRuleDestinationRead, + UpdateWithoutTimeout: resourceTopicRuleDestinationUpdate, + DeleteWithoutTimeout: resourceTopicRuleDestinationDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "http_url_configuration": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "confirmation_url": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + }, + }, + }, + "vpc_configuration": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "security_groups": { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "subnet_ids": { + Type: schema.TypeSet, + Required: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: verify.ValidARN, + }, + "vpc_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, + }, + } +} + +func resourceTopicRuleDestinationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).IoTConn + + input := &iot.CreateTopicRuleDestinationInput{ + DestinationConfiguration: &iot.TopicRuleDestinationConfiguration{}, + } + + if v, ok := d.GetOk("http_url_configuration"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.DestinationConfiguration.HttpUrlConfiguration = expandHttpUrlDestinationConfiguration(v.([]interface{})[0].(map[string]interface{})) + } + + if v, ok := d.GetOk("vpc_configuration"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.DestinationConfiguration.VpcConfiguration = expandVpcDestinationConfiguration(v.([]interface{})[0].(map[string]interface{})) + } + + log.Printf("[INFO] Creating IoT Topic Rule Destination: %s", input) + output, err := conn.CreateTopicRuleDestinationWithContext(ctx, input) + + if err != nil { + return diag.Errorf("creating IoT Topic Rule Destination: %s", err) + } + + d.SetId(aws.StringValue(output.TopicRuleDestination.Arn)) + + if _, err := waitTopicRuleDestinationCreated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return diag.Errorf("waiting for IoT Topic Rule Destination (%s) create: %s", d.Id(), err) + } + + return resourceTopicRuleDestinationRead(ctx, d, meta) +} + +func resourceTopicRuleDestinationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).IoTConn + + output, err := FindTopicRuleDestinationByARN(ctx, conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] IoT Topic Rule Destination %s not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return diag.Errorf("reading IoT Topic Rule Destination (%s): %s", d.Id(), err) + } + + if output.HttpUrlProperties != nil { + if err := d.Set("http_url_configuration", []interface{}{flattenHttpUrlDestinationProperties(output.HttpUrlProperties)}); err != nil { + return diag.Errorf("setting http_url_configuration: %s", err) + } + } else { + d.Set("http_url_configuration", nil) + } + if output.VpcProperties != nil { + if err := d.Set("vpc_configuration", []interface{}{flattenVpcDestinationProperties(output.VpcProperties)}); err != nil { + return diag.Errorf("setting vpc_configuration: %s", err) + } + } else { + d.Set("vpc_configuration", nil) + } + + return nil +} + +func resourceTopicRuleDestinationUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return resourceTopicRuleDestinationRead(ctx, d, meta) +} + +func resourceTopicRuleDestinationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).IoTConn + + log.Printf("[INFO] Deleting IoT Topic Rule Destination: %s", d.Id()) + _, err := conn.DeleteTopicRuleDestinationWithContext(ctx, &iot.DeleteTopicRuleDestinationInput{ + Arn: aws.String(d.Id()), + }) + + if err != nil { + return diag.Errorf("deleting IoT Topic Rule Destination: %s", err) + } + + if _, err := waitTopicRuleDestinationDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + return diag.Errorf("waiting for IoT Topic Rule Destination (%s) delete: %s", d.Id(), err) + } + + return nil +} + +func expandHttpUrlDestinationConfiguration(tfMap map[string]interface{}) *iot.HttpUrlDestinationConfiguration { + if tfMap == nil { + return nil + } + + apiObject := &iot.HttpUrlDestinationConfiguration{} + + if v, ok := tfMap["confirmation_url"].(string); ok && v != "" { + apiObject.ConfirmationUrl = aws.String(v) + } + + return apiObject +} + +func expandVpcDestinationConfiguration(tfMap map[string]interface{}) *iot.VpcDestinationConfiguration { + if tfMap == nil { + return nil + } + + apiObject := &iot.VpcDestinationConfiguration{} + + if v, ok := tfMap["role_arn"].(string); ok && v != "" { + apiObject.RoleArn = aws.String(v) + } + + if v, ok := tfMap["security_groups"].(*schema.Set); ok && v.Len() > 0 { + apiObject.SecurityGroups = flex.ExpandStringSet(v) + } + + if v, ok := tfMap["subnet_ids"].(*schema.Set); ok && v.Len() > 0 { + apiObject.SubnetIds = flex.ExpandStringSet(v) + } + + if v, ok := tfMap["vpc_id"].(string); ok && v != "" { + apiObject.VpcId = aws.String(v) + } + + return apiObject +} + +func flattenHttpUrlDestinationProperties(apiObject *iot.HttpUrlDestinationProperties) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.ConfirmationUrl; v != nil { + tfMap["confirmation_url"] = aws.StringValue(v) + } + + return tfMap +} + +func flattenVpcDestinationProperties(apiObject *iot.VpcDestinationProperties) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.RoleArn; v != nil { + tfMap["role_arn"] = aws.StringValue(v) + } + + if v := apiObject.SecurityGroups; v != nil { + tfMap["security_groups"] = aws.StringValueSlice(v) + } + + if v := apiObject.SubnetIds; v != nil { + tfMap["subnet_ids"] = aws.StringValueSlice(v) + } + + if v := apiObject.VpcId; v != nil { + tfMap["vpc_id"] = aws.StringValue(v) + } + + return tfMap +} + +func statusTopicRuleDestination(ctx context.Context, conn *iot.IoT, arn string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := FindTopicRuleDestinationByARN(ctx, conn, arn) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} + +func waitTopicRuleDestinationCreated(ctx context.Context, conn *iot.IoT, arn string, timeout time.Duration) (*iot.TopicRuleDestination, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{iot.TopicRuleDestinationStatusInProgress}, + Target: []string{iot.TopicRuleDestinationStatusEnabled}, + Refresh: statusTopicRuleDestination(ctx, conn, arn), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*iot.TopicRuleDestination); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusReason))) + + return output, err + } + + return nil, err +} + +func waitTopicRuleDestinationDeleted(ctx context.Context, conn *iot.IoT, arn string, timeout time.Duration) (*iot.TopicRuleDestination, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{iot.TopicRuleDestinationStatusDeleting}, + Target: []string{}, + Refresh: statusTopicRuleDestination(ctx, conn, arn), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*iot.TopicRuleDestination); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusReason))) + + return output, err + } + + return nil, err +} From d7ef866dce049a89615f2182466d4a490a7324b9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 15:42:15 -0400 Subject: [PATCH 73/87] r/aws_iot_topic_rule_destination: Start to add acceptance tests. --- .../iot/topic_rule_destination_test.go | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 internal/service/iot/topic_rule_destination_test.go diff --git a/internal/service/iot/topic_rule_destination_test.go b/internal/service/iot/topic_rule_destination_test.go new file mode 100644 index 00000000000..ee6041167a7 --- /dev/null +++ b/internal/service/iot/topic_rule_destination_test.go @@ -0,0 +1,124 @@ +package iot_test + +import ( + "context" + "fmt" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/service/iot" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfiot "github.com/hashicorp/terraform-provider-aws/internal/service/iot" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" +) + +func TestAccIoTTopicRuleDestination_basic(t *testing.T) { + url := fmt.Sprintf("https://%s.example.com/", acctest.RandomSubdomain()) + resourceName := "aws_iot_topic_rule_destination.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, iot.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckTopicRuleDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTopicRuleDestinationConfig(url), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleDestinationExists(resourceName), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "iot", regexp.MustCompile(`ruledestination/http/.+`)), + resource.TestCheckResourceAttr(resourceName, "http_url_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "http_url_configuration.0.confirmation_url", url), + resource.TestCheckResourceAttr(resourceName, "vpc_configuration.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIoTTopicRuleDestination_disappears(t *testing.T) { + url := fmt.Sprintf("https://%s.example.com/", acctest.RandomSubdomain()) + resourceName := "aws_iot_topic_rule_destination.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, iot.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckTopicRuleDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTopicRuleDestinationConfig(url), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleDestinationExists(resourceName), + acctest.CheckResourceDisappears(acctest.Provider, tfiot.ResourceTopicRuleDestination(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckTopicRuleDestinationDestroy(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_iot_topic_rule_destination" { + continue + } + + _, err := tfiot.FindTopicRuleDestinationByARN(context.TODO(), conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("IoT Topic Rule Destination %s still exists", rs.Primary.ID) + } + + return nil +} + +func testAccCheckTopicRuleDestinationExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No IoT Topic Rule Destination ID is set") + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn + + _, err := tfiot.FindTopicRuleDestinationByARN(context.TODO(), conn, rs.Primary.ID) + + if err != nil { + return err + } + + return nil + } +} + +func testAccTopicRuleDestinationConfig(url string) string { + return fmt.Sprintf(` +resource "aws_iot_topic_rule_destination" "test" { + http_url_configuration { + confirmation_url = %[1]q + } +} +`, url) +} From 114c17973540ca4cbc641e83b64631c008a08da2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 16:44:27 -0400 Subject: [PATCH 74/87] r/aws_iot_topic_rule_destination: Remove 'http_url_configuration' argument. --- .../service/iot/topic_rule_destination.go | 75 +++---------------- .../iot/topic_rule_destination_test.go | 48 ++++++++---- 2 files changed, 47 insertions(+), 76 deletions(-) diff --git a/internal/service/iot/topic_rule_destination.go b/internal/service/iot/topic_rule_destination.go index 0b773800cc3..f91ca284f31 100644 --- a/internal/service/iot/topic_rule_destination.go +++ b/internal/service/iot/topic_rule_destination.go @@ -11,9 +11,9 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/flex" + tfiam "github.com/hashicorp/terraform-provider-aws/internal/service/iam" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" ) @@ -30,7 +30,7 @@ func ResourceTopicRuleDestination() *schema.Resource { }, Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(5 * time.Minute), + Create: schema.DefaultTimeout(15 * time.Minute), Update: schema.DefaultTimeout(5 * time.Minute), Delete: schema.DefaultTimeout(5 * time.Minute), }, @@ -45,29 +45,19 @@ func ResourceTopicRuleDestination() *schema.Resource { Optional: true, Default: true, }, - "http_url_configuration": { + "vpc_configuration": { Type: schema.TypeList, - Optional: true, + Required: true, ForceNew: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "confirmation_url": { + "role_arn": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validation.IsURLWithHTTPS, + ValidateFunc: verify.ValidARN, }, - }, - }, - }, - "vpc_configuration": { - Type: schema.TypeList, - Optional: true, - ForceNew: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ "security_groups": { Type: schema.TypeSet, Optional: true, @@ -80,12 +70,6 @@ func ResourceTopicRuleDestination() *schema.Resource { ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: verify.ValidARN, - }, "vpc_id": { Type: schema.TypeString, Required: true, @@ -105,22 +89,22 @@ func resourceTopicRuleDestinationCreate(ctx context.Context, d *schema.ResourceD DestinationConfiguration: &iot.TopicRuleDestinationConfiguration{}, } - if v, ok := d.GetOk("http_url_configuration"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { - input.DestinationConfiguration.HttpUrlConfiguration = expandHttpUrlDestinationConfiguration(v.([]interface{})[0].(map[string]interface{})) - } - if v, ok := d.GetOk("vpc_configuration"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.DestinationConfiguration.VpcConfiguration = expandVpcDestinationConfiguration(v.([]interface{})[0].(map[string]interface{})) } log.Printf("[INFO] Creating IoT Topic Rule Destination: %s", input) - output, err := conn.CreateTopicRuleDestinationWithContext(ctx, input) + outputRaw, err := tfresource.RetryWhenAWSErrMessageContains(tfiam.PropagationTimeout, + func() (interface{}, error) { + return conn.CreateTopicRuleDestinationWithContext(ctx, input) + }, + iot.ErrCodeInvalidRequestException, "sts:AssumeRole") if err != nil { return diag.Errorf("creating IoT Topic Rule Destination: %s", err) } - d.SetId(aws.StringValue(output.TopicRuleDestination.Arn)) + d.SetId(aws.StringValue(outputRaw.(*iot.CreateTopicRuleDestinationOutput).TopicRuleDestination.Arn)) if _, err := waitTopicRuleDestinationCreated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return diag.Errorf("waiting for IoT Topic Rule Destination (%s) create: %s", d.Id(), err) @@ -144,13 +128,6 @@ func resourceTopicRuleDestinationRead(ctx context.Context, d *schema.ResourceDat return diag.Errorf("reading IoT Topic Rule Destination (%s): %s", d.Id(), err) } - if output.HttpUrlProperties != nil { - if err := d.Set("http_url_configuration", []interface{}{flattenHttpUrlDestinationProperties(output.HttpUrlProperties)}); err != nil { - return diag.Errorf("setting http_url_configuration: %s", err) - } - } else { - d.Set("http_url_configuration", nil) - } if output.VpcProperties != nil { if err := d.Set("vpc_configuration", []interface{}{flattenVpcDestinationProperties(output.VpcProperties)}); err != nil { return diag.Errorf("setting vpc_configuration: %s", err) @@ -185,20 +162,6 @@ func resourceTopicRuleDestinationDelete(ctx context.Context, d *schema.ResourceD return nil } -func expandHttpUrlDestinationConfiguration(tfMap map[string]interface{}) *iot.HttpUrlDestinationConfiguration { - if tfMap == nil { - return nil - } - - apiObject := &iot.HttpUrlDestinationConfiguration{} - - if v, ok := tfMap["confirmation_url"].(string); ok && v != "" { - apiObject.ConfirmationUrl = aws.String(v) - } - - return apiObject -} - func expandVpcDestinationConfiguration(tfMap map[string]interface{}) *iot.VpcDestinationConfiguration { if tfMap == nil { return nil @@ -225,20 +188,6 @@ func expandVpcDestinationConfiguration(tfMap map[string]interface{}) *iot.VpcDes return apiObject } -func flattenHttpUrlDestinationProperties(apiObject *iot.HttpUrlDestinationProperties) map[string]interface{} { - if apiObject == nil { - return nil - } - - tfMap := map[string]interface{}{} - - if v := apiObject.ConfirmationUrl; v != nil { - tfMap["confirmation_url"] = aws.StringValue(v) - } - - return tfMap -} - func flattenVpcDestinationProperties(apiObject *iot.VpcDestinationProperties) map[string]interface{} { if apiObject == nil { return nil diff --git a/internal/service/iot/topic_rule_destination_test.go b/internal/service/iot/topic_rule_destination_test.go index ee6041167a7..2e61532fd7b 100644 --- a/internal/service/iot/topic_rule_destination_test.go +++ b/internal/service/iot/topic_rule_destination_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/aws/aws-sdk-go/service/iot" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" @@ -16,7 +17,7 @@ import ( ) func TestAccIoTTopicRuleDestination_basic(t *testing.T) { - url := fmt.Sprintf("https://%s.example.com/", acctest.RandomSubdomain()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_topic_rule_destination.test" resource.ParallelTest(t, resource.TestCase{ @@ -26,13 +27,15 @@ func TestAccIoTTopicRuleDestination_basic(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestinationDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRuleDestinationConfig(url), + Config: testAccTopicRuleDestinationConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleDestinationExists(resourceName), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "iot", regexp.MustCompile(`ruledestination/http/.+`)), - resource.TestCheckResourceAttr(resourceName, "http_url_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "http_url_configuration.0.confirmation_url", url), - resource.TestCheckResourceAttr(resourceName, "vpc_configuration.#", "0"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "iot", regexp.MustCompile(`ruledestination/vpc/.+`)), + resource.TestCheckResourceAttr(resourceName, "vpc_configuration.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "vpc_configuration.0.role_arn"), + resource.TestCheckResourceAttr(resourceName, "vpc_configuration.0.security_groups.#", "1"), + resource.TestCheckResourceAttr(resourceName, "vpc_configuration.0.subnet_ids.#", "2"), + resource.TestCheckResourceAttrSet(resourceName, "vpc_configuration.0.vpc_id"), ), }, { @@ -45,7 +48,7 @@ func TestAccIoTTopicRuleDestination_basic(t *testing.T) { } func TestAccIoTTopicRuleDestination_disappears(t *testing.T) { - url := fmt.Sprintf("https://%s.example.com/", acctest.RandomSubdomain()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_topic_rule_destination.test" resource.ParallelTest(t, resource.TestCase{ @@ -55,7 +58,7 @@ func TestAccIoTTopicRuleDestination_disappears(t *testing.T) { CheckDestroy: testAccCheckTopicRuleDestinationDestroy, Steps: []resource.TestStep{ { - Config: testAccTopicRuleDestinationConfig(url), + Config: testAccTopicRuleDestinationConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleDestinationExists(resourceName), acctest.CheckResourceDisappears(acctest.Provider, tfiot.ResourceTopicRuleDestination(), resourceName), @@ -113,12 +116,31 @@ func testAccCheckTopicRuleDestinationExists(n string) resource.TestCheckFunc { } } -func testAccTopicRuleDestinationConfig(url string) string { - return fmt.Sprintf(` +func testAccTopicRuleDestinationBaseConfig(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigVpcWithSubnets(2), + testAccTopicRuleRoleConfig(rName), + fmt.Sprintf(` +resource "aws_security_group" "test" { + name = %[1]q + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} +`, rName)) +} + +func testAccTopicRuleDestinationConfig(rName string) string { + return acctest.ConfigCompose(testAccTopicRuleDestinationBaseConfig(rName), ` resource "aws_iot_topic_rule_destination" "test" { - http_url_configuration { - confirmation_url = %[1]q + vpc_configuration { + role_arn = aws_iam_role.test.arn + security_groups = [aws_security_group.test.id] + subnet_ids = aws_subnet.test[*].id + vpc_id = aws_vpc.test.id } } -`, url) +`) } From 6f03891578469b497ff73e45e5bd4bcb6b3eaeed Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 17:05:47 -0400 Subject: [PATCH 75/87] r/aws_iot_topic_rule_destination: Add documentation. --- .../iot_topic_rule_destination.html.markdown | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 website/docs/r/iot_topic_rule_destination.html.markdown diff --git a/website/docs/r/iot_topic_rule_destination.html.markdown b/website/docs/r/iot_topic_rule_destination.html.markdown new file mode 100644 index 00000000000..544fa1f728c --- /dev/null +++ b/website/docs/r/iot_topic_rule_destination.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "IoT Core" +layout: "aws" +page_title: "AWS: aws_iot_topic_rule_destination" +description: |- + Creates and manages an AWS IoT topic rule destination +--- + +# Resource: aws_iot_topic_rule_destination + +## Example Usage + +```terraform +resource "aws_iot_topic_rule_destination" "example" { + vpc_configuration { + role_arn = aws_iam_role.example.arn + security_groups = [aws_security_group.example.id] + subnet_ids = aws_subnet.example[*].id + vpc_id = aws_vpc.example.id + } +} +``` + +## Argument Reference + +* `enabled` - (Optional) Whether or not to enable the destination. Default: `true`. +* `vpc_configuration` - (Required) Configuration of the virtual private cloud (VPC) connection. For more info, see the [AWS documentation](https://docs.aws.amazon.com/iot/latest/developerguide/vpc-rule-action.html). + +The `vpc_configuration` object takes the following arguments: + +* `role_arn` - (Required) The ARN of a role that has permission to create and attach to elastic network interfaces (ENIs). +* `security_groups` - (Optional) The security groups of the VPC destination. +* `subnet_ids` - (Required) The subnet IDs of the VPC destination. +* `vpc_id` - (Required) The ID of the VPC. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The ARN of the topic rule destination + +## Import + +IoT topic rule destinations can be imported using the `arn`, e.g., + +``` +$ terraform import aws_iot_topic_rule_destination.example arn:aws:iot:us-west-2:123456789012:ruledestination/vpc/2ce781c8-68a6-4c52-9c62-63fe489ecc60 +``` \ No newline at end of file From 0aa890c2368355dcd75da5e4e4d626f7c8ffa380 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 17:26:48 -0400 Subject: [PATCH 76/87] r/aws_iot_topic_rule_destination: Add sweeper. --- internal/service/ec2/sweep.go | 1 + internal/service/iot/sweep.go | 53 +++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/internal/service/ec2/sweep.go b/internal/service/ec2/sweep.go index e7883e8f60a..3cfdd29981d 100644 --- a/internal/service/ec2/sweep.go +++ b/internal/service/ec2/sweep.go @@ -208,6 +208,7 @@ func init() { "aws_fsx_ontap_file_system", "aws_fsx_openzfs_file_system", "aws_fsx_windows_file_system", + "aws_iot_topic_rule_destination", "aws_lambda_function", "aws_lb", "aws_memorydb_subnet_group", diff --git a/internal/service/iot/sweep.go b/internal/service/iot/sweep.go index 42336aaee45..bda0ec3434c 100644 --- a/internal/service/iot/sweep.go +++ b/internal/service/iot/sweep.go @@ -67,8 +67,14 @@ func init() { }) resource.AddTestSweepers("aws_iot_topic_rule", &resource.Sweeper{ - Name: "aws_iot_topic_rule", - F: sweepTopicRules, + Name: "aws_iot_topic_rule", + F: sweepTopicRules, + Dependencies: []string{"aws_iot_topic_rule_destination"}, + }) + + resource.AddTestSweepers("aws_iot_topic_rule_destination", &resource.Sweeper{ + Name: "aws_iot_topic_rule_destination", + F: sweepTopicRuleDestinations, }) } @@ -523,3 +529,46 @@ func sweepThingGroups(region string) error { return nil } + +func sweepTopicRuleDestinations(region string) error { + client, err := sweep.SharedRegionalSweepClient(region) + if err != nil { + return fmt.Errorf("error getting client: %w", err) + } + conn := client.(*conns.AWSClient).IoTConn + input := &iot.ListTopicRuleDestinationsInput{} + sweepResources := make([]*sweep.SweepResource, 0) + + err = conn.ListTopicRuleDestinationsPages(input, func(page *iot.ListTopicRuleDestinationsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.DestinationSummaries { + r := ResourceTopicRuleDestination() + d := r.Data(nil) + d.SetId(aws.StringValue(v.Arn)) + + sweepResources = append(sweepResources, sweep.NewSweepResource(r, d, client)) + } + + return !lastPage + }) + + if sweep.SkipSweepError(err) { + log.Printf("[WARN] Skipping IoT Topic Rule Destination sweep for %s: %s", region, err) + return nil + } + + if err != nil { + return fmt.Errorf("error listing IoT Topic Rule Destinations (%s): %w", region, err) + } + + err = sweep.SweepOrchestrator(sweepResources) + + if err != nil { + return fmt.Errorf("error sweeping IoT Topic Rule Destinations (%s): %w", region, err) + } + + return nil +} From 7702d3cc0c08f77d7aa60a26fdfd2b24a18a0304 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 17:27:32 -0400 Subject: [PATCH 77/87] r/aws_iot_topic_rule_destination: Increase default deletion timeout. --- internal/service/iot/topic_rule_destination.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/iot/topic_rule_destination.go b/internal/service/iot/topic_rule_destination.go index f91ca284f31..16f2a780a73 100644 --- a/internal/service/iot/topic_rule_destination.go +++ b/internal/service/iot/topic_rule_destination.go @@ -32,7 +32,7 @@ func ResourceTopicRuleDestination() *schema.Resource { Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(15 * time.Minute), Update: schema.DefaultTimeout(5 * time.Minute), - Delete: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(15 * time.Minute), }, Schema: map[string]*schema.Schema{ From 9e6e0dc8dfe62282ffd6d0f4acbbec518fa0c70f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 18:17:58 -0400 Subject: [PATCH 78/87] 'FindTopicRuleDestinationByARN' now returns a NotFoundError if the destination is gone. --- internal/service/iot/find.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/internal/service/iot/find.go b/internal/service/iot/find.go index be6e2ff5a33..0def8f4c244 100644 --- a/internal/service/iot/find.go +++ b/internal/service/iot/find.go @@ -174,6 +174,39 @@ func FindTopicRuleByName(conn *iot.IoT, name string) (*iot.GetTopicRuleOutput, e } func FindTopicRuleDestinationByARN(ctx context.Context, conn *iot.IoT, arn string) (*iot.TopicRuleDestination, error) { + // GetTopicRuleDestination returns unhelpful errors such as + // "UnauthorizedException: Access to TopicRuleDestination 'arn:aws:iot:us-west-2:123456789012:ruledestination/vpc/f267138a-7383-4670-9e44-a7fe2f48af5e' was denied" + // when querying for a rule destination that doesn't exist. + var destination *iot.TopicRuleDestinationSummary + + err := conn.ListTopicRuleDestinationsPages(&iot.ListTopicRuleDestinationsInput{}, func(page *iot.ListTopicRuleDestinationsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.DestinationSummaries { + if v == nil { + continue + } + + if aws.StringValue(v.Arn) == arn { + destination = v + + return false + } + } + + return !lastPage + }) + + if err != nil { + return nil, err + } + + if destination == nil { + return nil, tfresource.NewEmptyResultError(destination) + } + input := &iot.GetTopicRuleDestinationInput{ Arn: aws.String(arn), } From 4c60bad364a0cd96157761c41967ca27c2680552 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 4 May 2022 18:18:33 -0400 Subject: [PATCH 79/87] r/aws_iot_topic_rule_destination: Allow 'enabled' to be updated. --- .../service/iot/topic_rule_destination.go | 60 +++++++++++++++++++ .../iot/topic_rule_destination_test.go | 56 +++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/internal/service/iot/topic_rule_destination.go b/internal/service/iot/topic_rule_destination.go index 16f2a780a73..f2ebe2721b8 100644 --- a/internal/service/iot/topic_rule_destination.go +++ b/internal/service/iot/topic_rule_destination.go @@ -110,6 +110,12 @@ func resourceTopicRuleDestinationCreate(ctx context.Context, d *schema.ResourceD return diag.Errorf("waiting for IoT Topic Rule Destination (%s) create: %s", d.Id(), err) } + if _, ok := d.GetOk("enabled"); !ok { + if _, err := waitTopicRuleDestinationDisabled(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return diag.Errorf("waiting for IoT Topic Rule Destination (%s) disable: %s", d.Id(), err) + } + } + return resourceTopicRuleDestinationRead(ctx, d, meta) } @@ -128,6 +134,8 @@ func resourceTopicRuleDestinationRead(ctx context.Context, d *schema.ResourceDat return diag.Errorf("reading IoT Topic Rule Destination (%s): %s", d.Id(), err) } + d.Set("arn", output.Arn) + d.Set("enabled", aws.StringValue(output.Status) == iot.TopicRuleDestinationStatusEnabled) if output.VpcProperties != nil { if err := d.Set("vpc_configuration", []interface{}{flattenVpcDestinationProperties(output.VpcProperties)}); err != nil { return diag.Errorf("setting vpc_configuration: %s", err) @@ -140,6 +148,20 @@ func resourceTopicRuleDestinationRead(ctx context.Context, d *schema.ResourceDat } func resourceTopicRuleDestinationUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).IoTConn + + if d.HasChange("enabled") { + if _, ok := d.GetOk("enabled"); ok { + if _, err := waitTopicRuleDestinationEnabled(ctx, conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { + return diag.Errorf("waiting for IoT Topic Rule Destination (%s) disable: %s", d.Id(), err) + } + } else { + if _, err := waitTopicRuleDestinationDisabled(ctx, conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { + return diag.Errorf("waiting for IoT Topic Rule Destination (%s) disable: %s", d.Id(), err) + } + } + } + return resourceTopicRuleDestinationRead(ctx, d, meta) } @@ -267,3 +289,41 @@ func waitTopicRuleDestinationDeleted(ctx context.Context, conn *iot.IoT, arn str return nil, err } + +func waitTopicRuleDestinationDisabled(ctx context.Context, conn *iot.IoT, arn string, timeout time.Duration) (*iot.TopicRuleDestination, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{iot.TopicRuleDestinationStatusEnabled}, + Target: []string{iot.TopicRuleDestinationStatusDisabled}, + Refresh: statusTopicRuleDestination(ctx, conn, arn), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*iot.TopicRuleDestination); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusReason))) + + return output, err + } + + return nil, err +} + +func waitTopicRuleDestinationEnabled(ctx context.Context, conn *iot.IoT, arn string, timeout time.Duration) (*iot.TopicRuleDestination, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{iot.TopicRuleDestinationStatusDisabled}, + Target: []string{iot.TopicRuleDestinationStatusEnabled}, + Refresh: statusTopicRuleDestination(ctx, conn, arn), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*iot.TopicRuleDestination); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusReason))) + + return output, err + } + + return nil, err +} diff --git a/internal/service/iot/topic_rule_destination_test.go b/internal/service/iot/topic_rule_destination_test.go index 2e61532fd7b..e533d9d0bd0 100644 --- a/internal/service/iot/topic_rule_destination_test.go +++ b/internal/service/iot/topic_rule_destination_test.go @@ -31,6 +31,7 @@ func TestAccIoTTopicRuleDestination_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckTopicRuleDestinationExists(resourceName), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "iot", regexp.MustCompile(`ruledestination/vpc/.+`)), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), resource.TestCheckResourceAttr(resourceName, "vpc_configuration.#", "1"), resource.TestCheckResourceAttrSet(resourceName, "vpc_configuration.0.role_arn"), resource.TestCheckResourceAttr(resourceName, "vpc_configuration.0.security_groups.#", "1"), @@ -69,6 +70,46 @@ func TestAccIoTTopicRuleDestination_disappears(t *testing.T) { }) } +func TestAccIoTTopicRuleDestination_enabled(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_iot_topic_rule_destination.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, iot.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckTopicRuleDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTopicRuleDestinationEnabledConfig(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleDestinationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "enabled", "false"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccTopicRuleDestinationEnabledConfig(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleDestinationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), + ), + }, + { + Config: testAccTopicRuleDestinationEnabledConfig(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicRuleDestinationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "enabled", "false"), + ), + }, + }, + }) +} + func testAccCheckTopicRuleDestinationDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn @@ -144,3 +185,18 @@ resource "aws_iot_topic_rule_destination" "test" { } `) } + +func testAccTopicRuleDestinationEnabledConfig(rName string, enabled bool) string { + return acctest.ConfigCompose(testAccTopicRuleDestinationBaseConfig(rName), fmt.Sprintf(` +resource "aws_iot_topic_rule_destination" "test" { + enabled = %[1]t + + vpc_configuration { + role_arn = aws_iam_role.test.arn + security_groups = [aws_security_group.test.id] + subnet_ids = aws_subnet.test[*].id + vpc_id = aws_vpc.test.id + } +} +`, enabled)) +} From 64ad1277aee6e1bdb88e36b089a6ebe88b4fb623 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 5 May 2022 07:49:16 -0400 Subject: [PATCH 80/87] r/aws_iot_topic_rule_destination: Don't forget to actually call 'UpdateTopicRuleDestination'. --- .../service/iot/topic_rule_destination.go | 55 ++++++++++++++----- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/internal/service/iot/topic_rule_destination.go b/internal/service/iot/topic_rule_destination.go index f2ebe2721b8..c5b206baa9d 100644 --- a/internal/service/iot/topic_rule_destination.go +++ b/internal/service/iot/topic_rule_destination.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/iot" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -30,9 +31,9 @@ func ResourceTopicRuleDestination() *schema.Resource { }, Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(15 * time.Minute), - Update: schema.DefaultTimeout(5 * time.Minute), - Delete: schema.DefaultTimeout(15 * time.Minute), + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), }, Schema: map[string]*schema.Schema{ @@ -94,11 +95,19 @@ func resourceTopicRuleDestinationCreate(ctx context.Context, d *schema.ResourceD } log.Printf("[INFO] Creating IoT Topic Rule Destination: %s", input) - outputRaw, err := tfresource.RetryWhenAWSErrMessageContains(tfiam.PropagationTimeout, + outputRaw, err := tfresource.RetryWhen(tfiam.PropagationTimeout, func() (interface{}, error) { return conn.CreateTopicRuleDestinationWithContext(ctx, input) }, - iot.ErrCodeInvalidRequestException, "sts:AssumeRole") + func(err error) (bool, error) { + if tfawserr.ErrMessageContains(err, iot.ErrCodeInvalidRequestException, "sts:AssumeRole") || + tfawserr.ErrMessageContains(err, iot.ErrCodeInvalidRequestException, "Missing permission") { + return true, err + } + + return false, err + }, + ) if err != nil { return diag.Errorf("creating IoT Topic Rule Destination: %s", err) @@ -111,6 +120,15 @@ func resourceTopicRuleDestinationCreate(ctx context.Context, d *schema.ResourceD } if _, ok := d.GetOk("enabled"); !ok { + _, err := conn.UpdateTopicRuleDestinationWithContext(ctx, &iot.UpdateTopicRuleDestinationInput{ + Arn: aws.String(d.Id()), + Status: aws.String(iot.TopicRuleDestinationStatusDisabled), + }) + + if err != nil { + return diag.Errorf("disabling IoT Topic Rule Destination (%s): %s", d.Id(), err) + } + if _, err := waitTopicRuleDestinationDisabled(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return diag.Errorf("waiting for IoT Topic Rule Destination (%s) disable: %s", d.Id(), err) } @@ -151,14 +169,25 @@ func resourceTopicRuleDestinationUpdate(ctx context.Context, d *schema.ResourceD conn := meta.(*conns.AWSClient).IoTConn if d.HasChange("enabled") { - if _, ok := d.GetOk("enabled"); ok { - if _, err := waitTopicRuleDestinationEnabled(ctx, conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { - return diag.Errorf("waiting for IoT Topic Rule Destination (%s) disable: %s", d.Id(), err) - } - } else { - if _, err := waitTopicRuleDestinationDisabled(ctx, conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { - return diag.Errorf("waiting for IoT Topic Rule Destination (%s) disable: %s", d.Id(), err) - } + input := &iot.UpdateTopicRuleDestinationInput{ + Arn: aws.String(d.Id()), + Status: aws.String(iot.TopicRuleDestinationStatusEnabled), + } + waiter := waitTopicRuleDestinationEnabled + + if _, ok := d.GetOk("enabled"); !ok { + input.Status = aws.String(iot.TopicRuleDestinationStatusDisabled) + waiter = waitTopicRuleDestinationDisabled + } + + _, err := conn.UpdateTopicRuleDestinationWithContext(ctx, input) + + if err != nil { + return diag.Errorf("updating IoT Topic Rule Destination (%s): %s", d.Id(), err) + } + + if _, err := waiter(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return diag.Errorf("waiting for IoT Topic Rule Destination (%s) update: %s", d.Id(), err) } } From 86f2fe98d2a153387bd554582926b55e19d4d0ae Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 5 May 2022 09:48:57 -0400 Subject: [PATCH 81/87] r/aws_topic_rule: Add 'kafka.client_properties' as TypeMap. --- internal/service/iot/topic_rule.go | 424 +----------------------- internal/service/iot/topic_rule_test.go | 34 +- 2 files changed, 37 insertions(+), 421 deletions(-) diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index 7172eb6a4ab..dcfeb0a96d6 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/flex" tfiam "github.com/hashicorp/terraform-provider-aws/internal/service/iam" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" @@ -539,30 +540,10 @@ func ResourceTopicRule() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "acks": { - Type: schema.TypeString, - Optional: true, - Default: 1, - ValidateFunc: validation.StringInSlice([]string{ - "0", - "1", - }, false), - }, - "bootstrap_servers": { - Type: schema.TypeString, + "client_properties": { + Type: schema.TypeMap, Required: true, - }, - "compression_type": { - Type: schema.TypeString, - Optional: true, - Default: "none", - ValidateFunc: validation.StringInSlice([]string{ - "none", - "gzip", - "snappy", - "lz4", - "zstd", - }, false), + Elem: &schema.Schema{Type: schema.TypeString}, }, "destination_arn": { Type: schema.TypeString, @@ -573,104 +554,14 @@ func ResourceTopicRule() *schema.Resource { Type: schema.TypeString, Optional: true, }, - "key_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.StringSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.StringSerializer", - }, false), - }, "partition": { Type: schema.TypeString, Optional: true, }, - "sasl_kerberos_keytab": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_krb5_kdc": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_krb5_realm": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_principal": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_service_name": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_mechanism": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "PLAIN", - "GSSAPI", - "SCRAM-SHA-512", - }, false), - }, - "sasl_plain_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_plain_password": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_password": { - Type: schema.TypeString, - Optional: true, - }, - "security_protocol": { - Type: schema.TypeString, - Optional: true, - Default: "SSL", - ValidateFunc: validation.StringInSlice([]string{ - "SSL", - "SASL_SSL", - }, false), - }, - "ssl_key_password": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_keystore": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_keystore_password": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_truststore": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_truststore_password": { - Type: schema.TypeString, - Optional: true, - }, "topic": { Type: schema.TypeString, Required: true, }, - "value_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.ByteBufferSerializer", - }, false), - }, }, }, ExactlyOneOf: topicRuleErrorActionExactlyOneOf, @@ -985,30 +876,10 @@ func ResourceTopicRule() *schema.Resource { Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "acks": { - Type: schema.TypeString, - Optional: true, - Default: 1, - ValidateFunc: validation.StringInSlice([]string{ - "0", - "1", - }, false), - }, - "bootstrap_servers": { - Type: schema.TypeString, + "client_properties": { + Type: schema.TypeMap, Required: true, - }, - "compression_type": { - Type: schema.TypeString, - Optional: true, - Default: "none", - ValidateFunc: validation.StringInSlice([]string{ - "none", - "gzip", - "snappy", - "lz4", - "zstd", - }, false), + Elem: &schema.Schema{Type: schema.TypeString}, }, "destination_arn": { Type: schema.TypeString, @@ -1019,104 +890,14 @@ func ResourceTopicRule() *schema.Resource { Type: schema.TypeString, Optional: true, }, - "key_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.StringSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.StringSerializer", - }, false), - }, "partition": { Type: schema.TypeString, Optional: true, }, - "sasl_kerberos_keytab": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_krb5_kdc": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_krb5_realm": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_principal": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_kerberos_service_name": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_mechanism": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "PLAIN", - "GSSAPI", - "SCRAM-SHA-512", - }, false), - }, - "sasl_plain_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_plain_password": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_username": { - Type: schema.TypeString, - Optional: true, - }, - "sasl_scram_password": { - Type: schema.TypeString, - Optional: true, - }, - "security_protocol": { - Type: schema.TypeString, - Optional: true, - Default: "SSL", - ValidateFunc: validation.StringInSlice([]string{ - "SSL", - "SASL_SSL", - }, false), - }, - "ssl_key_password": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_keystore": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_keystore_password": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_truststore": { - Type: schema.TypeString, - Optional: true, - }, - "ssl_truststore_password": { - Type: schema.TypeString, - Optional: true, - }, "topic": { Type: schema.TypeString, Required: true, }, - "value_serializer": { - Type: schema.TypeString, - Optional: true, - Default: "org.apache.kafka.common.serialization.ByteBufferSerializer", - ValidateFunc: validation.StringInSlice([]string{ - "org.apache.kafka.common.serialization.ByteBufferSerializer", - }, false), - }, }, }, }, @@ -1869,18 +1650,9 @@ func expandIotKafkaAction(tfList []interface{}) *iot.KafkaAction { apiObject := &iot.KafkaAction{} tfMap := tfList[0].(map[string]interface{}) - clientProperties := make(map[string]*string) - - if v, ok := tfMap["acks"].(string); ok && v != "" { - clientProperties["acks"] = aws.String(v) - } - - if v, ok := tfMap["bootstrap_servers"].(string); ok && v != "" { - clientProperties["bootstrap.servers"] = aws.String(v) - } - if v, ok := tfMap["compression_type"].(string); ok && v != "" { - clientProperties["compression.type"] = aws.String(v) + if v, ok := tfMap["client_properties"].(map[string]interface{}); ok && len(v) > 0 { + apiObject.ClientProperties = flex.ExpandStringMap(v) } if v, ok := tfMap["destination_arn"].(string); ok && v != "" { @@ -1891,94 +1663,14 @@ func expandIotKafkaAction(tfList []interface{}) *iot.KafkaAction { apiObject.Key = aws.String(v) } - if v, ok := tfMap["key_serializer"].(string); ok && v != "" { - clientProperties["key.serializer"] = aws.String(v) - } - if v, ok := tfMap["partition"].(string); ok && v != "" { apiObject.Partition = aws.String(v) } - if sp, ok := tfMap["security_protocol"].(string); ok && sp != "" { - clientProperties["security.protocol"] = aws.String(sp) - - switch sp { - case "SSL": - if v, ok := tfMap["ssl_keystore"].(string); ok && v != "" { - clientProperties["ssl.keystore"] = aws.String(v) - } - - if v, ok := tfMap["ssl_keystore_password"].(string); ok && v != "" { - clientProperties["ssl.keystore.password"] = aws.String(v) - } - - if v, ok := tfMap["ssl_key_password"].(string); ok && v != "" { - clientProperties["ssl.key.password"] = aws.String(v) - } - case "SASL": - if mechanism, ok := tfMap["sasl_mechanism"].(string); ok && mechanism != "" { - clientProperties["sasl.mechanism"] = aws.String(mechanism) - - switch mechanism { - case "PLAIN": - if v, ok := tfMap["sasl_plain_username"].(string); ok && v != "" { - clientProperties["sasl.plain.username"] = aws.String(v) - } - - if v, ok := tfMap["sasl_plain_password"].(string); ok && v != "" { - clientProperties["sasl.plain.password"] = aws.String(v) - } - case "SCRAM-SHA-512": - if v, ok := tfMap["sasl_scram_username"].(string); ok && v != "" { - clientProperties["sasl.scram.username"] = aws.String(v) - } - - if v, ok := tfMap["sasl_scram_password"].(string); ok && v != "" { - clientProperties["sasl.scram.password"] = aws.String(v) - } - case "GSSAPI": - if v, ok := tfMap["sasl_kerberos_keytab"].(string); ok && v != "" { - clientProperties["sasl.kerberos.keytab"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_krb5_kdc"].(string); ok && v != "" { - clientProperties["sasl.kerberos.krb5.kdc"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_krb5_realm"].(string); ok && v != "" { - clientProperties["sasl.kerberos.krb5.realm"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_principal"].(string); ok && v != "" { - clientProperties["sasl.kerberos.principal"] = aws.String(v) - } - - if v, ok := tfMap["sasl_kerberos_service_name"].(string); ok && v != "" { - clientProperties["sasl.kerberos.service.name"] = aws.String(v) - } - } - } - } - } - - if v, ok := tfMap["ssl_truststore"].(string); ok && v != "" { - clientProperties["ssl.truststore"] = aws.String(v) - } - - if v, ok := tfMap["ssl_truststore_password"].(string); ok && v != "" { - clientProperties["ssl.truststore.password"] = aws.String(v) - } - if v, ok := tfMap["topic"].(string); ok && v != "" { apiObject.Topic = aws.String(v) } - if v, ok := tfMap["value_serializer"].(string); ok && v != "" { - clientProperties["value.serializer"] = aws.String(v) - } - - apiObject.ClientProperties = clientProperties - return apiObject } @@ -3100,6 +2792,10 @@ func flattenIotKafkaAction(apiObject *iot.KafkaAction) []interface{} { tfMap := make(map[string]interface{}) + if v := apiObject.ClientProperties; v != nil { + tfMap["client_properties"] = aws.StringValueMap(v) + } + if v := apiObject.DestinationArn; v != nil { tfMap["destination_arn"] = aws.StringValue(v) } @@ -3116,100 +2812,6 @@ func flattenIotKafkaAction(apiObject *iot.KafkaAction) []interface{} { tfMap["topic"] = aws.StringValue(v) } - if cp := apiObject.ClientProperties; cp != nil { - if v, ok := cp["acks"]; ok && v != nil { - tfMap["acks"] = aws.StringValue(v) - } - - if v, ok := cp["bootstrap.servers"]; ok && v != nil { - tfMap["bootstrap_servers"] = aws.StringValue(v) - } - - if v, ok := cp["compression.type"]; ok && v != nil { - tfMap["compression_type"] = aws.StringValue(v) - } - - if v, ok := cp["key.serializer"]; ok && v != nil { - tfMap["key_serializer"] = aws.StringValue(v) - } - - if v, ok := cp["value.serializer"]; ok && v != nil { - tfMap["value_serializer"] = aws.StringValue(v) - } - - if v, ok := cp["ssl.truststore"]; ok && v != nil { - tfMap["ssl_truststore"] = aws.StringValue(v) - } - - if v, ok := cp["ssl.truststore.password"]; ok && v != nil { - tfMap["ssl_truststore_password"] = aws.StringValue(v) - } - - if sp, ok := cp["security.protocol"]; ok && sp != nil { - protocol := aws.StringValue(sp) - tfMap["security_protocol"] = protocol - - switch protocol { - case "SSL": - if v, ok := cp["ssl.keystore"]; ok && v != nil { - tfMap["ssl_keystore"] = aws.StringValue(v) - } - - if v, ok := cp["ssl.keystore.password"]; ok && v != nil { - tfMap["ssl_keystore_password"] = aws.StringValue(v) - } - - if v, ok := cp["ssl.key.password"]; ok && v != nil { - tfMap["ssl_key_password"] = aws.StringValue(v) - } - case "SASL": - if m, ok := cp["sasl.mechanism"]; ok && m != nil { - mechanism := aws.StringValue(m) - tfMap["sasl_mechanism"] = mechanism - - switch mechanism { - case "PLAIN": - if v, ok := cp["sasl.plain.username"]; ok && v != nil { - tfMap["sasl_plain_username"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.plain.password"]; ok && v != nil { - tfMap["sasl_plain_password"] = aws.StringValue(v) - } - case "SCRAM-SHA-512": - if v, ok := cp["sasl.scram.username"]; ok && v != nil { - tfMap["sasl_scram_username"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.scram.password"]; ok && v != nil { - tfMap["sasl_scram_password"] = aws.StringValue(v) - } - case "GSSAPI": - if v, ok := cp["sasl.kerberos.keytab"]; ok && v != nil { - tfMap["sasl_kerberos_keytab"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.kerberos.krb5.kdc"]; ok && v != nil { - tfMap["sasl_kerberos_krb5_kdc"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.kerberos.krb5.realm"]; ok && v != nil { - tfMap["sasl_kerberos_krb5_realm"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.kerberos.principal"]; ok && v != nil { - tfMap["sasl_kerberos_principal"] = aws.StringValue(v) - } - - if v, ok := cp["sasl.kerberos.service.name"]; ok && v != nil { - tfMap["sasl_kerberos_service_name"] = aws.StringValue(v) - } - } - } - } - } - } - return []interface{}{tfMap} } diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 188f15f57a5..c16eaf827a3 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -857,6 +857,10 @@ func TestAccIoTTopicRule_IoT_events(t *testing.T) { } func TestAccIoTTopicRule_kafka(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.test" @@ -883,10 +887,14 @@ func TestAccIoTTopicRule_kafka(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "kafka.*", map[string]string{ - "bootstrap_servers": "b-1.localhost:9094", - "ssl_keystore": "$${get_secret('secret_name', 'SecretBinary', '', '${aws_iam_role.test.arn}')}", - "ssl_keystore_password": "password", - "topic": "fake_topic", + "client_properties.%": "6", + "client_properties.acks": "1", + "client_properties.bootstrap.servers": "b-1.localhost:9094", + "client_properties.compression.type": "none", + "client_properties.key.serializer": "org.apache.kafka.common.serialization.StringSerializer", + "client_properties.security.protocol": "SSL", + "client_properties.value.serializer": "org.apache.kafka.common.serialization.ByteBufferSerializer", + "topic": "fake_topic", }), resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), @@ -1973,7 +1981,7 @@ resource "aws_iot_topic_rule" "test" { func testAccTopicRuleKafkaConfig(rName string) string { return acctest.ConfigCompose( - testAccTopicRuleRoleConfig(rName), + testAccTopicRuleDestinationConfig(rName), fmt.Sprintf(` data "aws_region" "current" {} @@ -1984,11 +1992,17 @@ resource "aws_iot_topic_rule" "test" { sql_version = "2015-10-08" kafka { - destination_arn = "arn:${data.aws_partition.current.partition}:kafka:${data.aws_region.current.name}:123456789012:topic/test" - topic = "fake_topic" - bootstrap_servers = "b-1.localhost:9094" - ssl_keystore = "$${get_secret('secret_name', 'SecretBinary', '', '${aws_iam_role.test.arn}')}" - ssl_keystore_password = "password" + destination_arn = aws_iot_topic_rule_destination.test.arn + topic = "fake_topic" + + client_properties = { + "acks" = "1" + "bootstrap.servers" = "b-1.localhost:9094" + "compression.type" = "none" + "key.serializer" = "org.apache.kafka.common.serialization.StringSerializer" + "security.protocol" = "SSL" + "value.serializer" = "org.apache.kafka.common.serialization.ByteBufferSerializer" + } } } `, rName)) From c7b067236372a32a88dc87397532e1e27e0b9a45 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 5 May 2022 12:39:19 -0400 Subject: [PATCH 82/87] More checks in 'TestAccIoTTopicRule_kafka'. --- internal/service/iot/topic_rule_test.go | 31 ++++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index c16eaf827a3..bfbca8cd91a 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -887,14 +887,15 @@ func TestAccIoTTopicRule_kafka(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "http.#", "0"), resource.TestCheckResourceAttr(resourceName, "kafka.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "kafka.*", map[string]string{ - "client_properties.%": "6", - "client_properties.acks": "1", - "client_properties.bootstrap.servers": "b-1.localhost:9094", - "client_properties.compression.type": "none", - "client_properties.key.serializer": "org.apache.kafka.common.serialization.StringSerializer", - "client_properties.security.protocol": "SSL", - "client_properties.value.serializer": "org.apache.kafka.common.serialization.ByteBufferSerializer", - "topic": "fake_topic", + "client_properties.%": "8", + "client_properties.acks": "1", + "client_properties.bootstrap.servers": "b-1.localhost:9094", + "client_properties.compression.type": "none", + "client_properties.key.serializer": "org.apache.kafka.common.serialization.StringSerializer", + "client_properties.security.protocol": "SSL", + "client_properties.ssl.keystore.password": "password", + "client_properties.value.serializer": "org.apache.kafka.common.serialization.ByteBufferSerializer", + "topic": "fake_topic", }), resource.TestCheckResourceAttr(resourceName, "kinesis.#", "0"), resource.TestCheckResourceAttr(resourceName, "lambda.#", "0"), @@ -1996,12 +1997,14 @@ resource "aws_iot_topic_rule" "test" { topic = "fake_topic" client_properties = { - "acks" = "1" - "bootstrap.servers" = "b-1.localhost:9094" - "compression.type" = "none" - "key.serializer" = "org.apache.kafka.common.serialization.StringSerializer" - "security.protocol" = "SSL" - "value.serializer" = "org.apache.kafka.common.serialization.ByteBufferSerializer" + "acks" = "1" + "bootstrap.servers" = "b-1.localhost:9094" + "compression.type" = "none" + "key.serializer" = "org.apache.kafka.common.serialization.StringSerializer" + "security.protocol" = "SSL" + "ssl.keystore" = "$${get_secret('secret_name', 'SecretBinary', '', '${aws_iam_role.test.arn}')}" + "ssl.keystore.password" = "password" + "value.serializer" = "org.apache.kafka.common.serialization.ByteBufferSerializer" } } } From bc48ba231729d286e5c33f48be06c70434fcc733 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 5 May 2022 13:26:44 -0400 Subject: [PATCH 83/87] r/aws_iot_topic_rule: Add documentation for 'kafka'. --- website/docs/r/iot_topic_rule.html.markdown | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/website/docs/r/iot_topic_rule.html.markdown b/website/docs/r/iot_topic_rule.html.markdown index 5a06b1d0c28..be39ed8a159 100644 --- a/website/docs/r/iot_topic_rule.html.markdown +++ b/website/docs/r/iot_topic_rule.html.markdown @@ -88,7 +88,7 @@ EOF * `enabled` - (Required) Specifies whether the rule is enabled. * `sql` - (Required) The SQL statement used to query the topic. For more information, see AWS IoT SQL Reference (http://docs.aws.amazon.com/iot/latest/developerguide/iot-rules.html#aws-iot-sql-reference) in the AWS IoT Developer Guide. * `sql_version` - (Required) The version of the SQL rules engine to use when evaluating the rule. -* `error_action` - (Optional) Configuration block with error action to be associated with the rule. See the documentation for `cloudwatch_alarm`, `cloudwatch_logs`, `cloudwatch_metric`, `dynamodb`, `dynamodbv2`, `elasticsearch`, `firehose`, `http`, `iot_analytics`, `iot_events`, `kinesis`, `lambda`, `republish`, `s3`, `sns`, `sqs`, `step_functions`, `timestream` configuration blocks for further configuration details. +* `error_action` - (Optional) Configuration block with error action to be associated with the rule. See the documentation for `cloudwatch_alarm`, `cloudwatch_logs`, `cloudwatch_metric`, `dynamodb`, `dynamodbv2`, `elasticsearch`, `firehose`, `http`, `iot_analytics`, `iot_events`, `kafka`, `kinesis`, `lambda`, `republish`, `s3`, `sns`, `sqs`, `step_functions`, `timestream` configuration blocks for further configuration details. * `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. The `cloudwatch_alarm` object takes the following arguments: @@ -167,6 +167,14 @@ The `iot_events` object takes the following arguments: * `role_arn` - (Required) The ARN of the IAM role that grants access. * `message_id` - (Optional) Use this to ensure that only one input (message) with a given messageId is processed by an AWS IoT Events detector. +The `kafka` object takes the following arguments: + +* `client_properties` - (Required) Properties of the Apache Kafka producer client. For more info, see the [AWS documentation](https://docs.aws.amazon.com/iot/latest/developerguide/apache-kafka-rule-action.html). +* `destination_arn` - (Required) The ARN of Kafka action's VPC [`aws_iot_topic_rule_destination`](iot_topic_rule_destination.html) . +* `key` - (Optional) The Kafka message key. +* `partition` - (Optional) The Kafka message partition. +* `topic` - (Optional) The Kafka topic for messages to be sent to the Kafka broker. + The `kinesis` object takes the following arguments: * `partition_key` - (Optional) The partition key. From 31ebacb28fcf3e27faa08cc139514c406ce7ecb8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 5 May 2022 13:36:23 -0400 Subject: [PATCH 84/87] Fix terrafmt error. --- internal/service/iot/topic_rule_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index bfbca8cd91a..c4bf30d2917 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -2183,7 +2183,7 @@ resource "aws_iot_topic_rule" "test" { } timestamp { - unit = "MILLISECONDS" + unit = "MILLISECONDS" value = "$${time}" } } From 841474f91bc10e564f51361566b0d455decf9f1d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 5 May 2022 13:38:44 -0400 Subject: [PATCH 85/87] Fix 'MD047/single-trailing-newline Files should end with a single newline character'. --- website/docs/r/iot_topic_rule_destination.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/iot_topic_rule_destination.html.markdown b/website/docs/r/iot_topic_rule_destination.html.markdown index 544fa1f728c..a8d84ce6e18 100644 --- a/website/docs/r/iot_topic_rule_destination.html.markdown +++ b/website/docs/r/iot_topic_rule_destination.html.markdown @@ -45,4 +45,4 @@ IoT topic rule destinations can be imported using the `arn`, e.g., ``` $ terraform import aws_iot_topic_rule_destination.example arn:aws:iot:us-west-2:123456789012:ruledestination/vpc/2ce781c8-68a6-4c52-9c62-63fe489ecc60 -``` \ No newline at end of file +``` From a3106f2375bea687dc3f1a68f78776bb89b80b08 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 5 May 2022 13:49:05 -0400 Subject: [PATCH 86/87] r/aws_iot_topic_rule: Add 's3.canned_acl'. Acceptance test output: % make testacc TESTS=TestAccIoTTopicRule_s3 PKG=iot ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/iot/... -v -count 1 -parallel 20 -run='TestAccIoTTopicRule_s3' -timeout 180m === RUN TestAccIoTTopicRule_s3 === PAUSE TestAccIoTTopicRule_s3 === CONT TestAccIoTTopicRule_s3 --- PASS: TestAccIoTTopicRule_s3 (38.49s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/iot 41.921s --- .changelog/19175.txt | 3 +++ internal/service/iot/topic_rule.go | 18 ++++++++++++++++++ internal/service/iot/topic_rule_test.go | 2 ++ website/docs/r/iot_topic_rule.html.markdown | 1 + 4 files changed, 24 insertions(+) create mode 100644 .changelog/19175.txt diff --git a/.changelog/19175.txt b/.changelog/19175.txt new file mode 100644 index 00000000000..01b745b8141 --- /dev/null +++ b/.changelog/19175.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_iot_topic_rule: Add `s3.canned_acl` and `error_action.s3.canned_acl` arguments +``` \ No newline at end of file diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index dcfeb0a96d6..405d7e4c99e 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -639,6 +639,11 @@ func ResourceTopicRule() *schema.Resource { Type: schema.TypeString, Required: true, }, + "canned_acl": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(iot.CannedAccessControlList_Values(), false), + }, "key": { Type: schema.TypeString, Required: true, @@ -973,6 +978,11 @@ func ResourceTopicRule() *schema.Resource { Type: schema.TypeString, Required: true, }, + "canned_acl": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(iot.CannedAccessControlList_Values(), false), + }, "key": { Type: schema.TypeString, Required: true, @@ -1747,6 +1757,10 @@ func expandIotS3Action(tfList []interface{}) *iot.S3Action { apiObject.BucketName = aws.String(v) } + if v, ok := tfMap["canned_acl"].(string); ok && v != "" { + apiObject.CannedAcl = aws.String(v) + } + if v, ok := tfMap["key"].(string); ok && v != "" { apiObject.Key = aws.String(v) } @@ -2966,6 +2980,10 @@ func flattenIotS3Action(apiObject *iot.S3Action) []interface{} { tfMap["bucket_name"] = aws.StringValue(v) } + if v := apiObject.CannedAcl; v != nil { + tfMap["canned_acl"] = aws.StringValue(v) + } + if v := apiObject.Key; v != nil { tfMap["key"] = aws.StringValue(v) } diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index c4bf30d2917..348e967be4c 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -1139,6 +1139,7 @@ func TestAccIoTTopicRule_s3(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "s3.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "s3.*", map[string]string{ "bucket_name": "mybucket", + "canned_acl": "private", "key": "mykey", }), resource.TestCheckResourceAttr(resourceName, "sns.#", "0"), @@ -2097,6 +2098,7 @@ resource "aws_iot_topic_rule" "test" { s3 { bucket_name = "mybucket" + canned_acl = "private" key = "mykey" role_arn = aws_iam_role.test.arn } diff --git a/website/docs/r/iot_topic_rule.html.markdown b/website/docs/r/iot_topic_rule.html.markdown index be39ed8a159..d4c02db8879 100644 --- a/website/docs/r/iot_topic_rule.html.markdown +++ b/website/docs/r/iot_topic_rule.html.markdown @@ -194,6 +194,7 @@ The `republish` object takes the following arguments: The `s3` object takes the following arguments: * `bucket_name` - (Required) The Amazon S3 bucket name. +* `canned_acl` - (Optional) The Amazon S3 canned ACL that controls access to the object identified by the object key. [Valid values](https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl). * `key` - (Required) The object key. * `role_arn` - (Required) The ARN of the IAM role that grants access. From 8b059a14ebd5eab9e642084867ca605a528d3cfa Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 5 May 2022 14:00:48 -0400 Subject: [PATCH 87/87] Skip tests for unsupported GovCloud functionality. --- internal/service/iot/topic_rule_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 348e967be4c..7b5463f8c10 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -14,6 +14,16 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) +func init() { + acctest.RegisterServiceErrorCheckFunc(iot.EndpointsID, testAccErrorCheckSkip) +} + +func testAccErrorCheckSkip(t *testing.T) resource.ErrorCheckFunc { + return acctest.ErrorCheckSkipMessagesContaining(t, + "not been supported in region", + ) +} + func TestAccIoTTopicRule_basic(t *testing.T) { rName := testAccTopicRuleName() resourceName := "aws_iot_topic_rule.test"