From f0af39b7609d96d3a5eee5edbb4ec0945b0289e5 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 7 Apr 2022 12:49:05 +0300 Subject: [PATCH 1/9] use finder --- internal/service/configservice/config_rule.go | 99 ++++------------- .../service/configservice/config_rule_test.go | 105 +++++++----------- internal/service/configservice/config_test.go | 3 +- internal/service/configservice/find.go | 33 ++++++ internal/service/configservice/status.go | 24 ++++ internal/service/configservice/wait.go | 34 ++++++ 6 files changed, 159 insertions(+), 139 deletions(-) create mode 100644 internal/service/configservice/find.go create mode 100644 internal/service/configservice/status.go create mode 100644 internal/service/configservice/wait.go diff --git a/internal/service/configservice/config_rule.go b/internal/service/configservice/config_rule.go index 11216c1ba711..d8f2df06e831 100644 --- a/internal/service/configservice/config_rule.go +++ b/internal/service/configservice/config_rule.go @@ -7,8 +7,8 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/configservice" + "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" @@ -58,7 +58,7 @@ func ResourceConfigRule() *schema.Resource { "maximum_execution_frequency": { Type: schema.TypeString, Optional: true, - ValidateFunc: validExecutionFrequency(), + ValidateFunc: validation.StringInSlice(configservice.MaximumExecutionFrequency_Values(), false), }, "scope": { Type: schema.TypeList, @@ -101,12 +101,9 @@ func ResourceConfigRule() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "owner": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - configservice.OwnerCustomLambda, - configservice.OwnerAws, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(configservice.Owner_Values(), false), }, "source_detail": { Type: schema.TypeSet, @@ -178,14 +175,12 @@ func resourceRulePutConfig(d *schema.ResourceData, meta interface{}) error { err := resource.Retry(tfiam.PropagationTimeout, func() *resource.RetryError { _, err := conn.PutConfigRule(&input) if err != nil { - if awsErr, ok := err.(awserr.Error); ok { - if awsErr.Code() == "InsufficientPermissionsException" { - // IAM is eventually consistent - return resource.RetryableError(err) - } + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeInsufficientPermissionsException) { + // IAM is eventually consistent + return resource.RetryableError(err) } - return resource.NonRetryableError(fmt.Errorf("Failed to create AWSConfig rule: %s", err)) + return resource.NonRetryableError(fmt.Errorf("Failed to create AWSConfig rule: %w", err)) } return nil @@ -194,7 +189,7 @@ func resourceRulePutConfig(d *schema.ResourceData, meta interface{}) error { _, err = conn.PutConfigRule(&input) } if err != nil { - return fmt.Errorf("Error creating AWSConfig rule: %s", err) + return fmt.Errorf("Error creating AWSConfig rule: %w", err) } d.SetId(name) @@ -202,10 +197,11 @@ func resourceRulePutConfig(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] AWSConfig config rule %q created", name) if !d.IsNewResource() && d.HasChange("tags_all") { + arn := d.Get("arn").(string) o, n := d.GetChange("tags_all") - if err := UpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating Config Config Rule (%s) tags: %s", d.Get("arn").(string), err) + if err := UpdateTags(conn, arn, o, n); err != nil { + return fmt.Errorf("error updating Config Config Rule (%s) tags: %w", arn, err) } } @@ -217,34 +213,16 @@ func resourceConfigRuleRead(d *schema.ResourceData, meta interface{}) error { defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - out, err := conn.DescribeConfigRules(&configservice.DescribeConfigRulesInput{ - ConfigRuleNames: []*string{aws.String(d.Id())}, - }) - if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchConfigRuleException" { - log.Printf("[WARN] Config Rule %q is gone (NoSuchConfigRuleException)", d.Id()) - d.SetId("") - return nil - } - return err - } + rule, err := FindConfigRule(conn, d.Id()) - numberOfRules := len(out.ConfigRules) - if numberOfRules < 1 { - log.Printf("[WARN] Config Rule %q is gone (no rules found)", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] ConfigService Config Rule (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - if numberOfRules > 1 { - return fmt.Errorf("Expected exactly 1 Config Rule, received %d: %#v", - numberOfRules, out.ConfigRules) - } - - log.Printf("[DEBUG] AWS Config config rule received: %s", out) - - rule := out.ConfigRules[0] - d.Set("arn", rule.ConfigRuleArn) + arn := aws.StringValue(rule.ConfigRuleArn) + d.Set("arn", arn) d.Set("rule_id", rule.ConfigRuleId) d.Set("name", rule.ConfigRuleName) d.Set("description", rule.Description) @@ -257,10 +235,10 @@ func resourceConfigRuleRead(d *schema.ResourceData, meta interface{}) error { d.Set("source", flattenRuleSource(rule.Source)) - tags, err := ListTags(conn, d.Get("arn").(string)) + tags, err := ListTags(conn, arn) if err != nil { - return fmt.Errorf("error listing tags for Config Config Rule (%s): %s", d.Get("arn").(string), err) + return fmt.Errorf("error listing tags for Config Config Rule (%s): %w", arn, err) } tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) @@ -289,7 +267,7 @@ func resourceConfigRuleDelete(d *schema.ResourceData, meta interface{}) error { err := resource.Retry(2*time.Minute, func() *resource.RetryError { _, err := conn.DeleteConfigRule(input) if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceInUseException" { + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeResourceInUseException) { return resource.RetryableError(err) } return resource.NonRetryableError(err) @@ -300,42 +278,13 @@ func resourceConfigRuleDelete(d *schema.ResourceData, meta interface{}) error { _, err = conn.DeleteConfigRule(input) } if err != nil { - return fmt.Errorf("Deleting Config Rule failed: %s", err) + return fmt.Errorf("error Deleting Config Rule failed: %w", err) } - conf := resource.StateChangeConf{ - Pending: []string{ - configservice.ConfigRuleStateActive, - configservice.ConfigRuleStateDeleting, - configservice.ConfigRuleStateDeletingResults, - configservice.ConfigRuleStateEvaluating, - }, - Target: []string{""}, - Timeout: 5 * time.Minute, - Refresh: func() (interface{}, string, error) { - out, err := conn.DescribeConfigRules(&configservice.DescribeConfigRulesInput{ - ConfigRuleNames: []*string{aws.String(d.Id())}, - }) - if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchConfigRuleException" { - return 42, "", nil - } - return 42, "", fmt.Errorf("Failed to describe config rule %q: %s", d.Id(), err) - } - if len(out.ConfigRules) < 1 { - return 42, "", nil - } - rule := out.ConfigRules[0] - return out, *rule.ConfigRuleState, nil - }, - } - _, err = conf.WaitForState() - if err != nil { - return err + if _, err := waitRuleDeleted(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Config Service Rule (%s) to deleted: %w", d.Id(), err) } - log.Printf("[DEBUG] AWS Config config rule %q deleted", name) - return nil } diff --git a/internal/service/configservice/config_rule_test.go b/internal/service/configservice/config_rule_test.go index e59448897bdd..b4fead0a546a 100644 --- a/internal/service/configservice/config_rule_test.go +++ b/internal/service/configservice/config_rule_test.go @@ -5,13 +5,14 @@ import ( "regexp" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/configservice" 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" + tfconfig "github.com/hashicorp/terraform-provider-aws/internal/service/configservice" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func testAccConfigRule_basic(t *testing.T) { @@ -70,6 +71,11 @@ func testAccConfigRule_ownerAws(t *testing.T) { resource.TestCheckTypeSetElemAttr(resourceName, "scope.0.compliance_resource_types.*", "AWS::EC2::Instance"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -112,49 +118,6 @@ func testAccConfigRule_customlambda(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "scope.0.tag_value", "yes"), ), }, - }, - }) -} - -func testAccConfigRule_importAws(t *testing.T) { - resourceName := "aws_config_config_rule.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, configservice.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckConfigRuleDestroy, - Steps: []resource.TestStep{ - { - Config: testAccConfigRuleConfig_ownerAws(rName), - }, - - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccConfigRule_importLambda(t *testing.T) { - resourceName := "aws_config_config_rule.test" - rInt := sdkacctest.RandInt() - - path := "test-fixtures/lambdatest.zip" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, configservice.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckConfigRuleDestroy, - Steps: []resource.TestStep{ - { - Config: testAccConfigRuleConfig_customLambda(rInt, path), - }, - { ResourceName: resourceName, ImportState: true, @@ -294,6 +257,29 @@ func testAccConfigRule_tags(t *testing.T) { }) } +func testAccConfigRule_disappears(t *testing.T) { + var cr configservice.ConfigRule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_config_config_rule.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, configservice.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckConfigRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigRuleConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigRuleExists(resourceName, &cr), + acctest.CheckResourceDisappears(acctest.Provider, tfconfig.ResourceConfigRule(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckConfigRuleName(n, desired string, obj *configservice.ConfigRule) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -319,18 +305,12 @@ func testAccCheckConfigRuleExists(n string, obj *configservice.ConfigRule) resou } conn := acctest.Provider.Meta().(*conns.AWSClient).ConfigServiceConn - out, err := conn.DescribeConfigRules(&configservice.DescribeConfigRulesInput{ - ConfigRuleNames: []*string{aws.String(rs.Primary.Attributes["name"])}, - }) + + rule, err := tfconfig.FindConfigRule(conn, rs.Primary.ID) if err != nil { - return fmt.Errorf("Failed to describe config rule: %s", err) - } - if len(out.ConfigRules) < 1 { - return fmt.Errorf("No config rule found when describing %q", rs.Primary.Attributes["name"]) + return fmt.Errorf("Failed to describe config rule: %w", err) } - - cr := out.ConfigRules[0] - *obj = *cr + *obj = *rule return nil } @@ -344,16 +324,17 @@ func testAccCheckConfigRuleDestroy(s *terraform.State) error { continue } - resp, err := conn.DescribeConfigRules(&configservice.DescribeConfigRulesInput{ - ConfigRuleNames: []*string{aws.String(rs.Primary.Attributes["name"])}, - }) + _, err := tfconfig.FindConfigRule(conn, rs.Primary.ID) - if err == nil { - if len(resp.ConfigRules) != 0 && - *resp.ConfigRules[0].ConfigRuleName == rs.Primary.Attributes["name"] { - return fmt.Errorf("config rule still exists: %s", rs.Primary.Attributes["name"]) - } + if tfresource.NotFound(err) { + continue } + + if err != nil { + return err + } + + return fmt.Errorf("ConfigService Rule %s still exists", rs.Primary.ID) } return nil diff --git a/internal/service/configservice/config_test.go b/internal/service/configservice/config_test.go index 98b8baca63cb..745a5a62778e 100644 --- a/internal/service/configservice/config_test.go +++ b/internal/service/configservice/config_test.go @@ -10,12 +10,11 @@ func TestAccConfigService_serial(t *testing.T) { "basic": testAccConfigRule_basic, "ownerAws": testAccConfigRule_ownerAws, "customlambda": testAccConfigRule_customlambda, - "importAws": testAccConfigRule_importAws, - "importLambda": testAccConfigRule_importLambda, "scopeTagKey": testAccConfigRule_Scope_TagKey, "scopeTagKeyEmpty": testAccConfigRule_Scope_TagKey_Empty, "scopeTagValue": testAccConfigRule_Scope_TagValue, "tags": testAccConfigRule_tags, + "disappears": testAccConfigRule_disappears, }, "ConfigurationRecorderStatus": { "basic": testAccConfigurationRecorderStatus_basic, diff --git a/internal/service/configservice/find.go b/internal/service/configservice/find.go new file mode 100644 index 000000000000..f56bd445c969 --- /dev/null +++ b/internal/service/configservice/find.go @@ -0,0 +1,33 @@ +package configservice + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/configservice" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" +) + +func FindConfigRule(conn *configservice.ConfigService, name string) (*configservice.ConfigRule, error) { + input := &configservice.DescribeConfigRulesInput{ + ConfigRuleNames: []*string{aws.String(name)}, + } + + output, err := conn.DescribeConfigRules(input) + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchConfigRuleException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if output == nil { + return nil, nil + } + + if output == nil || output.ConfigRules == nil || len(output.ConfigRules) == 0 || output.ConfigRules[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.ConfigRules[0], nil +} diff --git a/internal/service/configservice/status.go b/internal/service/configservice/status.go new file mode 100644 index 000000000000..51edaf8b79fc --- /dev/null +++ b/internal/service/configservice/status.go @@ -0,0 +1,24 @@ +package configservice + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/configservice" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" +) + +func statusRule(conn *configservice.ConfigService, name string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := FindConfigRule(conn, name) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.ConfigRuleState), nil + } +} diff --git a/internal/service/configservice/wait.go b/internal/service/configservice/wait.go new file mode 100644 index 000000000000..ce9a8b437f66 --- /dev/null +++ b/internal/service/configservice/wait.go @@ -0,0 +1,34 @@ +package configservice + +import ( + "time" + + "github.com/aws/aws-sdk-go/service/configservice" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const ( + ruleDeletedTimeout = 5 * time.Minute +) + +func waitRuleDeleted(conn *configservice.ConfigService, name string) (*configservice.ConfigRule, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + configservice.ConfigRuleStateActive, + configservice.ConfigRuleStateDeleting, + configservice.ConfigRuleStateDeletingResults, + configservice.ConfigRuleStateEvaluating, + }, + Target: []string{}, + Refresh: statusRule(conn, name), + Timeout: ruleDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*configservice.ConfigRule); ok { + return v, err + } + + return nil, err +} From 2763db92f0008a49489d57c6024ed4eec294e0a6 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 7 Apr 2022 12:49:35 +0300 Subject: [PATCH 2/9] use finder --- a.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 a.txt diff --git a/a.txt b/a.txt new file mode 100644 index 000000000000..aa7c2e67fdf2 --- /dev/null +++ b/a.txt @@ -0,0 +1,18 @@ +==> Checking that code complies with gofmt requirements... +TF_ACC=1 go test ./internal/service/configservice/... -v -count 1 -parallel 20 -run='TestAccConfigService_serial/Config/disappears' -timeout 180m +=== RUN TestAccConfigService_serial +=== RUN TestAccConfigService_serial/RemediationConfiguration +=== RUN TestAccConfigService_serial/RemediationConfiguration/disappears +=== RUN TestAccConfigService_serial/Config +=== RUN TestAccConfigService_serial/Config/disappears +=== RUN TestAccConfigService_serial/ConfigurationRecorderStatus +=== RUN TestAccConfigService_serial/ConfigurationRecorder +--- PASS: TestAccConfigService_serial (236.24s) + --- PASS: TestAccConfigService_serial/RemediationConfiguration (124.11s) + --- PASS: TestAccConfigService_serial/RemediationConfiguration/disappears (124.11s) + --- PASS: TestAccConfigService_serial/Config (112.13s) + --- PASS: TestAccConfigService_serial/Config/disappears (112.13s) + --- PASS: TestAccConfigService_serial/ConfigurationRecorderStatus (0.00s) + --- PASS: TestAccConfigService_serial/ConfigurationRecorder (0.00s) +PASS +ok github.com/hashicorp/terraform-provider-aws/internal/service/configservice 238.108s From f0133eba75afd62ef014751c3bc2b7d9611ea6fc Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 7 Apr 2022 12:51:40 +0300 Subject: [PATCH 3/9] use finder --- a.txt | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 a.txt diff --git a/a.txt b/a.txt deleted file mode 100644 index aa7c2e67fdf2..000000000000 --- a/a.txt +++ /dev/null @@ -1,18 +0,0 @@ -==> Checking that code complies with gofmt requirements... -TF_ACC=1 go test ./internal/service/configservice/... -v -count 1 -parallel 20 -run='TestAccConfigService_serial/Config/disappears' -timeout 180m -=== RUN TestAccConfigService_serial -=== RUN TestAccConfigService_serial/RemediationConfiguration -=== RUN TestAccConfigService_serial/RemediationConfiguration/disappears -=== RUN TestAccConfigService_serial/Config -=== RUN TestAccConfigService_serial/Config/disappears -=== RUN TestAccConfigService_serial/ConfigurationRecorderStatus -=== RUN TestAccConfigService_serial/ConfigurationRecorder ---- PASS: TestAccConfigService_serial (236.24s) - --- PASS: TestAccConfigService_serial/RemediationConfiguration (124.11s) - --- PASS: TestAccConfigService_serial/RemediationConfiguration/disappears (124.11s) - --- PASS: TestAccConfigService_serial/Config (112.13s) - --- PASS: TestAccConfigService_serial/Config/disappears (112.13s) - --- PASS: TestAccConfigService_serial/ConfigurationRecorderStatus (0.00s) - --- PASS: TestAccConfigService_serial/ConfigurationRecorder (0.00s) -PASS -ok github.com/hashicorp/terraform-provider-aws/internal/service/configservice 238.108s From 77cc81f329a7519da3dc68955dd4d0a0b319c3a1 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 8 Apr 2022 14:35:41 +0300 Subject: [PATCH 4/9] add support for custom_policy_details --- internal/service/configservice/config_rule.go | 44 +++++++++-- .../service/configservice/config_rule_test.go | 78 +++++++++++++++++++ internal/service/configservice/config_test.go | 1 + internal/service/configservice/flex.go | 41 +++++++++- 4 files changed, 155 insertions(+), 9 deletions(-) diff --git a/internal/service/configservice/config_rule.go b/internal/service/configservice/config_rule.go index d8f2df06e831..3b899f468b78 100644 --- a/internal/service/configservice/config_rule.go +++ b/internal/service/configservice/config_rule.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "log" + "regexp" "time" "github.com/aws/aws-sdk-go/aws" @@ -100,6 +101,33 @@ func ResourceConfigRule() *schema.Resource { Required: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "custom_policy_details": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable_debug_log_delivery": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "policy_runtime": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 64), + validation.StringMatch(regexp.MustCompile(`^guard\-2\.x\.x$`), "Must match cloudformation-guard version"), + ), + }, + "policy_text": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 10000), + }, + }, + }, + }, "owner": { Type: schema.TypeString, Required: true, @@ -113,25 +141,27 @@ func ResourceConfigRule() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "event_source": { - Type: schema.TypeString, - Optional: true, - Default: "aws.config", + Type: schema.TypeString, + Optional: true, + Default: "aws.config", + ValidateFunc: validation.StringInSlice(configservice.EventSource_Values(), false), }, "maximum_execution_frequency": { Type: schema.TypeString, Optional: true, - ValidateFunc: validExecutionFrequency(), + ValidateFunc: validation.StringInSlice(configservice.MaximumExecutionFrequency_Values(), false), }, "message_type": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(configservice.MessageType_Values(), false), }, }, }, }, "source_identifier": { Type: schema.TypeString, - Required: true, + Optional: true, ValidateFunc: validation.StringLenBetween(0, 256), }, }, diff --git a/internal/service/configservice/config_rule_test.go b/internal/service/configservice/config_rule_test.go index b4fead0a546a..23db888ea999 100644 --- a/internal/service/configservice/config_rule_test.go +++ b/internal/service/configservice/config_rule_test.go @@ -127,6 +127,45 @@ func testAccConfigRule_customlambda(t *testing.T) { }) } +func testAccConfigRule_ownerPolicy(t *testing.T) { + var cr configservice.ConfigRule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_config_config_rule.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, configservice.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckConfigRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigRuleConfig_ownerPolicy(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigRuleExists(resourceName, &cr), + testAccCheckConfigRuleName(resourceName, rName, &cr), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile("config-rule/config-rule-[a-z0-9]+$")), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestMatchResourceAttr(resourceName, "rule_id", regexp.MustCompile("config-rule-[a-z0-9]+$")), + resource.TestCheckResourceAttr(resourceName, "description", "Terraform Acceptance tests"), + resource.TestCheckResourceAttr(resourceName, "source.#", "1"), + resource.TestCheckResourceAttr(resourceName, "source.0.owner", "CUSTOM_POLICY"), + resource.TestCheckResourceAttr(resourceName, "source.0.source_detail.#", "1"), + resource.TestCheckResourceAttr(resourceName, "source.0.source_detail.0.message_type", "ConfigurationItemChangeNotification"), + resource.TestCheckResourceAttr(resourceName, "source.0.custom_policy_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "source.0.custom_policy_details.0.policy_runtime", "guard-2.x.x"), + resource.TestCheckResourceAttrSet(resourceName, "source.0.custom_policy_details.0.policy_text"), + resource.TestCheckResourceAttr(resourceName, "scope.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccConfigRule_Scope_TagKey(t *testing.T) { var configRule configservice.ConfigRule rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -419,6 +458,45 @@ PARAMS `, rName) } +func testAccConfigRuleConfig_ownerPolicy(rName string) string { + return testAccConfigRuleConfig_base(rName) + fmt.Sprintf(` +resource "aws_config_config_rule" "test" { + name = %q + description = "Terraform Acceptance tests" + + source { + owner = "CUSTOM_POLICY" + + source_detail { + message_type = "ConfigurationItemChangeNotification" + } + + custom_policy_details { + policy_runtime = "guard-2.x.x" + policy_text = < 0 { + source.CustomPolicyDetails = expandRuleSourceCustomPolicyDetails(v) + } + return &source } @@ -129,6 +138,17 @@ func expandRuleSourceDetails(configured *schema.Set) []*configservice.SourceDeta return results } +func expandRuleSourceCustomPolicyDetails(configured []interface{}) *configservice.CustomPolicyDetails { + cfg := configured[0].(map[string]interface{}) + source := configservice.CustomPolicyDetails{ + PolicyRuntime: aws.String(cfg["policy_runtime"].(string)), + PolicyText: aws.String(cfg["policy_text"].(string)), + EnableDebugLogDelivery: aws.Bool(cfg["enable_debug_log_delivery"].(bool)), + } + + return &source +} + func flattenAccountAggregationSources(sources []*configservice.AccountAggregationSource) []interface{} { var result []interface{} @@ -204,9 +224,26 @@ func flattenRuleSource(source *configservice.Source) []interface{} { m := make(map[string]interface{}) m["owner"] = aws.StringValue(source.Owner) m["source_identifier"] = aws.StringValue(source.SourceIdentifier) + + if source.CustomPolicyDetails != nil { + m["custom_policy_details"] = flattenRuleSourceCustomPolicyDetails(source.CustomPolicyDetails) + } + if len(source.SourceDetails) > 0 { m["source_detail"] = schema.NewSet(ruleSourceDetailsHash, flattenRuleSourceDetails(source.SourceDetails)) } + + result = append(result, m) + return result +} + +func flattenRuleSourceCustomPolicyDetails(source *configservice.CustomPolicyDetails) []interface{} { + var result []interface{} + m := make(map[string]interface{}) + m["policy_runtime"] = aws.StringValue(source.PolicyRuntime) + m["policy_text"] = aws.StringValue(source.PolicyText) + m["enable_debug_log_delivery"] = aws.BoolValue(source.EnableDebugLogDelivery) + result = append(result, m) return result } From 87c2b013b06c86b2682af8c713af539e99b62381 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 8 Apr 2022 15:28:26 +0300 Subject: [PATCH 5/9] add support for custom_policy_details --- internal/service/configservice/config_rule.go | 6 ++++++ internal/service/configservice/config_rule_test.go | 10 +++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/internal/service/configservice/config_rule.go b/internal/service/configservice/config_rule.go index 3b899f468b78..9cd6fadc8af9 100644 --- a/internal/service/configservice/config_rule.go +++ b/internal/service/configservice/config_rule.go @@ -124,6 +124,12 @@ func ResourceConfigRule() *schema.Resource { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringLenBetween(0, 10000), + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { // policy_text always returns empty + if d.Id() != "" && old == "" { + return true + } + return false + }, }, }, }, diff --git a/internal/service/configservice/config_rule_test.go b/internal/service/configservice/config_rule_test.go index 23db888ea999..c2901dfa6530 100644 --- a/internal/service/configservice/config_rule_test.go +++ b/internal/service/configservice/config_rule_test.go @@ -153,7 +153,7 @@ func testAccConfigRule_ownerPolicy(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "source.0.source_detail.0.message_type", "ConfigurationItemChangeNotification"), resource.TestCheckResourceAttr(resourceName, "source.0.custom_policy_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "source.0.custom_policy_details.0.policy_runtime", "guard-2.x.x"), - resource.TestCheckResourceAttrSet(resourceName, "source.0.custom_policy_details.0.policy_text"), + resource.TestCheckResourceAttr(resourceName, "source.0.custom_policy_details.0.enable_debug_log_delivery", "false"), resource.TestCheckResourceAttr(resourceName, "scope.#", "0"), ), }, @@ -474,19 +474,15 @@ resource "aws_config_config_rule" "test" { custom_policy_details { policy_runtime = "guard-2.x.x" policy_text = < Date: Fri, 8 Apr 2022 15:42:47 +0300 Subject: [PATCH 6/9] changelog + docs --- .changelog/24057.txt | 11 +++ .../docs/r/config_config_rule.html.markdown | 71 +++++++++++++++---- 2 files changed, 68 insertions(+), 14 deletions(-) create mode 100644 .changelog/24057.txt diff --git a/.changelog/24057.txt b/.changelog/24057.txt new file mode 100644 index 000000000000..c7b28e3e7919 --- /dev/null +++ b/.changelog/24057.txt @@ -0,0 +1,11 @@ +```release-note:enhancement +resource/aws_config_config_rule: Add `source.custom_policy_details` argument. +``` + +```release-note:enhancement +resource/aws_config_config_rule: Add plan time validation for `source.source_detail.event_source` and `source.source_detail.message_type`. +``` + +```release-note:enhancement +resource/aws_config_config_rule: Make `source.source_identifier` optional. +``` \ No newline at end of file diff --git a/website/docs/r/config_config_rule.html.markdown b/website/docs/r/config_config_rule.html.markdown index 4c56411d93f8..7b98583909ba 100644 --- a/website/docs/r/config_config_rule.html.markdown +++ b/website/docs/r/config_config_rule.html.markdown @@ -110,6 +110,39 @@ resource "aws_config_config_rule" "example" { } ``` + +### Custom Policies + +```terraform +resource "aws_config_config_rule" "example" { + name = "example" + + source { + owner = "CUSTOM_POLICY" + + source_detail { + message_type = "ConfigurationItemChangeNotification" + } + + custom_policy_details { + policy_runtime = "guard-2.x.x" + policy_text = < Date: Fri, 8 Apr 2022 15:43:42 +0300 Subject: [PATCH 7/9] fmt --- internal/service/configservice/config_rule_test.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/internal/service/configservice/config_rule_test.go b/internal/service/configservice/config_rule_test.go index c2901dfa6530..561c4f89e6dd 100644 --- a/internal/service/configservice/config_rule_test.go +++ b/internal/service/configservice/config_rule_test.go @@ -461,17 +461,16 @@ PARAMS func testAccConfigRuleConfig_ownerPolicy(rName string) string { return testAccConfigRuleConfig_base(rName) + fmt.Sprintf(` resource "aws_config_config_rule" "test" { - name = %q - description = "Terraform Acceptance tests" + name = %q source { - owner = "CUSTOM_POLICY" + owner = "CUSTOM_POLICY" source_detail { message_type = "ConfigurationItemChangeNotification" - } + } - custom_policy_details { + custom_policy_details { policy_runtime = "guard-2.x.x" policy_text = < Date: Fri, 8 Apr 2022 15:50:34 +0300 Subject: [PATCH 8/9] fix --- internal/service/configservice/flex.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/configservice/flex.go b/internal/service/configservice/flex.go index ccfef1e91311..42af6a899771 100644 --- a/internal/service/configservice/flex.go +++ b/internal/service/configservice/flex.go @@ -100,7 +100,7 @@ func expandRuleSource(configured []interface{}) *configservice.Source { Owner: aws.String(cfg["owner"].(string)), } - if v, ok := cfg["source_detail"].(string); ok && v != "" { + if v, ok := cfg["source_identifier"].(string); ok && v != "" { source.SourceIdentifier = aws.String(v) } From 5204f366c35ec054c8f8e02052be72617a62f636 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 8 Apr 2022 18:20:53 +0300 Subject: [PATCH 9/9] fix --- internal/service/configservice/config_rule_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/configservice/config_rule_test.go b/internal/service/configservice/config_rule_test.go index 561c4f89e6dd..2b02bee800c0 100644 --- a/internal/service/configservice/config_rule_test.go +++ b/internal/service/configservice/config_rule_test.go @@ -146,7 +146,6 @@ func testAccConfigRule_ownerPolicy(t *testing.T) { acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile("config-rule/config-rule-[a-z0-9]+$")), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestMatchResourceAttr(resourceName, "rule_id", regexp.MustCompile("config-rule-[a-z0-9]+$")), - resource.TestCheckResourceAttr(resourceName, "description", "Terraform Acceptance tests"), resource.TestCheckResourceAttr(resourceName, "source.#", "1"), resource.TestCheckResourceAttr(resourceName, "source.0.owner", "CUSTOM_POLICY"), resource.TestCheckResourceAttr(resourceName, "source.0.source_detail.#", "1"),