From 3829d237ca9b3079dc9557817d36195859c0092e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20L=C3=B3pez?= Date: Fri, 14 May 2021 10:56:17 -0600 Subject: [PATCH 1/7] added resource and datasource for organizations delegated administrator, added datasource for delegated services --- ..._organizations_delegated_administrators.go | 108 +++++++++++++ ...nizations_delegated_administrators_test.go | 28 ++++ ...ce_aws_organizations_delegated_services.go | 74 +++++++++ ...s_organizations_delegated_services_test.go | 36 +++++ aws/provider.go | 3 + ...s_organizations_delegated_administrator.go | 131 +++++++++++++++ ...anizations_delegated_administrator_test.go | 150 ++++++++++++++++++ aws/resource_aws_organizations_test.go | 4 + ...ons_delegated_administrators.html.markdown | 36 +++++ ...nizations_delegated_services.html.markdown | 30 ++++ ...ions_delegated_administrator.html.markdown | 48 ++++++ 11 files changed, 648 insertions(+) create mode 100644 aws/data_source_aws_organizations_delegated_administrators.go create mode 100644 aws/data_source_aws_organizations_delegated_administrators_test.go create mode 100644 aws/data_source_aws_organizations_delegated_services.go create mode 100644 aws/data_source_aws_organizations_delegated_services_test.go create mode 100644 aws/resource_aws_organizations_delegated_administrator.go create mode 100644 aws/resource_aws_organizations_delegated_administrator_test.go create mode 100644 website/docs/d/organizations_delegated_administrators.html.markdown create mode 100644 website/docs/d/organizations_delegated_services.html.markdown create mode 100644 website/docs/r/organizations_delegated_administrator.html.markdown diff --git a/aws/data_source_aws_organizations_delegated_administrators.go b/aws/data_source_aws_organizations_delegated_administrators.go new file mode 100644 index 00000000000..2686beb821c --- /dev/null +++ b/aws/data_source_aws_organizations_delegated_administrators.go @@ -0,0 +1,108 @@ +package aws + +import ( + "context" + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func dataSourceAwsOrganizationsDelegatedAdministrators() *schema.Resource { + return &schema.Resource{ + ReadWithoutTimeout: dataSourceAwsOrganizationsDelegatedAdministratorsRead, + Schema: map[string]*schema.Schema{ + "service_principal": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + "delegated_administrators": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "delegation_enabled_date": { + Type: schema.TypeString, + Computed: true, + }, + "email": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "joined_method": { + Type: schema.TypeString, + Computed: true, + }, + "joined_timestamp": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceAwsOrganizationsDelegatedAdministratorsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).organizationsconn + + input := &organizations.ListDelegatedAdministratorsInput{} + + if v, ok := d.GetOk("service_principal"); ok { + input.ServicePrincipal = aws.String(v.(string)) + } + + org, err := conn.ListDelegatedAdministratorsWithContext(ctx, input) + if err != nil { + return diag.FromErr(fmt.Errorf("error describing organizations delegated Administrators: %w", err)) + } + + if err = d.Set("delegated_administrators", flattenOrganizationsDelegatedAdministrators(org.DelegatedAdministrators)); err != nil { + return diag.FromErr(fmt.Errorf("error setting delegated_Administrators: %w", err)) + } + + return nil +} + +func flattenOrganizationsDelegatedAdministrators(delegatedAdministrators []*organizations.DelegatedAdministrator) []map[string]interface{} { + if len(delegatedAdministrators) == 0 { + return nil + } + + var result []map[string]interface{} + for _, delegated := range delegatedAdministrators { + result = append(result, map[string]interface{}{ + "arn": aws.StringValue(delegated.Arn), + "delegation_enabled_date": aws.TimeValue(delegated.DelegationEnabledDate).Format(time.RFC3339), + "email": aws.StringValue(delegated.Email), + "id": aws.StringValue(delegated.Id), + "joined_method": aws.StringValue(delegated.JoinedMethod), + "joined_timestamp": aws.TimeValue(delegated.JoinedTimestamp).Format(time.RFC3339), + "name": aws.StringValue(delegated.Name), + "status": aws.StringValue(delegated.Status), + }) + } + return result +} diff --git a/aws/data_source_aws_organizations_delegated_administrators_test.go b/aws/data_source_aws_organizations_delegated_administrators_test.go new file mode 100644 index 00000000000..e53cc15c510 --- /dev/null +++ b/aws/data_source_aws_organizations_delegated_administrators_test.go @@ -0,0 +1,28 @@ +package aws + +import ( + "testing" + + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_basic(t *testing.T) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccOrganizationsAccountPreCheck(t) + }, + ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsOrganizationsDelegatedAdministratorsConfig, + }, + }, + }) +} + +const testAccDataSourceAwsOrganizationsDelegatedAdministratorsConfig = ` +data "aws_organizations_delegated_administrators" "test" {} +` diff --git a/aws/data_source_aws_organizations_delegated_services.go b/aws/data_source_aws_organizations_delegated_services.go new file mode 100644 index 00000000000..4de4370a5bf --- /dev/null +++ b/aws/data_source_aws_organizations_delegated_services.go @@ -0,0 +1,74 @@ +package aws + +import ( + "context" + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceAwsOrganizationsDelegatedServices() *schema.Resource { + return &schema.Resource{ + ReadWithoutTimeout: dataSourceAwsOrganizationsDelegatedServicesRead, + Schema: map[string]*schema.Schema{ + "account_id": { + Type: schema.TypeString, + Required: true, + }, + "delegated_services": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "delegation_enabled_date": { + Type: schema.TypeString, + Computed: true, + }, + "service_principal": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceAwsOrganizationsDelegatedServicesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).organizationsconn + + input := &organizations.ListDelegatedServicesForAccountInput{ + AccountId: aws.String(d.Get("account_id").(string)), + } + + org, err := conn.ListDelegatedServicesForAccountWithContext(ctx, input) + if err != nil { + return diag.FromErr(fmt.Errorf("error describing organizations delegated services: %w", err)) + } + + if err = d.Set("delegated_services", flattenOrganizationsDelegatedServices(org.DelegatedServices)); err != nil { + return diag.FromErr(fmt.Errorf("error setting delegated_services: %w", err)) + } + + return nil +} + +func flattenOrganizationsDelegatedServices(delegatedServices []*organizations.DelegatedService) []map[string]interface{} { + if len(delegatedServices) == 0 { + return nil + } + + var result []map[string]interface{} + for _, delegated := range delegatedServices { + result = append(result, map[string]interface{}{ + "delegation_enabled_date": aws.TimeValue(delegated.DelegationEnabledDate).Format(time.RFC3339), + "service_principal": aws.StringValue(delegated.ServicePrincipal), + }) + } + return result +} diff --git a/aws/data_source_aws_organizations_delegated_services_test.go b/aws/data_source_aws_organizations_delegated_services_test.go new file mode 100644 index 00000000000..276bfdb429a --- /dev/null +++ b/aws/data_source_aws_organizations_delegated_services_test.go @@ -0,0 +1,36 @@ +package aws + +import ( + "testing" + + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceAwsOrganizationsDelegatedServices_basic(t *testing.T) { + dataSourceName := "data.aws_organizations_delegated_services.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccOrganizationsAccountPreCheck(t) + }, + ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsOrganizationsDelegatedServicesConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckResourceAttrAccountID(dataSourceName, "account_id"), + ), + }, + }, + }) +} + +const testAccDataSourceAwsOrganizationsDelegatedServicesConfig = ` +data "aws_caller_identity" "current" {} + +data "aws_organizations_delegated_services" "test" { + account_id = data.aws_caller_identity.current.account_id +} +` diff --git a/aws/provider.go b/aws/provider.go index 9e6ef2c3179..778be47da03 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -345,6 +345,8 @@ func Provider() *schema.Provider { "aws_network_acls": dataSourceAwsNetworkAcls(), "aws_network_interface": dataSourceAwsNetworkInterface(), "aws_network_interfaces": dataSourceAwsNetworkInterfaces(), + "aws_organizations_delegated_administrators": dataSourceAwsOrganizationsDelegatedAdministrators(), + "aws_organizations_delegated_services": dataSourceAwsOrganizationsDelegatedServices(), "aws_organizations_organization": dataSourceAwsOrganizationsOrganization(), "aws_organizations_organizational_units": dataSourceAwsOrganizationsOrganizationalUnits(), "aws_outposts_outpost": dataSourceAwsOutpostsOutpost(), @@ -902,6 +904,7 @@ func Provider() *schema.Provider { "aws_opsworks_rds_db_instance": resourceAwsOpsworksRdsDbInstance(), "aws_organizations_organization": resourceAwsOrganizationsOrganization(), "aws_organizations_account": resourceAwsOrganizationsAccount(), + "aws_delegated_administrator": resourceAwsOrganizationsDelegatedAdministrator(), "aws_organizations_policy": resourceAwsOrganizationsPolicy(), "aws_organizations_policy_attachment": resourceAwsOrganizationsPolicyAttachment(), "aws_organizations_organizational_unit": resourceAwsOrganizationsOrganizationalUnit(), diff --git a/aws/resource_aws_organizations_delegated_administrator.go b/aws/resource_aws_organizations_delegated_administrator.go new file mode 100644 index 00000000000..02e33567f1a --- /dev/null +++ b/aws/resource_aws_organizations_delegated_administrator.go @@ -0,0 +1,131 @@ +package aws + +import ( + "context" + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceAwsOrganizationsDelegatedAdministrator() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceAwsOrganizationsDelegatedAdministratorCreate, + ReadWithoutTimeout: resourceAwsOrganizationsDelegatedAdministratorRead, + DeleteWithoutTimeout: resourceAwsOrganizationsDelegatedAdministratorDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + Schema: map[string]*schema.Schema{ + "account_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateAwsAccountId, + }, + "service_principal": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "delegation_enabled_date": { + Type: schema.TypeString, + Computed: true, + }, + "email": { + Type: schema.TypeString, + Computed: true, + }, + "joined_method": { + Type: schema.TypeString, + Computed: true, + }, + "joined_timestamp": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsOrganizationsDelegatedAdministratorCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).organizationsconn + + name := d.Get("name").(string) + accountID := d.Get("account_id").(string) + input := &organizations.RegisterDelegatedAdministratorInput{ + AccountId: aws.String(accountID), + ServicePrincipal: aws.String(d.Get("service_principal").(string)), + } + + _, err := conn.RegisterDelegatedAdministratorWithContext(ctx, input) + if err != nil { + return diag.FromErr(fmt.Errorf("error creating Organizations DelegatedAdministrator (%s): %w", name, err)) + } + + d.SetId(accountID) + + return resourceAwsOrganizationsDelegatedAdministratorRead(ctx, d, meta) +} + +func resourceAwsOrganizationsDelegatedAdministratorRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).organizationsconn + input := &organizations.ListDelegatedAdministratorsInput{ + ServicePrincipal: aws.String(d.Get("service_principal").(string)), + } + var delegatedAccount *organizations.DelegatedAdministrator + err := conn.ListDelegatedAdministratorsPagesWithContext(ctx, input, func(page *organizations.ListDelegatedAdministratorsOutput, lastPage bool) bool { + for _, delegated := range page.DelegatedAdministrators { + if aws.StringValue(delegated.Id) != d.Id() { + delegatedAccount = delegated + } + } + + return !lastPage + }) + if err != nil { + return diag.FromErr(fmt.Errorf("error listing AWS Organization (%s) DelegatedAdministrators: %w", d.Id(), err)) + } + + d.Set("arn", delegatedAccount.Arn) + d.Set("delegation_enabled_date", aws.TimeValue(delegatedAccount.DelegationEnabledDate).Format(time.RFC3339)) + d.Set("email", delegatedAccount.Email) + d.Set("joined_method", delegatedAccount.Status) + d.Set("joined_timestamp", aws.TimeValue(delegatedAccount.JoinedTimestamp).Format(time.RFC3339)) + d.Set("name", delegatedAccount.Name) + d.Set("status", delegatedAccount.Status) + + return nil +} + +func resourceAwsOrganizationsDelegatedAdministratorDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).organizationsconn + + input := &organizations.DeregisterDelegatedAdministratorInput{ + AccountId: aws.String(d.Id()), + ServicePrincipal: aws.String(d.Get("service_principal").(string)), + } + + _, err := conn.DeregisterDelegatedAdministratorWithContext(ctx, input) + if err != nil { + return diag.FromErr(fmt.Errorf("error deleting Organizations DelegatedAdministrator (%s): %w", d.Id(), err)) + } + return nil +} diff --git a/aws/resource_aws_organizations_delegated_administrator_test.go b/aws/resource_aws_organizations_delegated_administrator_test.go new file mode 100644 index 00000000000..5f0211ac6d9 --- /dev/null +++ b/aws/resource_aws_organizations_delegated_administrator_test.go @@ -0,0 +1,150 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func testAccAwsOrganizationsDelegatedAdministrator_basic(t *testing.T) { + var organization organizations.DelegatedAdministrator + resourceName := "aws_organizations_delegated_administrator.test" + servicePrincipal := "" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAwsOrganizationsDelegatedAdministratorDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsOrganizationsDelegatedAdministratorConfig(servicePrincipal), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsOrganizationsDelegatedAdministratorExists(resourceName, &organization), + testAccCheckResourceAttrAccountID(resourceName, "account_id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAwsOrganizationsDelegatedAdministrator_disappears(t *testing.T) { + var organization organizations.DelegatedAdministrator + resourceName := "aws_organizations_delegated_administrator.test" + servicePrincipal := "" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAwsOrganizationsDelegatedAdministratorDestroy, + ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), + Steps: []resource.TestStep{ + { + Config: testAccAwsOrganizationsDelegatedAdministratorConfig(servicePrincipal), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsOrganizationsDelegatedAdministratorExists(resourceName, &organization), + testAccCheckResourceDisappears(testAccProvider, resourceAwsOrganizationsDelegatedAdministrator(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAwsOrganizationsDelegatedAdministratorDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).organizationsconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_organizations_organization" { + continue + } + + input := &organizations.ListDelegatedAdministratorsInput{ + ServicePrincipal: aws.String(rs.Primary.Attributes["service_principal"]), + } + + exists := false + err := conn.ListDelegatedAdministratorsPages(input, func(page *organizations.ListDelegatedAdministratorsOutput, lastPage bool) bool { + for _, delegated := range page.DelegatedAdministrators { + if aws.StringValue(delegated.Id) != rs.Primary.ID { + exists = true + } + } + + return !lastPage + }) + + if err != nil { + return err + } + + if exists { + return fmt.Errorf("organization DelegatedAdministrator still exists: %q", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckAwsOrganizationsDelegatedAdministratorExists(n string, org *organizations.DelegatedAdministrator) 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("Organization ID not set") + } + + conn := testAccProvider.Meta().(*AWSClient).organizationsconn + input := &organizations.ListDelegatedAdministratorsInput{ + ServicePrincipal: aws.String(rs.Primary.Attributes["service_principal"]), + } + + exists := false + var resp *organizations.DelegatedAdministrator + err := conn.ListDelegatedAdministratorsPages(input, func(page *organizations.ListDelegatedAdministratorsOutput, lastPage bool) bool { + for _, delegated := range page.DelegatedAdministrators { + if aws.StringValue(delegated.Id) != rs.Primary.ID { + exists = true + resp = delegated + } + } + + return !lastPage + }) + + if err != nil { + return err + } + + if !exists { + return fmt.Errorf("organization DelegatedAdministrator %q does not exist", rs.Primary.ID) + } + + *org = *resp + + return nil + } +} + +func testAccAwsOrganizationsDelegatedAdministratorConfig(servicePrincipal string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +resource "aws_organizations_delegated_administrator" "test" { + account_id = data.aws_caller_identity.current.account_id + service_principal = %[1]q +} +`, servicePrincipal) +} diff --git a/aws/resource_aws_organizations_test.go b/aws/resource_aws_organizations_test.go index b01a75e766e..26ef8eef80f 100644 --- a/aws/resource_aws_organizations_test.go +++ b/aws/resource_aws_organizations_test.go @@ -46,6 +46,10 @@ func TestAccAWSOrganizations_serial(t *testing.T) { "OrganizationalUnit": testAccAwsOrganizationsPolicyAttachment_OrganizationalUnit, "Root": testAccAwsOrganizationsPolicyAttachment_Root, }, + "DelegatedAdministrator": { + "basic": testAccAwsOrganizationsDelegatedAdministrator_basic, + "disappears": testAccAwsOrganizationsDelegatedAdministrator_disappears, + }, } for group, m := range testCases { diff --git a/website/docs/d/organizations_delegated_administrators.html.markdown b/website/docs/d/organizations_delegated_administrators.html.markdown new file mode 100644 index 00000000000..b57767ec7cf --- /dev/null +++ b/website/docs/d/organizations_delegated_administrators.html.markdown @@ -0,0 +1,36 @@ +--- +subcategory: "Organizations" +layout: "aws" +page_title: "AWS: aws_organizations_delegated_administrators" +description: |- + Get a list the AWS accounts that are designated as delegated administrators in this organization +--- + +# Data Source: aws_organizations_delegated_administrators + +Get a list the AWS accounts that are designated as delegated administrators in this organization + +## Example Usage + +```terraform +data "aws_organizations_delegated_administrators" "example" { + service_principal = "SERVICE PRINCIPAL" +} +``` + + +## Argument Reference + +* `service_principal` - (Optional) Specifies a service principal name. If specified, then the operation lists the delegated administrators only for the specified service. If you don't specify a service principal, the operation lists all delegated administrators for all services in your organization. + +## Attributes Reference + +* `delegated_administrators` - The list of delegated administrators in your organization, which have the following attributes: + * `arn` - The Amazon Resource Name (ARN) of the delegated administrator's account. + * `delegation_enabled_date` - The date when the account was made a delegated administrator. + * `email` - The email address that is associated with the delegated administrator's AWS account. + * `id` - The unique identifier (ID) of the delegated administrator's account. + * `joined_method` - The method by which the delegated administrator's account joined the organization. + * `joined_timestamp` - The date when the delegated administrator's account became a part of the organization. + * `name` - The friendly name of the delegated administrator's account. + * `status` - The status of the delegated administrator's account in the organization. diff --git a/website/docs/d/organizations_delegated_services.html.markdown b/website/docs/d/organizations_delegated_services.html.markdown new file mode 100644 index 00000000000..63c5a81852a --- /dev/null +++ b/website/docs/d/organizations_delegated_services.html.markdown @@ -0,0 +1,30 @@ +--- +subcategory: "Organizations" +layout: "aws" +page_title: "AWS: aws_organizations_delegated_services" +description: |- + Get a list the AWS services for which the specified account is a delegated administrator +--- + +# Data Source: aws_organizations_delegated_services + +Get a list the AWS services for which the specified account is a delegated administrator + +## Example Usage + +```terraform +data "aws_organizations_delegated_services" "example" { + account_id = "AWS ACCOUNT ID" +} +``` + + +## Argument Reference + +* `account_id` - (Required) The account ID number of a delegated administrator account in the organization. + +## Attributes Reference + +* `delegated_services` - The services for which the account is a delegated administrator, which have the following attributes: + * `delegation_enabled_date` - The date that the account became a delegated administrator for this service. + * `service_principal` - The name of an AWS service that can request an operation for the specified service. diff --git a/website/docs/r/organizations_delegated_administrator.html.markdown b/website/docs/r/organizations_delegated_administrator.html.markdown new file mode 100644 index 00000000000..b0bf7a55a41 --- /dev/null +++ b/website/docs/r/organizations_delegated_administrator.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "Organizations" +layout: "aws" +page_title: "AWS: aws_organizations_delegated_administrator" +description: |- + Provides a resource to manage an AWS Organizations Delegated Administrator. +--- + +# Resource: aws_organizations_delegated_administrator + +Provides a resource to manage an [AWS Organizations Delegated Administrator](https://docs.aws.amazon.com/organizations/latest/APIReference/API_RegisterDelegatedAdministrator.html). + +## Example Usage + +```terraform +resource "aws_organizations_delegated_administrator" "example" { + account_id = "AWS ACCOUNT ID" + service_principal = "Service principal" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `account_id` - (Required) The account ID number of the member account in the organization to register as a delegated administrator. +* `service_principal` - The service principal of the AWS service for which you want to make the member account a delegated administrator. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The unique identifier (ID) of the delegated administrator. +* `arn` - The Amazon Resource Name (ARN) of the delegated administrator's account. +* `delegation_enabled_date` - The date when the account was made a delegated administrator. +* `email` - The email address that is associated with the delegated administrator's AWS account. +* `joined_method` - The method by which the delegated administrator's account joined the organization. +* `joined_timestamp` - The date when the delegated administrator's account became a part of the organization. +* `name` - The friendly name of the delegated administrator's account. +* `status` - The status of the delegated administrator's account in the organization. + +## Import + +`aws_organizations_delegated_administrator` can be imported by using the account ID, e.g. + +``` +$ terraform import aws_organizations_delegated_administrator.example 123456789012 +``` From 21bc15cc4db587def6b02e8ee7f24b506f5d4592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20L=C3=B3pez?= Date: Fri, 14 May 2021 12:10:37 -0600 Subject: [PATCH 2/7] fixes typo --- aws/provider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/provider.go b/aws/provider.go index 778be47da03..dec0ccc9952 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -904,7 +904,7 @@ func Provider() *schema.Provider { "aws_opsworks_rds_db_instance": resourceAwsOpsworksRdsDbInstance(), "aws_organizations_organization": resourceAwsOrganizationsOrganization(), "aws_organizations_account": resourceAwsOrganizationsAccount(), - "aws_delegated_administrator": resourceAwsOrganizationsDelegatedAdministrator(), + "aws_organizations_delegated_administrator": resourceAwsOrganizationsDelegatedAdministrator(), "aws_organizations_policy": resourceAwsOrganizationsPolicy(), "aws_organizations_policy_attachment": resourceAwsOrganizationsPolicyAttachment(), "aws_organizations_organizational_unit": resourceAwsOrganizationsOrganizationalUnit(), From 488b604c3ad84282242c5849c899b2498d0ca825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20L=C3=B3pez?= Date: Fri, 14 May 2021 18:37:07 -0600 Subject: [PATCH 3/7] added provier awsalternate for testing, fixes some typo --- ..._organizations_delegated_administrators.go | 2 + ...nizations_delegated_administrators_test.go | 38 +++++++++++-- ...ce_aws_organizations_delegated_services.go | 2 + ...s_organizations_delegated_services_test.go | 22 ++++--- ...s_organizations_delegated_administrator.go | 47 +++++++++++---- ...anizations_delegated_administrator_test.go | 57 +++++++++++++------ ...ions_delegated_administrator.html.markdown | 4 +- 7 files changed, 130 insertions(+), 42 deletions(-) diff --git a/aws/data_source_aws_organizations_delegated_administrators.go b/aws/data_source_aws_organizations_delegated_administrators.go index 2686beb821c..4b95912f74c 100644 --- a/aws/data_source_aws_organizations_delegated_administrators.go +++ b/aws/data_source_aws_organizations_delegated_administrators.go @@ -83,6 +83,8 @@ func dataSourceAwsOrganizationsDelegatedAdministratorsRead(ctx context.Context, return diag.FromErr(fmt.Errorf("error setting delegated_Administrators: %w", err)) } + d.SetId(meta.(*AWSClient).accountid) + return nil } diff --git a/aws/data_source_aws_organizations_delegated_administrators_test.go b/aws/data_source_aws_organizations_delegated_administrators_test.go index e53cc15c510..e9589f573da 100644 --- a/aws/data_source_aws_organizations_delegated_administrators_test.go +++ b/aws/data_source_aws_organizations_delegated_administrators_test.go @@ -1,28 +1,54 @@ package aws import ( + "fmt" "testing" "github.com/aws/aws-sdk-go/service/organizations" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_basic(t *testing.T) { + var providers []*schema.Provider + dataSourceName := "data.aws_organizations_delegated_administrators.test" + servicePrincipal := "config-multiaccountsetup.amazonaws.com" + dataSourceIdentity := "data.aws_caller_identity.delegated" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - testAccOrganizationsAccountPreCheck(t) + testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), - ProviderFactories: testAccProviderFactories, + ProviderFactories: testAccProviderFactoriesAlternate(&providers), Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsOrganizationsDelegatedAdministratorsConfig, + Config: testAccDataSourceAwsOrganizationsDelegatedAdministratorsConfig(servicePrincipal), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "delegated_administrators.#", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "delegated_administrators.0.id", dataSourceIdentity, "account_id"), + testAccCheckResourceAttrRfc3339(dataSourceName, "delegated_administrators.0.delegation_enabled_date"), + testAccCheckResourceAttrRfc3339(dataSourceName, "delegated_administrators.0.joined_timestamp"), + ), }, }, }) } -const testAccDataSourceAwsOrganizationsDelegatedAdministratorsConfig = ` -data "aws_organizations_delegated_administrators" "test" {} -` +func testAccDataSourceAwsOrganizationsDelegatedAdministratorsConfig(servicePrincipal string) string { + return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` +data "aws_caller_identity" "delegated" { + provider = "awsalternate" +} + +resource "aws_organizations_delegated_administrator" "test" { + account_id = data.aws_caller_identity.delegated.account_id + service_principal = %[1]q +} + +data "aws_organizations_delegated_administrators" "test" { + service_principal = aws_organizations_delegated_administrator.test.service_principal +} +`, servicePrincipal) +} diff --git a/aws/data_source_aws_organizations_delegated_services.go b/aws/data_source_aws_organizations_delegated_services.go index 4de4370a5bf..85b2eb13b0c 100644 --- a/aws/data_source_aws_organizations_delegated_services.go +++ b/aws/data_source_aws_organizations_delegated_services.go @@ -55,6 +55,8 @@ func dataSourceAwsOrganizationsDelegatedServicesRead(ctx context.Context, d *sch return diag.FromErr(fmt.Errorf("error setting delegated_services: %w", err)) } + d.SetId(meta.(*AWSClient).accountid) + return nil } diff --git a/aws/data_source_aws_organizations_delegated_services_test.go b/aws/data_source_aws_organizations_delegated_services_test.go index 276bfdb429a..22709247607 100644 --- a/aws/data_source_aws_organizations_delegated_services_test.go +++ b/aws/data_source_aws_organizations_delegated_services_test.go @@ -5,32 +5,40 @@ import ( "github.com/aws/aws-sdk-go/service/organizations" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func TestAccDataSourceAwsOrganizationsDelegatedServices_basic(t *testing.T) { + var providers []*schema.Provider dataSourceName := "data.aws_organizations_delegated_services.test" + dataSourceIdentity := "data.aws_caller_identity.delegated" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - testAccOrganizationsAccountPreCheck(t) + testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), - ProviderFactories: testAccProviderFactories, + ProviderFactories: testAccProviderFactoriesAlternate(&providers), Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsOrganizationsDelegatedServicesConfig, + Config: testAccDataSourceAwsOrganizationsDelegatedServicesConfig(), Check: resource.ComposeTestCheckFunc( - testAccCheckResourceAttrAccountID(dataSourceName, "account_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "account_id", dataSourceIdentity, "account_id"), ), }, }, }) } -const testAccDataSourceAwsOrganizationsDelegatedServicesConfig = ` -data "aws_caller_identity" "current" {} +func testAccDataSourceAwsOrganizationsDelegatedServicesConfig() string { + return testAccAlternateAccountProviderConfig() + ` +data "aws_caller_identity" "delegated" { + provider = "awsalternate" +} data "aws_organizations_delegated_services" "test" { - account_id = data.aws_caller_identity.current.account_id + account_id = data.aws_caller_identity.delegated.account_id } ` +} diff --git a/aws/resource_aws_organizations_delegated_administrator.go b/aws/resource_aws_organizations_delegated_administrator.go index 02e33567f1a..662e7181a87 100644 --- a/aws/resource_aws_organizations_delegated_administrator.go +++ b/aws/resource_aws_organizations_delegated_administrator.go @@ -3,6 +3,8 @@ package aws import ( "context" "fmt" + "log" + "strings" "time" "github.com/aws/aws-sdk-go/aws" @@ -68,32 +70,37 @@ func resourceAwsOrganizationsDelegatedAdministrator() *schema.Resource { func resourceAwsOrganizationsDelegatedAdministratorCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).organizationsconn - name := d.Get("name").(string) accountID := d.Get("account_id").(string) + servicePrincipal := d.Get("service_principal").(string) input := &organizations.RegisterDelegatedAdministratorInput{ AccountId: aws.String(accountID), - ServicePrincipal: aws.String(d.Get("service_principal").(string)), + ServicePrincipal: aws.String(servicePrincipal), } _, err := conn.RegisterDelegatedAdministratorWithContext(ctx, input) if err != nil { - return diag.FromErr(fmt.Errorf("error creating Organizations DelegatedAdministrator (%s): %w", name, err)) + return diag.FromErr(fmt.Errorf("error creating Organizations DelegatedAdministrator (%s): %w", accountID, err)) } - d.SetId(accountID) + d.SetId(fmt.Sprintf("%s/%s", accountID, servicePrincipal)) return resourceAwsOrganizationsDelegatedAdministratorRead(ctx, d, meta) } func resourceAwsOrganizationsDelegatedAdministratorRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).organizationsconn + + accountID, servicePrincipal, err := decodeOrganizationDelegatedAdministratorID(d.Id()) + if err != nil { + return diag.FromErr(fmt.Errorf("error decoding ID AWS Organization (%s) DelegatedAdministrators: %w", d.Id(), err)) + } input := &organizations.ListDelegatedAdministratorsInput{ - ServicePrincipal: aws.String(d.Get("service_principal").(string)), + ServicePrincipal: aws.String(servicePrincipal), } var delegatedAccount *organizations.DelegatedAdministrator - err := conn.ListDelegatedAdministratorsPagesWithContext(ctx, input, func(page *organizations.ListDelegatedAdministratorsOutput, lastPage bool) bool { + err = conn.ListDelegatedAdministratorsPagesWithContext(ctx, input, func(page *organizations.ListDelegatedAdministratorsOutput, lastPage bool) bool { for _, delegated := range page.DelegatedAdministrators { - if aws.StringValue(delegated.Id) != d.Id() { + if aws.StringValue(delegated.Id) == accountID { delegatedAccount = delegated } } @@ -104,6 +111,12 @@ func resourceAwsOrganizationsDelegatedAdministratorRead(ctx context.Context, d * return diag.FromErr(fmt.Errorf("error listing AWS Organization (%s) DelegatedAdministrators: %w", d.Id(), err)) } + if delegatedAccount == nil { + log.Printf("[WARN] AWS Organization DelegatedAdministrators not found (%s), removing from state", d.Id()) + d.SetId("") + return nil + } + d.Set("arn", delegatedAccount.Arn) d.Set("delegation_enabled_date", aws.TimeValue(delegatedAccount.DelegationEnabledDate).Format(time.RFC3339)) d.Set("email", delegatedAccount.Email) @@ -111,6 +124,8 @@ func resourceAwsOrganizationsDelegatedAdministratorRead(ctx context.Context, d * d.Set("joined_timestamp", aws.TimeValue(delegatedAccount.JoinedTimestamp).Format(time.RFC3339)) d.Set("name", delegatedAccount.Name) d.Set("status", delegatedAccount.Status) + d.Set("account_id", accountID) + d.Set("service_principal", servicePrincipal) return nil } @@ -118,14 +133,26 @@ func resourceAwsOrganizationsDelegatedAdministratorRead(ctx context.Context, d * func resourceAwsOrganizationsDelegatedAdministratorDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).organizationsconn + accountID, servicePrincipal, err := decodeOrganizationDelegatedAdministratorID(d.Id()) + if err != nil { + return diag.FromErr(fmt.Errorf("error decoding ID AWS Organization (%s) DelegatedAdministrators: %w", d.Id(), err)) + } input := &organizations.DeregisterDelegatedAdministratorInput{ - AccountId: aws.String(d.Id()), - ServicePrincipal: aws.String(d.Get("service_principal").(string)), + AccountId: aws.String(accountID), + ServicePrincipal: aws.String(servicePrincipal), } - _, err := conn.DeregisterDelegatedAdministratorWithContext(ctx, input) + _, err = conn.DeregisterDelegatedAdministratorWithContext(ctx, input) if err != nil { return diag.FromErr(fmt.Errorf("error deleting Organizations DelegatedAdministrator (%s): %w", d.Id(), err)) } return nil } + +func decodeOrganizationDelegatedAdministratorID(id string) (string, string, error) { + idParts := strings.Split(id, "/") + if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { + return "", "", fmt.Errorf("expected ID in the form of account_id/service_principal, given: %q", id) + } + return idParts[0], idParts[1], nil +} diff --git a/aws/resource_aws_organizations_delegated_administrator_test.go b/aws/resource_aws_organizations_delegated_administrator_test.go index 5f0211ac6d9..f91088ba042 100644 --- a/aws/resource_aws_organizations_delegated_administrator_test.go +++ b/aws/resource_aws_organizations_delegated_administrator_test.go @@ -7,25 +7,34 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/organizations" "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/terraform" ) func testAccAwsOrganizationsDelegatedAdministrator_basic(t *testing.T) { + var providers []*schema.Provider var organization organizations.DelegatedAdministrator resourceName := "aws_organizations_delegated_administrator.test" - servicePrincipal := "" + servicePrincipal := "config-multiaccountsetup.amazonaws.com" + dataSourceIdentity := "data.aws_caller_identity.delegated" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), - ProviderFactories: testAccProviderFactories, + ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsOrganizationsDelegatedAdministratorDestroy, Steps: []resource.TestStep{ { Config: testAccAwsOrganizationsDelegatedAdministratorConfig(servicePrincipal), Check: resource.ComposeTestCheckFunc( testAccCheckAwsOrganizationsDelegatedAdministratorExists(resourceName, &organization), - testAccCheckResourceAttrAccountID(resourceName, "account_id"), + resource.TestCheckResourceAttrPair(resourceName, "account_id", dataSourceIdentity, "account_id"), + resource.TestCheckResourceAttr(resourceName, "service_principal", servicePrincipal), + testAccCheckResourceAttrRfc3339(resourceName, "delegation_enabled_date"), + testAccCheckResourceAttrRfc3339(resourceName, "joined_timestamp"), ), }, { @@ -38,13 +47,17 @@ func testAccAwsOrganizationsDelegatedAdministrator_basic(t *testing.T) { } func testAccAwsOrganizationsDelegatedAdministrator_disappears(t *testing.T) { + var providers []*schema.Provider var organization organizations.DelegatedAdministrator resourceName := "aws_organizations_delegated_administrator.test" - servicePrincipal := "" + servicePrincipal := "config-multiaccountsetup.amazonaws.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactories, + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsOrganizationsDelegatedAdministratorDestroy, ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), Steps: []resource.TestStep{ @@ -64,18 +77,22 @@ func testAccCheckAwsOrganizationsDelegatedAdministratorDestroy(s *terraform.Stat conn := testAccProvider.Meta().(*AWSClient).organizationsconn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_organizations_organization" { + if rs.Type != "aws_organizations_delegated_administrator" { continue } + accountID, servicePrincipal, err := decodeOrganizationDelegatedAdministratorID(rs.Primary.ID) + if err != nil { + return err + } input := &organizations.ListDelegatedAdministratorsInput{ - ServicePrincipal: aws.String(rs.Primary.Attributes["service_principal"]), + ServicePrincipal: aws.String(servicePrincipal), } exists := false - err := conn.ListDelegatedAdministratorsPages(input, func(page *organizations.ListDelegatedAdministratorsOutput, lastPage bool) bool { + err = conn.ListDelegatedAdministratorsPages(input, func(page *organizations.ListDelegatedAdministratorsOutput, lastPage bool) bool { for _, delegated := range page.DelegatedAdministrators { - if aws.StringValue(delegated.Id) != rs.Primary.ID { + if aws.StringValue(delegated.Id) == accountID { exists = true } } @@ -106,16 +123,20 @@ func testAccCheckAwsOrganizationsDelegatedAdministratorExists(n string, org *org return fmt.Errorf("Organization ID not set") } + accountID, servicePrincipal, err := decodeOrganizationDelegatedAdministratorID(rs.Primary.ID) + if err != nil { + return err + } conn := testAccProvider.Meta().(*AWSClient).organizationsconn input := &organizations.ListDelegatedAdministratorsInput{ - ServicePrincipal: aws.String(rs.Primary.Attributes["service_principal"]), + ServicePrincipal: aws.String(servicePrincipal), } exists := false var resp *organizations.DelegatedAdministrator - err := conn.ListDelegatedAdministratorsPages(input, func(page *organizations.ListDelegatedAdministratorsOutput, lastPage bool) bool { + err = conn.ListDelegatedAdministratorsPages(input, func(page *organizations.ListDelegatedAdministratorsOutput, lastPage bool) bool { for _, delegated := range page.DelegatedAdministrators { - if aws.StringValue(delegated.Id) != rs.Primary.ID { + if aws.StringValue(delegated.Id) == accountID { exists = true resp = delegated } @@ -139,11 +160,13 @@ func testAccCheckAwsOrganizationsDelegatedAdministratorExists(n string, org *org } func testAccAwsOrganizationsDelegatedAdministratorConfig(servicePrincipal string) string { - return fmt.Sprintf(` -data "aws_caller_identity" "current" {} + return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` +data "aws_caller_identity" "delegated" { + provider = "awsalternate" +} resource "aws_organizations_delegated_administrator" "test" { - account_id = data.aws_caller_identity.current.account_id + account_id = data.aws_caller_identity.delegated.account_id service_principal = %[1]q } `, servicePrincipal) diff --git a/website/docs/r/organizations_delegated_administrator.html.markdown b/website/docs/r/organizations_delegated_administrator.html.markdown index b0bf7a55a41..cf607f0eb8d 100644 --- a/website/docs/r/organizations_delegated_administrator.html.markdown +++ b/website/docs/r/organizations_delegated_administrator.html.markdown @@ -41,8 +41,8 @@ In addition to all arguments above, the following attributes are exported: ## Import -`aws_organizations_delegated_administrator` can be imported by using the account ID, e.g. +`aws_organizations_delegated_administrator` can be imported by using the account ID and its service principal, e.g. ``` -$ terraform import aws_organizations_delegated_administrator.example 123456789012 +$ terraform import aws_organizations_delegated_administrator.example 123456789012/config.amazonaws.com ``` From cf798825a3649129b0fc3cb325e002a4cbee34bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20L=C3=B3pez?= Date: Fri, 14 May 2021 18:46:19 -0600 Subject: [PATCH 4/7] fixes linter terrafmt --- aws/data_source_aws_organizations_delegated_services_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/data_source_aws_organizations_delegated_services_test.go b/aws/data_source_aws_organizations_delegated_services_test.go index 22709247607..9efbac819a0 100644 --- a/aws/data_source_aws_organizations_delegated_services_test.go +++ b/aws/data_source_aws_organizations_delegated_services_test.go @@ -38,7 +38,7 @@ data "aws_caller_identity" "delegated" { } data "aws_organizations_delegated_services" "test" { - account_id = data.aws_caller_identity.delegated.account_id + account_id = data.aws_caller_identity.delegated.account_id } ` } From 52553e51a71e99b0e7e4ede9bc9e3a6688acc894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20L=C3=B3pez?= Date: Fri, 14 May 2021 18:56:08 -0600 Subject: [PATCH 5/7] added changelog file --- .changelog/19389.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changelog/19389.txt diff --git a/.changelog/19389.txt b/.changelog/19389.txt new file mode 100644 index 00000000000..e03772359b0 --- /dev/null +++ b/.changelog/19389.txt @@ -0,0 +1,11 @@ +```release-note:new-resource +aws_organizations_delegated_administrator +``` + +```release-note:new-data-source +aws_organizations_delegated_administrators +``` + +```release-note:new-data-source +aws_organizations_delegated_services +``` \ No newline at end of file From 25880dec8b76ec61615da3ff5356c67f859d2e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20L=C3=B3pez?= Date: Tue, 18 May 2021 12:03:01 -0600 Subject: [PATCH 6/7] refactorized, added more test --- ..._organizations_delegated_administrators.go | 18 +++-- ...nizations_delegated_administrators_test.go | 71 ++++++++++++++++++- ...ce_aws_organizations_delegated_services.go | 20 ++++-- ...s_organizations_delegated_services_test.go | 48 ++++++++++++- ...s_organizations_delegated_administrator.go | 2 +- ...ions_delegated_administrator.html.markdown | 2 +- 6 files changed, 148 insertions(+), 13 deletions(-) diff --git a/aws/data_source_aws_organizations_delegated_administrators.go b/aws/data_source_aws_organizations_delegated_administrators.go index 4b95912f74c..8a365cd239b 100644 --- a/aws/data_source_aws_organizations_delegated_administrators.go +++ b/aws/data_source_aws_organizations_delegated_administrators.go @@ -22,7 +22,7 @@ func dataSourceAwsOrganizationsDelegatedAdministrators() *schema.Resource { ValidateFunc: validation.StringLenBetween(1, 128), }, "delegated_administrators": { - Type: schema.TypeList, + Type: schema.TypeSet, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -74,13 +74,23 @@ func dataSourceAwsOrganizationsDelegatedAdministratorsRead(ctx context.Context, input.ServicePrincipal = aws.String(v.(string)) } - org, err := conn.ListDelegatedAdministratorsWithContext(ctx, input) + var delegators []*organizations.DelegatedAdministrator + + err := conn.ListDelegatedAdministratorsPagesWithContext(ctx, input, func(page *organizations.ListDelegatedAdministratorsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + delegators = page.DelegatedAdministrators + + return !lastPage + }) if err != nil { return diag.FromErr(fmt.Errorf("error describing organizations delegated Administrators: %w", err)) } - if err = d.Set("delegated_administrators", flattenOrganizationsDelegatedAdministrators(org.DelegatedAdministrators)); err != nil { - return diag.FromErr(fmt.Errorf("error setting delegated_Administrators: %w", err)) + if err = d.Set("delegated_administrators", flattenOrganizationsDelegatedAdministrators(delegators)); err != nil { + return diag.FromErr(fmt.Errorf("error setting delegated_administrators: %w", err)) } d.SetId(meta.(*AWSClient).accountid) diff --git a/aws/data_source_aws_organizations_delegated_administrators_test.go b/aws/data_source_aws_organizations_delegated_administrators_test.go index e9589f573da..6efb09f1aff 100644 --- a/aws/data_source_aws_organizations_delegated_administrators_test.go +++ b/aws/data_source_aws_organizations_delegated_administrators_test.go @@ -15,7 +15,7 @@ func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_basic(t *testing.T servicePrincipal := "config-multiaccountsetup.amazonaws.com" dataSourceIdentity := "data.aws_caller_identity.delegated" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) testAccAlternateAccountPreCheck(t) @@ -36,6 +36,60 @@ func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_basic(t *testing.T }) } +func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_servicePrincipal(t *testing.T) { + var providers []*schema.Provider + dataSourceName := "data.aws_organizations_delegated_administrators.test" + servicePrincipal := "config-multiaccountsetup.amazonaws.com" + dataSourceIdentity := "data.aws_caller_identity.delegated" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), + ProviderFactories: testAccProviderFactoriesAlternate(&providers), + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsOrganizationsDelegatedAdministratorsServicePrincipalConfig(servicePrincipal), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "delegated_administrators.#", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "delegated_administrators.0.id", dataSourceIdentity, "account_id"), + testAccCheckResourceAttrRfc3339(dataSourceName, "delegated_administrators.0.delegation_enabled_date"), + testAccCheckResourceAttrRfc3339(dataSourceName, "delegated_administrators.0.joined_timestamp"), + ), + }, + }, + }) +} + +func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_empty(t *testing.T) { + dataSourceName := "data.aws_organizations_delegated_administrators.test" + servicePrincipal := "config-multiaccountsetup.amazonaws.com" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsOrganizationsDelegatedAdministratorsEmptyConfig(servicePrincipal), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "delegated_administrators.#", "0"), + ), + }, + }, + }) +} + +func testAccDataSourceAwsOrganizationsDelegatedAdministratorsEmptyConfig(servicePrincipal string) string { + return fmt.Sprintf(` +data "aws_organizations_delegated_administrators" "test" { + service_principal = %[1]q +} +`, servicePrincipal) +} + func testAccDataSourceAwsOrganizationsDelegatedAdministratorsConfig(servicePrincipal string) string { return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` data "aws_caller_identity" "delegated" { @@ -47,6 +101,21 @@ resource "aws_organizations_delegated_administrator" "test" { service_principal = %[1]q } +data "aws_organizations_delegated_administrators" "test" {} +`, servicePrincipal) +} + +func testAccDataSourceAwsOrganizationsDelegatedAdministratorsServicePrincipalConfig(servicePrincipal string) string { + return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` +data "aws_caller_identity" "delegated" { + provider = "awsalternate" +} + +resource "aws_organizations_delegated_administrator" "test" { + account_id = data.aws_caller_identity.delegated.account_id + service_principal = %[1]q +} + data "aws_organizations_delegated_administrators" "test" { service_principal = aws_organizations_delegated_administrator.test.service_principal } diff --git a/aws/data_source_aws_organizations_delegated_services.go b/aws/data_source_aws_organizations_delegated_services.go index 85b2eb13b0c..b8482a378ce 100644 --- a/aws/data_source_aws_organizations_delegated_services.go +++ b/aws/data_source_aws_organizations_delegated_services.go @@ -16,11 +16,12 @@ func dataSourceAwsOrganizationsDelegatedServices() *schema.Resource { ReadWithoutTimeout: dataSourceAwsOrganizationsDelegatedServicesRead, Schema: map[string]*schema.Schema{ "account_id": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validateAwsAccountId, }, "delegated_services": { - Type: schema.TypeList, + Type: schema.TypeSet, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -46,12 +47,21 @@ func dataSourceAwsOrganizationsDelegatedServicesRead(ctx context.Context, d *sch AccountId: aws.String(d.Get("account_id").(string)), } - org, err := conn.ListDelegatedServicesForAccountWithContext(ctx, input) + var delegators []*organizations.DelegatedService + err := conn.ListDelegatedServicesForAccountPagesWithContext(ctx, input, func(page *organizations.ListDelegatedServicesForAccountOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + delegators = page.DelegatedServices + + return !lastPage + }) if err != nil { return diag.FromErr(fmt.Errorf("error describing organizations delegated services: %w", err)) } - if err = d.Set("delegated_services", flattenOrganizationsDelegatedServices(org.DelegatedServices)); err != nil { + if err = d.Set("delegated_services", flattenOrganizationsDelegatedServices(delegators)); err != nil { return diag.FromErr(fmt.Errorf("error setting delegated_services: %w", err)) } diff --git a/aws/data_source_aws_organizations_delegated_services_test.go b/aws/data_source_aws_organizations_delegated_services_test.go index 9efbac819a0..d1b0100f8fc 100644 --- a/aws/data_source_aws_organizations_delegated_services_test.go +++ b/aws/data_source_aws_organizations_delegated_services_test.go @@ -1,6 +1,7 @@ package aws import ( + "fmt" "testing" "github.com/aws/aws-sdk-go/service/organizations" @@ -13,7 +14,7 @@ func TestAccDataSourceAwsOrganizationsDelegatedServices_basic(t *testing.T) { dataSourceName := "data.aws_organizations_delegated_services.test" dataSourceIdentity := "data.aws_caller_identity.delegated" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) testAccAlternateAccountPreCheck(t) @@ -24,6 +25,7 @@ func TestAccDataSourceAwsOrganizationsDelegatedServices_basic(t *testing.T) { { Config: testAccDataSourceAwsOrganizationsDelegatedServicesConfig(), Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "delegated_services.#", "0"), resource.TestCheckResourceAttrPair(dataSourceName, "account_id", dataSourceIdentity, "account_id"), ), }, @@ -31,6 +33,33 @@ func TestAccDataSourceAwsOrganizationsDelegatedServices_basic(t *testing.T) { }) } +func TestAccDataSourceAwsOrganizationsDelegatedServices_administrator(t *testing.T) { + var providers []*schema.Provider + dataSourceName := "data.aws_organizations_delegated_services.test" + dataSourceIdentity := "data.aws_caller_identity.delegated" + servicePrincipal := "config-multiaccountsetup.amazonaws.com" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), + ProviderFactories: testAccProviderFactoriesAlternate(&providers), + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsOrganizationsDelegatedServicesAdministratorConfig(servicePrincipal), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "delegated_services.#", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "account_id", dataSourceIdentity, "account_id"), + testAccCheckResourceAttrRfc3339(dataSourceName, "delegated_services.0.delegation_enabled_date"), + resource.TestCheckResourceAttr(dataSourceName, "delegated_services.0.service_principal", servicePrincipal), + ), + }, + }, + }) +} + func testAccDataSourceAwsOrganizationsDelegatedServicesConfig() string { return testAccAlternateAccountProviderConfig() + ` data "aws_caller_identity" "delegated" { @@ -42,3 +71,20 @@ data "aws_organizations_delegated_services" "test" { } ` } + +func testAccDataSourceAwsOrganizationsDelegatedServicesAdministratorConfig(servicePrincipal string) string { + return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` +data "aws_caller_identity" "delegated" { + provider = "awsalternate" +} + +resource "aws_organizations_delegated_administrator" "delegated" { + account_id = data.aws_caller_identity.delegated.account_id + service_principal = %[1]q +} + +data "aws_organizations_delegated_services" "test" { + account_id = aws_organizations_delegated_administrator.delegated.account_id +} +`, servicePrincipal) +} diff --git a/aws/resource_aws_organizations_delegated_administrator.go b/aws/resource_aws_organizations_delegated_administrator.go index 662e7181a87..e51909730df 100644 --- a/aws/resource_aws_organizations_delegated_administrator.go +++ b/aws/resource_aws_organizations_delegated_administrator.go @@ -120,7 +120,7 @@ func resourceAwsOrganizationsDelegatedAdministratorRead(ctx context.Context, d * d.Set("arn", delegatedAccount.Arn) d.Set("delegation_enabled_date", aws.TimeValue(delegatedAccount.DelegationEnabledDate).Format(time.RFC3339)) d.Set("email", delegatedAccount.Email) - d.Set("joined_method", delegatedAccount.Status) + d.Set("joined_method", delegatedAccount.JoinedMethod) d.Set("joined_timestamp", aws.TimeValue(delegatedAccount.JoinedTimestamp).Format(time.RFC3339)) d.Set("name", delegatedAccount.Name) d.Set("status", delegatedAccount.Status) diff --git a/website/docs/r/organizations_delegated_administrator.html.markdown b/website/docs/r/organizations_delegated_administrator.html.markdown index cf607f0eb8d..0e7f70820d2 100644 --- a/website/docs/r/organizations_delegated_administrator.html.markdown +++ b/website/docs/r/organizations_delegated_administrator.html.markdown @@ -24,7 +24,7 @@ resource "aws_organizations_delegated_administrator" "example" { The following arguments are supported: * `account_id` - (Required) The account ID number of the member account in the organization to register as a delegated administrator. -* `service_principal` - The service principal of the AWS service for which you want to make the member account a delegated administrator. +* `service_principal` - (Required) The service principal of the AWS service for which you want to make the member account a delegated administrator. ## Attributes Reference From 1e9d8208748949d3481914765daaa1c6d697a89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20L=C3=B3pez?= Date: Tue, 18 May 2021 16:47:25 -0600 Subject: [PATCH 7/7] refactorized --- ..._organizations_delegated_administrators.go | 2 +- ...nizations_delegated_administrators_test.go | 52 ++++++++++++++- ...ce_aws_organizations_delegated_services.go | 2 +- ...s_organizations_delegated_services_test.go | 64 +++++++++++++++++-- 4 files changed, 110 insertions(+), 10 deletions(-) diff --git a/aws/data_source_aws_organizations_delegated_administrators.go b/aws/data_source_aws_organizations_delegated_administrators.go index 8a365cd239b..d4c47c743cd 100644 --- a/aws/data_source_aws_organizations_delegated_administrators.go +++ b/aws/data_source_aws_organizations_delegated_administrators.go @@ -81,7 +81,7 @@ func dataSourceAwsOrganizationsDelegatedAdministratorsRead(ctx context.Context, return !lastPage } - delegators = page.DelegatedAdministrators + delegators = append(delegators, page.DelegatedAdministrators...) return !lastPage }) diff --git a/aws/data_source_aws_organizations_delegated_administrators_test.go b/aws/data_source_aws_organizations_delegated_administrators_test.go index 6efb09f1aff..63a414baa0b 100644 --- a/aws/data_source_aws_organizations_delegated_administrators_test.go +++ b/aws/data_source_aws_organizations_delegated_administrators_test.go @@ -36,6 +36,34 @@ func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_basic(t *testing.T }) } +func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_multiple(t *testing.T) { + var providers []*schema.Provider + dataSourceName := "data.aws_organizations_delegated_administrators.test" + servicePrincipal := "config-multiaccountsetup.amazonaws.com" + servicePrincipal2 := "config.amazonaws.com" + dataSourceIdentity := "data.aws_caller_identity.delegated" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), + ProviderFactories: testAccProviderFactoriesAlternate(&providers), + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsOrganizationsDelegatedAdministratorsMultipleConfig(servicePrincipal, servicePrincipal2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "delegated_administrators.#", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "delegated_administrators.0.id", dataSourceIdentity, "account_id"), + testAccCheckResourceAttrRfc3339(dataSourceName, "delegated_administrators.0.delegation_enabled_date"), + testAccCheckResourceAttrRfc3339(dataSourceName, "delegated_administrators.0.joined_timestamp"), + ), + }, + }, + }) +} + func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_servicePrincipal(t *testing.T) { var providers []*schema.Provider dataSourceName := "data.aws_organizations_delegated_administrators.test" @@ -67,7 +95,7 @@ func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_empty(t *testing.T dataSourceName := "data.aws_organizations_delegated_administrators.test" servicePrincipal := "config-multiaccountsetup.amazonaws.com" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), ProviderFactories: testAccProviderFactories, @@ -83,7 +111,7 @@ func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_empty(t *testing.T } func testAccDataSourceAwsOrganizationsDelegatedAdministratorsEmptyConfig(servicePrincipal string) string { - return fmt.Sprintf(` + return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` data "aws_organizations_delegated_administrators" "test" { service_principal = %[1]q } @@ -105,6 +133,26 @@ data "aws_organizations_delegated_administrators" "test" {} `, servicePrincipal) } +func testAccDataSourceAwsOrganizationsDelegatedAdministratorsMultipleConfig(servicePrincipal, servicePrincipal2 string) string { + return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` +data "aws_caller_identity" "delegated" { + provider = "awsalternate" +} + +resource "aws_organizations_delegated_administrator" "delegated" { + account_id = data.aws_caller_identity.delegated.account_id + service_principal = %[1]q +} + +resource "aws_organizations_delegated_administrator" "other_delegated" { + account_id = data.aws_caller_identity.delegated.account_id + service_principal = %[2]q +} + +data "aws_organizations_delegated_administrators" "test" {} +`, servicePrincipal, servicePrincipal2) +} + func testAccDataSourceAwsOrganizationsDelegatedAdministratorsServicePrincipalConfig(servicePrincipal string) string { return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` data "aws_caller_identity" "delegated" { diff --git a/aws/data_source_aws_organizations_delegated_services.go b/aws/data_source_aws_organizations_delegated_services.go index b8482a378ce..c5b67353722 100644 --- a/aws/data_source_aws_organizations_delegated_services.go +++ b/aws/data_source_aws_organizations_delegated_services.go @@ -53,7 +53,7 @@ func dataSourceAwsOrganizationsDelegatedServicesRead(ctx context.Context, d *sch return !lastPage } - delegators = page.DelegatedServices + delegators = append(delegators, page.DelegatedServices...) return !lastPage }) diff --git a/aws/data_source_aws_organizations_delegated_services_test.go b/aws/data_source_aws_organizations_delegated_services_test.go index d1b0100f8fc..0e320092d84 100644 --- a/aws/data_source_aws_organizations_delegated_services_test.go +++ b/aws/data_source_aws_organizations_delegated_services_test.go @@ -13,6 +13,7 @@ func TestAccDataSourceAwsOrganizationsDelegatedServices_basic(t *testing.T) { var providers []*schema.Provider dataSourceName := "data.aws_organizations_delegated_services.test" dataSourceIdentity := "data.aws_caller_identity.delegated" + servicePrincipal := "config-multiaccountsetup.amazonaws.com" resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -23,7 +24,33 @@ func TestAccDataSourceAwsOrganizationsDelegatedServices_basic(t *testing.T) { ProviderFactories: testAccProviderFactoriesAlternate(&providers), Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsOrganizationsDelegatedServicesConfig(), + Config: testAccDataSourceAwsOrganizationsDelegatedServicesConfig(servicePrincipal), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "delegated_services.#", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "account_id", dataSourceIdentity, "account_id"), + testAccCheckResourceAttrRfc3339(dataSourceName, "delegated_services.0.delegation_enabled_date"), + resource.TestCheckResourceAttr(dataSourceName, "delegated_services.0.service_principal", servicePrincipal), + ), + }, + }, + }) +} + +func TestAccDataSourceAwsOrganizationsDelegatedServices_empty(t *testing.T) { + var providers []*schema.Provider + dataSourceName := "data.aws_organizations_delegated_services.test" + dataSourceIdentity := "data.aws_caller_identity.delegated" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ErrorCheck: testAccErrorCheck(t, organizations.EndpointsID), + ProviderFactories: testAccProviderFactoriesAlternate(&providers), + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsOrganizationsDelegatedServicesEmptyConfig(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(dataSourceName, "delegated_services.#", "0"), resource.TestCheckResourceAttrPair(dataSourceName, "account_id", dataSourceIdentity, "account_id"), @@ -33,11 +60,12 @@ func TestAccDataSourceAwsOrganizationsDelegatedServices_basic(t *testing.T) { }) } -func TestAccDataSourceAwsOrganizationsDelegatedServices_administrator(t *testing.T) { +func TestAccDataSourceAwsOrganizationsDelegatedServices_multiple(t *testing.T) { var providers []*schema.Provider dataSourceName := "data.aws_organizations_delegated_services.test" dataSourceIdentity := "data.aws_caller_identity.delegated" servicePrincipal := "config-multiaccountsetup.amazonaws.com" + servicePrincipal2 := "config.amazonaws.com" resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -48,19 +76,21 @@ func TestAccDataSourceAwsOrganizationsDelegatedServices_administrator(t *testing ProviderFactories: testAccProviderFactoriesAlternate(&providers), Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsOrganizationsDelegatedServicesAdministratorConfig(servicePrincipal), + Config: testAccDataSourceAwsOrganizationsDelegatedServicesMultipleConfig(servicePrincipal, servicePrincipal2), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(dataSourceName, "delegated_services.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "delegated_services.#", "2"), resource.TestCheckResourceAttrPair(dataSourceName, "account_id", dataSourceIdentity, "account_id"), testAccCheckResourceAttrRfc3339(dataSourceName, "delegated_services.0.delegation_enabled_date"), resource.TestCheckResourceAttr(dataSourceName, "delegated_services.0.service_principal", servicePrincipal), + testAccCheckResourceAttrRfc3339(dataSourceName, "delegated_services.1.delegation_enabled_date"), + resource.TestCheckResourceAttr(dataSourceName, "delegated_services.1.service_principal", servicePrincipal2), ), }, }, }) } -func testAccDataSourceAwsOrganizationsDelegatedServicesConfig() string { +func testAccDataSourceAwsOrganizationsDelegatedServicesEmptyConfig() string { return testAccAlternateAccountProviderConfig() + ` data "aws_caller_identity" "delegated" { provider = "awsalternate" @@ -72,7 +102,7 @@ data "aws_organizations_delegated_services" "test" { ` } -func testAccDataSourceAwsOrganizationsDelegatedServicesAdministratorConfig(servicePrincipal string) string { +func testAccDataSourceAwsOrganizationsDelegatedServicesConfig(servicePrincipal string) string { return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` data "aws_caller_identity" "delegated" { provider = "awsalternate" @@ -88,3 +118,25 @@ data "aws_organizations_delegated_services" "test" { } `, servicePrincipal) } + +func testAccDataSourceAwsOrganizationsDelegatedServicesMultipleConfig(servicePrincipal, servicePrincipal2 string) string { + return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` +data "aws_caller_identity" "delegated" { + provider = "awsalternate" +} + +resource "aws_organizations_delegated_administrator" "delegated" { + account_id = data.aws_caller_identity.delegated.account_id + service_principal = %[1]q +} + +resource "aws_organizations_delegated_administrator" "other_delegated" { + account_id = data.aws_caller_identity.delegated.account_id + service_principal = %[2]q +} + +data "aws_organizations_delegated_services" "test" { + account_id = aws_organizations_delegated_administrator.other_delegated.account_id +} +`, servicePrincipal, servicePrincipal2) +}