Skip to content

Commit

Permalink
Merge pull request #35739 from AliAllomani/f-aws_account_region
Browse files Browse the repository at this point in the history
New resource: aws_account_region
  • Loading branch information
ewbankkit authored Mar 6, 2024
2 parents 530ad30 + c517680 commit cfc45bb
Show file tree
Hide file tree
Showing 8 changed files with 430 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .changelog/35739.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_account_region
```
2 changes: 1 addition & 1 deletion internal/acctest/acctest.go
Original file line number Diff line number Diff line change
Expand Up @@ -1084,7 +1084,7 @@ func PreCheckOrganizationMemberAccount(ctx context.Context, t *testing.T) {
func PreCheckRegionOptIn(ctx context.Context, t *testing.T, region string) {
t.Helper()

output, err := tfaccount.FindRegionOptInStatus(ctx, Provider.Meta().(*conns.AWSClient).AccountClient(ctx), "", region)
output, err := tfaccount.FindRegionOptStatus(ctx, Provider.Meta().(*conns.AWSClient).AccountClient(ctx), "", region)

if err != nil {
t.Fatalf("reading Region (%s) opt-in status: %s", region, err)
Expand Down
4 changes: 4 additions & 0 deletions internal/service/account/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ func TestAccAccount_serial(t *testing.T) {
"PrimaryContact": {
"basic": testAccPrimaryContact_basic,
},
"Region": {
"basic": testAccRegion_basic,
"AccountID": testAccRegion_accountID,
},
}

acctest.RunSerialTests2Levels(t, testCases, 0)
Expand Down
9 changes: 9 additions & 0 deletions internal/service/account/exports.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package account

// Exports for use in other modules.
var (
FindRegionOptStatus = findRegionOptStatus
)
206 changes: 205 additions & 1 deletion internal/service/account/region.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,163 @@ package account

import (
"context"
"strings"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/account"
"github.com/aws/aws-sdk-go-v2/service/account/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/enum"
"github.com/hashicorp/terraform-provider-aws/internal/errs"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
"github.com/hashicorp/terraform-provider-aws/internal/flex"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

func FindRegionOptInStatus(ctx context.Context, conn *account.Client, accountID, region string) (*account.GetRegionOptStatusOutput, error) {
// @SDKResource("aws_account_region", name="Region")
func resourceRegion() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceRegionUpdate,
ReadWithoutTimeout: resourceRegionRead,
UpdateWithoutTimeout: resourceRegionUpdate,
DeleteWithoutTimeout: schema.NoopContext,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: verify.ValidAccountID,
},
"enabled": {
Type: schema.TypeBool,
Required: true,
},
"opt_status": {
Type: schema.TypeString,
Computed: true,
},
"region_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(60 * time.Minute),
Update: schema.DefaultTimeout(60 * time.Minute),
},
}
}

const (
regionResourceIDPartCount = 2
)

func resourceRegionUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).AccountClient(ctx)

var id string
region := d.Get("region_name").(string)
accountID := ""
if v, ok := d.GetOk("account_id"); ok {
accountID = v.(string)
id = errs.Must(flex.FlattenResourceId([]string{accountID, region}, regionResourceIDPartCount, false))
} else {
id = region
}

timeout := d.Timeout(schema.TimeoutCreate)
if !d.IsNewResource() {
timeout = d.Timeout(schema.TimeoutUpdate)
}

if v := d.Get("enabled").(bool); v {
input := &account.EnableRegionInput{
RegionName: aws.String(region),
}
if accountID != "" {
input.AccountId = aws.String(accountID)
}

_, err := conn.EnableRegion(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "enabling Account Region (%s): %s", id, err)
}

if _, err := waitRegionEnabled(ctx, conn, accountID, region, timeout); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for Account Region (%s) enable: %s", d.Id(), err)
}
} else {
input := &account.DisableRegionInput{
RegionName: aws.String(region),
}
if accountID != "" {
input.AccountId = aws.String(accountID)
}

_, err := conn.DisableRegion(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "enabling Account Region (%s): %s", id, err)
}

if _, err := waitRegionDisabled(ctx, conn, accountID, region, timeout); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for Account Region (%s) disable: %s", d.Id(), err)
}
}

if d.IsNewResource() {
d.SetId(id)
}

return append(diags, resourceRegionRead(ctx, d, meta)...)
}

func resourceRegionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).AccountClient(ctx)

var accountID, region string
if strings.Contains(d.Id(), flex.ResourceIdSeparator) {
parts, err := flex.ExpandResourceId(d.Id(), regionResourceIDPartCount, false)
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}

accountID = parts[0]
region = parts[1]
} else {
region = d.Id()
}

output, err := findRegionOptStatus(ctx, conn, accountID, region)

if err != nil {
return sdkdiag.AppendErrorf(diags, "reading Account Region (%s): %s", d.Id(), err)
}

d.Set("account_id", accountID)
d.Set("enabled", output.RegionOptStatus == types.RegionOptStatusEnabled || output.RegionOptStatus == types.RegionOptStatusEnabledByDefault)
d.Set("opt_status", string(output.RegionOptStatus))
d.Set("region_name", output.RegionName)

return diags
}

func findRegionOptStatus(ctx context.Context, conn *account.Client, accountID, region string) (*account.GetRegionOptStatusOutput, error) {
input := &account.GetRegionOptStatusInput{
RegionName: aws.String(region),
}
Expand All @@ -31,3 +181,57 @@ func FindRegionOptInStatus(ctx context.Context, conn *account.Client, accountID,

return output, nil
}

func statusRegionOptStatus(ctx context.Context, conn *account.Client, accountID, region string) retry.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := findRegionOptStatus(ctx, conn, accountID, region)

if tfresource.NotFound(err) {
return nil, "", nil
}

if err != nil {
return nil, "", err
}

return output, string(output.RegionOptStatus), nil
}
}

func waitRegionEnabled(ctx context.Context, conn *account.Client, accountID, region string, timeout time.Duration) (*account.GetRegionOptStatusOutput, error) {
stateConf := &retry.StateChangeConf{
Pending: enum.Slice(types.RegionOptStatusEnabling),
Target: enum.Slice(types.RegionOptStatusEnabled),
Refresh: statusRegionOptStatus(ctx, conn, accountID, region),
Timeout: timeout,
Delay: 1 * time.Minute,
PollInterval: 30 * time.Second,
}

outputRaw, err := stateConf.WaitForStateContext(ctx)

if output, ok := outputRaw.(*account.GetRegionOptStatusOutput); ok {
return output, err
}

return nil, err
}

func waitRegionDisabled(ctx context.Context, conn *account.Client, accountID, region string, timeout time.Duration) (*account.GetRegionOptStatusOutput, error) {
stateConf := &retry.StateChangeConf{
Pending: enum.Slice(types.RegionOptStatusDisabling),
Target: enum.Slice(types.RegionOptStatusDisabled),
Refresh: statusRegionOptStatus(ctx, conn, accountID, region),
Timeout: timeout,
Delay: 1 * time.Minute,
PollInterval: 30 * time.Second,
}

outputRaw, err := stateConf.WaitForStateContext(ctx)

if output, ok := outputRaw.(*account.GetRegionOptStatusOutput); ok {
return output, err
}

return nil, err
}
Loading

0 comments on commit cfc45bb

Please sign in to comment.