From f57a0cd33c31cc718429c89e9fd1e18aeca695c0 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 6 Aug 2020 12:57:48 -0400 Subject: [PATCH] resource/aws_accessanalyzer_analyzer: Support ORGANIZATION value in type argument Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12593 Output from acceptance testing in Organizations testing account: ``` --- PASS: TestAccAWSAccessAnalyzer_serial (344.90s) --- PASS: TestAccAWSAccessAnalyzer_serial/Analyzer (344.90s) --- PASS: TestAccAWSAccessAnalyzer_serial/Analyzer/basic (10.64s) --- PASS: TestAccAWSAccessAnalyzer_serial/Analyzer/disappears (7.41s) --- PASS: TestAccAWSAccessAnalyzer_serial/Analyzer/Tags (22.00s) --- PASS: TestAccAWSAccessAnalyzer_serial/Analyzer/Type_Organization (304.86s) ``` --- aws/resource_aws_accessanalyzer_analyzer.go | 30 +++++++++++- ...source_aws_accessanalyzer_analyzer_test.go | 49 +++++++++++++++++++ aws/resource_aws_accessanalyzer_test.go | 7 +-- .../r/accessanalyzer_analyzer.html.markdown | 19 ++++++- 4 files changed, 100 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_accessanalyzer_analyzer.go b/aws/resource_aws_accessanalyzer_analyzer.go index 1fbca1245ad..976e908452b 100644 --- a/aws/resource_aws_accessanalyzer_analyzer.go +++ b/aws/resource_aws_accessanalyzer_analyzer.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/accessanalyzer" @@ -12,6 +13,14 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) +const ( + // Maximum amount of time to wait for Organizations eventual consistency on creation + // This timeout value is much higher than usual since the cross-service validation + // appears to be consistently caching for 5 minutes: + // --- PASS: TestAccAWSAccessAnalyzer_serial/Analyzer/Type_Organization (315.86s) + accessAnalyzerOrganizationCreationTimeout = 10 * time.Minute +) + func resourceAwsAccessAnalyzerAnalyzer() *schema.Resource { return &schema.Resource{ Create: resourceAwsAccessAnalyzerAnalyzerCreate, @@ -37,9 +46,11 @@ func resourceAwsAccessAnalyzerAnalyzer() *schema.Resource { "type": { Type: schema.TypeString, Optional: true, + ForceNew: true, Default: accessanalyzer.TypeAccount, ValidateFunc: validation.StringInSlice([]string{ accessanalyzer.TypeAccount, + accessanalyzer.TypeOrganization, }, false), }, }, @@ -57,7 +68,24 @@ func resourceAwsAccessAnalyzerAnalyzerCreate(d *schema.ResourceData, meta interf Type: aws.String(d.Get("type").(string)), } - _, err := conn.CreateAnalyzer(input) + // Handle Organizations eventual consistency + err := resource.Retry(accessAnalyzerOrganizationCreationTimeout, func() *resource.RetryError { + _, err := conn.CreateAnalyzer(input) + + if isAWSErr(err, accessanalyzer.ErrCodeValidationException, "You must create an organization") { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if isResourceTimeoutError(err) { + _, err = conn.CreateAnalyzer(input) + } if err != nil { return fmt.Errorf("error creating Access Analyzer Analyzer (%s): %s", analyzerName, err) diff --git a/aws/resource_aws_accessanalyzer_analyzer_test.go b/aws/resource_aws_accessanalyzer_analyzer_test.go index 9e192184f48..a0b94018a15 100644 --- a/aws/resource_aws_accessanalyzer_analyzer_test.go +++ b/aws/resource_aws_accessanalyzer_analyzer_test.go @@ -112,6 +112,38 @@ func testAccAWSAccessAnalyzerAnalyzer_Tags(t *testing.T) { }) } +// This test can be run via the pattern: TestAccAWSAccessAnalyzer +func testAccAWSAccessAnalyzerAnalyzer_Type_Organization(t *testing.T) { + var analyzer accessanalyzer.AnalyzerSummary + + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_accessanalyzer_analyzer.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckAWSAccessAnalyzer(t) + testAccOrganizationsAccountPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAccessAnalyzerAnalyzerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAccessAnalyzerAnalyzerConfigTypeOrganization(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAccessAnalyzerAnalyzerExists(resourceName, &analyzer), + resource.TestCheckResourceAttr(resourceName, "type", accessanalyzer.TypeOrganization), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckAccessAnalyzerAnalyzerDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).accessanalyzerconn @@ -218,3 +250,20 @@ resource "aws_accessanalyzer_analyzer" "test" { } `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } + +func testAccAWSAccessAnalyzerAnalyzerConfigTypeOrganization(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_organizations_organization" "test" { + aws_service_access_principals = ["access-analyzer.${data.aws_partition.current.dns_suffix}"] +} + +resource "aws_accessanalyzer_analyzer" "test" { + depends_on = [aws_organizations_organization.test] + + analyzer_name = %[1]q + type = "ORGANIZATION" +} +`, rName) +} diff --git a/aws/resource_aws_accessanalyzer_test.go b/aws/resource_aws_accessanalyzer_test.go index f0be1162d0e..638025c99b1 100644 --- a/aws/resource_aws_accessanalyzer_test.go +++ b/aws/resource_aws_accessanalyzer_test.go @@ -11,9 +11,10 @@ import ( func TestAccAWSAccessAnalyzer_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "Analyzer": { - "basic": testAccAWSAccessAnalyzerAnalyzer_basic, - "disappears": testAccAWSAccessAnalyzerAnalyzer_disappears, - "Tags": testAccAWSAccessAnalyzerAnalyzer_Tags, + "basic": testAccAWSAccessAnalyzerAnalyzer_basic, + "disappears": testAccAWSAccessAnalyzerAnalyzer_disappears, + "Tags": testAccAWSAccessAnalyzerAnalyzer_Tags, + "Type_Organization": testAccAWSAccessAnalyzerAnalyzer_Type_Organization, }, } diff --git a/website/docs/r/accessanalyzer_analyzer.html.markdown b/website/docs/r/accessanalyzer_analyzer.html.markdown index 935ef405760..82cef7d93f5 100644 --- a/website/docs/r/accessanalyzer_analyzer.html.markdown +++ b/website/docs/r/accessanalyzer_analyzer.html.markdown @@ -12,12 +12,29 @@ Manages an Access Analyzer Analyzer. More information can be found in the [Acces ## Example Usage +### Account Analyzer + ```hcl resource "aws_accessanalyzer_analyzer" "example" { analyzer_name = "example" } ``` +### Organization Analyzer + +```hcl +resource "aws_organizations_organization" "example" { + aws_service_access_principals = ["access-analyzer.amazonaws.com"] +} + +resource "aws_accessanalyzer_analyzer" "example" { + depends_on = [aws_organizations_organization.example] + + analyzer_name = "example" + type = "ORGANIZATION" +} +``` + ## Argument Reference The following arguments are required: @@ -27,7 +44,7 @@ The following arguments are required: The following arguments are optional: * `tags` - (Optional) Key-value map of resource tags. -* `type` - (Optional) Type of Analyzer. Valid value is currently only `ACCOUNT`. Defaults to `ACCOUNT`. +* `type` - (Optional) Type of Analyzer. Valid values are `ACCOUNT` or `ORGANIZATION`. Defaults to `ACCOUNT`. ## Attributes Reference