Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New resource for Delegated Administrators for Organizations and datasources for Delegated Administrators and Services #19389

Merged
merged 7 commits into from
May 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changelog/19389.txt
Original file line number Diff line number Diff line change
@@ -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
```
120 changes: 120 additions & 0 deletions aws/data_source_aws_organizations_delegated_administrators.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
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.TypeSet,
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))
}

var delegators []*organizations.DelegatedAdministrator

err := conn.ListDelegatedAdministratorsPagesWithContext(ctx, input, func(page *organizations.ListDelegatedAdministratorsOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

delegators = append(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(delegators)); err != nil {
return diag.FromErr(fmt.Errorf("error setting delegated_administrators: %w", err))
}

d.SetId(meta.(*AWSClient).accountid)

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
}
171 changes: 171 additions & 0 deletions aws/data_source_aws_organizations_delegated_administrators_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
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) {
gdavison marked this conversation as resolved.
Show resolved Hide resolved
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: 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"),
),
gdavison marked this conversation as resolved.
Show resolved Hide resolved
},
},
})
}

gdavison marked this conversation as resolved.
Show resolved Hide resolved
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"
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"),
),
gdavison marked this conversation as resolved.
Show resolved Hide resolved
},
},
})
}

func TestAccDataSourceAwsOrganizationsDelegatedAdministrators_empty(t *testing.T) {
dataSourceName := "data.aws_organizations_delegated_administrators.test"
servicePrincipal := "config-multiaccountsetup.amazonaws.com"

resource.Test(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 testAccAlternateAccountProviderConfig() + 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" {
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" {}
`, 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" {
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)
}
86 changes: 86 additions & 0 deletions aws/data_source_aws_organizations_delegated_services.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
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,
ValidateFunc: validateAwsAccountId,
},
"delegated_services": {
Type: schema.TypeSet,
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)),
}

var delegators []*organizations.DelegatedService
err := conn.ListDelegatedServicesForAccountPagesWithContext(ctx, input, func(page *organizations.ListDelegatedServicesForAccountOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

delegators = append(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(delegators)); err != nil {
return diag.FromErr(fmt.Errorf("error setting delegated_services: %w", err))
}

d.SetId(meta.(*AWSClient).accountid)

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
}
Loading