Skip to content

Commit 8cfb084

Browse files
authored
Merge pull request #44501 from hashicorp/td-iam-paginate-list
IAM: Use paginated List APIs
2 parents a200ba9 + 084d120 commit 8cfb084

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1101
-959
lines changed

internal/sdkv2/state.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,8 @@ func ToLowerSchemaStateFunc(v any) string {
2424
func ToUpperSchemaStateFunc(v any) string {
2525
return strings.ToUpper(v.(string))
2626
}
27+
28+
// TrimSpaceSchemaStateFunc removes all leading and trailing white space from a string value before storing it in state.
29+
func TrimSpaceSchemaStateFunc(v any) string {
30+
return strings.TrimSpace(v.(string))
31+
}

internal/sdkv2/state_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,16 @@ func TestToUpperSchemaStateFunc(t *testing.T) {
4747
t.Errorf("unexpected diff (+want, -got): %s", diff)
4848
}
4949
}
50+
51+
func TestTrimSpaceSchemaStateFunc(t *testing.T) {
52+
t.Parallel()
53+
54+
var input any = " in-state "
55+
want := "in-state"
56+
57+
got := TrimSpaceSchemaStateFunc(input)
58+
59+
if diff := cmp.Diff(got, want); diff != "" {
60+
t.Errorf("unexpected diff (+want, -got): %s", diff)
61+
}
62+
}

internal/service/iam/access_key.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"crypto/sha256"
1010
"fmt"
1111
"log"
12-
"reflect"
1312
"time"
1413

1514
"github.com/aws/aws-sdk-go-v2/aws"
@@ -24,7 +23,7 @@ import (
2423
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
2524
tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices"
2625
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
27-
itypes "github.com/hashicorp/terraform-provider-aws/internal/types"
26+
inttypes "github.com/hashicorp/terraform-provider-aws/internal/types"
2827
"github.com/hashicorp/terraform-provider-aws/names"
2928
)
3029

@@ -249,10 +248,11 @@ func resourceAccessKeyDelete(ctx context.Context, d *schema.ResourceData, meta a
249248
conn := meta.(*conns.AWSClient).IAMClient(ctx)
250249

251250
log.Printf("[DEBUG] Deleting IAM Access Key: %s", d.Id())
252-
_, err := conn.DeleteAccessKey(ctx, &iam.DeleteAccessKeyInput{
251+
input := iam.DeleteAccessKeyInput{
253252
AccessKeyId: aws.String(d.Id()),
254253
UserName: aws.String(d.Get("user").(string)),
255-
})
254+
}
255+
_, err := conn.DeleteAccessKey(ctx, &input)
256256

257257
if errs.IsA[*awstypes.NoSuchEntityException](err) {
258258
return diags
@@ -281,7 +281,7 @@ func findAccessKeyByTwoPartKey(ctx context.Context, conn *iam.Client, username,
281281
UserName: aws.String(username),
282282
}
283283

284-
return findAccessKey(ctx, conn, input, func(v awstypes.AccessKeyMetadata) bool {
284+
return findAccessKey(ctx, conn, input, func(v *awstypes.AccessKeyMetadata) bool {
285285
return aws.ToString(v.AccessKeyId) == id
286286
})
287287
}
@@ -291,10 +291,10 @@ func findAccessKeysByUser(ctx context.Context, conn *iam.Client, username string
291291
UserName: aws.String(username),
292292
}
293293

294-
return findAccessKeys(ctx, conn, input, tfslices.PredicateTrue[awstypes.AccessKeyMetadata]())
294+
return findAccessKeys(ctx, conn, input, tfslices.PredicateTrue[*awstypes.AccessKeyMetadata]())
295295
}
296296

297-
func findAccessKey(ctx context.Context, conn *iam.Client, input *iam.ListAccessKeysInput, filter tfslices.Predicate[awstypes.AccessKeyMetadata]) (*awstypes.AccessKeyMetadata, error) {
297+
func findAccessKey(ctx context.Context, conn *iam.Client, input *iam.ListAccessKeysInput, filter tfslices.Predicate[*awstypes.AccessKeyMetadata]) (*awstypes.AccessKeyMetadata, error) {
298298
output, err := findAccessKeys(ctx, conn, input, filter)
299299

300300
if err != nil {
@@ -304,7 +304,7 @@ func findAccessKey(ctx context.Context, conn *iam.Client, input *iam.ListAccessK
304304
return tfresource.AssertSingleValueResult(output)
305305
}
306306

307-
func findAccessKeys(ctx context.Context, conn *iam.Client, input *iam.ListAccessKeysInput, filter tfslices.Predicate[awstypes.AccessKeyMetadata]) ([]awstypes.AccessKeyMetadata, error) {
307+
func findAccessKeys(ctx context.Context, conn *iam.Client, input *iam.ListAccessKeysInput, filter tfslices.Predicate[*awstypes.AccessKeyMetadata]) ([]awstypes.AccessKeyMetadata, error) {
308308
var output []awstypes.AccessKeyMetadata
309309

310310
pages := iam.NewListAccessKeysPaginator(conn, input)
@@ -323,7 +323,7 @@ func findAccessKeys(ctx context.Context, conn *iam.Client, input *iam.ListAccess
323323
}
324324

325325
for _, v := range page.AccessKeyMetadata {
326-
if !reflect.ValueOf(v).IsZero() && filter(v) {
326+
if p := &v; !inttypes.IsZero(p) && filter(p) {
327327
output = append(output, v)
328328
}
329329
}
@@ -371,5 +371,5 @@ func sesSMTPPasswordFromSecretKeySigV4(key *string, region string) (string, erro
371371
versionedSig := make([]byte, 0, len(rawSig)+1)
372372
versionedSig = append(versionedSig, version)
373373
versionedSig = append(versionedSig, rawSig...)
374-
return itypes.Base64Encode(versionedSig), nil
374+
return inttypes.Base64Encode(versionedSig), nil
375375
}

internal/service/iam/account_alias.go

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ package iam
55

66
import (
77
"context"
8+
"log"
89

910
"github.com/aws/aws-sdk-go-v2/aws"
1011
"github.com/aws/aws-sdk-go-v2/service/iam"
12+
awstypes "github.com/aws/aws-sdk-go-v2/service/iam/types"
1113
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1214
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1315
"github.com/hashicorp/terraform-provider-aws/internal/conns"
16+
"github.com/hashicorp/terraform-provider-aws/internal/errs"
1417
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
18+
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
1519
)
1620

1721
// @SDKResource("aws_iam_account_alias", name="Account Alias")
@@ -41,15 +45,14 @@ func resourceAccountAliasCreate(ctx context.Context, d *schema.ResourceData, met
4145
conn := meta.(*conns.AWSClient).IAMClient(ctx)
4246

4347
accountAlias := d.Get("account_alias").(string)
44-
45-
params := &iam.CreateAccountAliasInput{
48+
input := iam.CreateAccountAliasInput{
4649
AccountAlias: aws.String(accountAlias),
4750
}
4851

49-
_, err := conn.CreateAccountAlias(ctx, params)
52+
_, err := conn.CreateAccountAlias(ctx, &input)
5053

5154
if err != nil {
52-
return sdkdiag.AppendErrorf(diags, "creating account alias with name '%s': %s", accountAlias, err)
55+
return sdkdiag.AppendErrorf(diags, "creating IAM Account Alias (%s): %s", accountAlias, err)
5356
}
5457

5558
d.SetId(accountAlias)
@@ -61,23 +64,20 @@ func resourceAccountAliasRead(ctx context.Context, d *schema.ResourceData, meta
6164
var diags diag.Diagnostics
6265
conn := meta.(*conns.AWSClient).IAMClient(ctx)
6366

64-
params := &iam.ListAccountAliasesInput{}
65-
66-
resp, err := conn.ListAccountAliases(ctx, params)
67+
var input iam.ListAccountAliasesInput
68+
output, err := findAccountAlias(ctx, conn, &input)
6769

68-
if err != nil {
69-
return sdkdiag.AppendErrorf(diags, "listing account aliases: %s", err)
70-
}
71-
72-
if !d.IsNewResource() && (resp == nil || len(resp.AccountAliases) == 0) {
70+
if !d.IsNewResource() && tfresource.NotFound(err) {
71+
log.Printf("[WARN] IAM Account Alias (%s) not found, removing from state", d.Id())
7372
d.SetId("")
7473
return diags
7574
}
7675

77-
accountAlias := resp.AccountAliases[0]
76+
if err != nil {
77+
return sdkdiag.AppendErrorf(diags, "reading IAM Account Alias (%s): %s", d.Id(), err)
78+
}
7879

79-
d.SetId(accountAlias)
80-
d.Set("account_alias", accountAlias)
80+
d.Set("account_alias", output)
8181

8282
return diags
8383
}
@@ -86,17 +86,47 @@ func resourceAccountAliasDelete(ctx context.Context, d *schema.ResourceData, met
8686
var diags diag.Diagnostics
8787
conn := meta.(*conns.AWSClient).IAMClient(ctx)
8888

89-
accountAlias := d.Get("account_alias").(string)
90-
91-
params := &iam.DeleteAccountAliasInput{
92-
AccountAlias: aws.String(accountAlias),
89+
log.Printf("[DEBUG] Deleting IAM Account Alias: %s", d.Id())
90+
input := iam.DeleteAccountAliasInput{
91+
AccountAlias: aws.String(d.Id()),
9392
}
9493

95-
_, err := conn.DeleteAccountAlias(ctx, params)
94+
_, err := conn.DeleteAccountAlias(ctx, &input)
95+
96+
if errs.IsA[*awstypes.NoSuchEntityException](err) {
97+
return diags
98+
}
9699

97100
if err != nil {
98-
return sdkdiag.AppendErrorf(diags, "deleting account alias with name '%s': %s", accountAlias, err)
101+
return sdkdiag.AppendErrorf(diags, "deleting IAM Account Alias (%s): %s", d.Id(), err)
99102
}
100103

101104
return diags
102105
}
106+
107+
func findAccountAlias(ctx context.Context, conn *iam.Client, input *iam.ListAccountAliasesInput) (*string, error) {
108+
output, err := findAccountAliases(ctx, conn, input)
109+
110+
if err != nil {
111+
return nil, err
112+
}
113+
114+
return tfresource.AssertSingleValueResult(output)
115+
}
116+
117+
func findAccountAliases(ctx context.Context, conn *iam.Client, input *iam.ListAccountAliasesInput) ([]string, error) {
118+
var output []string
119+
120+
pages := iam.NewListAccountAliasesPaginator(conn, input)
121+
for pages.HasMorePages() {
122+
page, err := pages.NextPage(ctx)
123+
124+
if err != nil {
125+
return nil, err
126+
}
127+
128+
output = append(output, page.AccountAliases...)
129+
}
130+
131+
return output, nil
132+
}

internal/service/iam/account_alias_data_source.go

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ package iam
55

66
import (
77
"context"
8-
"log"
98

9+
"github.com/aws/aws-sdk-go-v2/aws"
1010
"github.com/aws/aws-sdk-go-v2/service/iam"
1111
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1212
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -32,22 +32,15 @@ func dataSourceAccountAliasRead(ctx context.Context, d *schema.ResourceData, met
3232
var diags diag.Diagnostics
3333
conn := meta.(*conns.AWSClient).IAMClient(ctx)
3434

35-
log.Printf("[DEBUG] Reading IAM Account Aliases.")
35+
var input iam.ListAccountAliasesInput
36+
output, err := findAccountAlias(ctx, conn, &input)
3637

37-
req := &iam.ListAccountAliasesInput{}
38-
resp, err := conn.ListAccountAliases(ctx, req)
3938
if err != nil {
4039
return sdkdiag.AppendErrorf(diags, "reading IAM Account Alias: %s", err)
4140
}
4241

43-
// 'AccountAliases': [] if there is no alias.
44-
if resp == nil || len(resp.AccountAliases) == 0 {
45-
return sdkdiag.AppendErrorf(diags, "reading IAM Account Alias: empty result")
46-
}
47-
48-
alias := resp.AccountAliases[0]
49-
d.SetId(alias)
50-
d.Set("account_alias", alias)
42+
d.SetId(aws.ToString(output))
43+
d.Set("account_alias", output)
5144

5245
return diags
5346
}

internal/service/iam/account_alias_test.go

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import (
1616
"github.com/hashicorp/terraform-plugin-testing/terraform"
1717
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
1818
"github.com/hashicorp/terraform-provider-aws/internal/conns"
19+
tfiam "github.com/hashicorp/terraform-provider-aws/internal/service/iam"
20+
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
1921
"github.com/hashicorp/terraform-provider-aws/names"
2022
)
2123

@@ -27,7 +29,8 @@ func TestAccIAMAccountAlias_serial(t *testing.T) {
2729
acctest.CtBasic: testAccAccountAliasDataSource_basic,
2830
},
2931
"Resource": {
30-
acctest.CtBasic: testAccAccountAlias_basic,
32+
acctest.CtBasic: testAccAccountAlias_basic,
33+
acctest.CtDisappears: testAccAccountAlias_disappears,
3134
},
3235
}
3336

@@ -37,7 +40,6 @@ func TestAccIAMAccountAlias_serial(t *testing.T) {
3740
func testAccAccountAlias_basic(t *testing.T) {
3841
ctx := acctest.Context(t)
3942
resourceName := "aws_iam_account_alias.test"
40-
4143
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
4244

4345
resource.Test(t, resource.TestCase{
@@ -64,6 +66,32 @@ func testAccAccountAlias_basic(t *testing.T) {
6466
})
6567
}
6668

69+
func testAccAccountAlias_disappears(t *testing.T) {
70+
ctx := acctest.Context(t)
71+
resourceName := "aws_iam_account_alias.test"
72+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
73+
74+
resource.Test(t, resource.TestCase{
75+
PreCheck: func() {
76+
acctest.PreCheck(ctx, t)
77+
testAccPreCheckAccountAlias(ctx, t)
78+
},
79+
ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID),
80+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
81+
CheckDestroy: testAccCheckAccountAliasDestroy(ctx),
82+
Steps: []resource.TestStep{
83+
{
84+
Config: testAccAccountAliasConfig_basic(rName),
85+
Check: resource.ComposeAggregateTestCheckFunc(
86+
testAccCheckAccountAliasExists(ctx, resourceName),
87+
acctest.CheckResourceDisappears(ctx, acctest.Provider, tfiam.ResourceAccountAlias(), resourceName),
88+
),
89+
ExpectNonEmptyPlan: true,
90+
},
91+
},
92+
})
93+
}
94+
6795
func testAccCheckAccountAliasDestroy(ctx context.Context) resource.TestCheckFunc {
6896
return func(s *terraform.State) error {
6997
conn := acctest.Provider.Meta().(*conns.AWSClient).IAMClient(ctx)
@@ -73,21 +101,18 @@ func testAccCheckAccountAliasDestroy(ctx context.Context) resource.TestCheckFunc
73101
continue
74102
}
75103

76-
params := &iam.ListAccountAliasesInput{}
77-
78-
resp, err := conn.ListAccountAliases(ctx, params)
104+
var input iam.ListAccountAliasesInput
105+
_, err := tfiam.FindAccountAlias(ctx, conn, &input)
79106

80-
if err != nil {
81-
return fmt.Errorf("error reading IAM Account Alias (%s): %w", rs.Primary.ID, err)
107+
if tfresource.NotFound(err) {
108+
continue
82109
}
83110

84-
if resp == nil {
85-
return fmt.Errorf("error reading IAM Account Alias (%s): empty response", rs.Primary.ID)
111+
if err != nil {
112+
return err
86113
}
87114

88-
if len(resp.AccountAliases) > 0 {
89-
return fmt.Errorf("Bad: Account alias still exists: %q", rs.Primary.ID)
90-
}
115+
return fmt.Errorf("IAM Server Certificate %s still exists", rs.Primary.ID)
91116
}
92117

93118
return nil
@@ -96,29 +121,17 @@ func testAccCheckAccountAliasDestroy(ctx context.Context) resource.TestCheckFunc
96121

97122
func testAccCheckAccountAliasExists(ctx context.Context, n string) resource.TestCheckFunc {
98123
return func(s *terraform.State) error {
99-
rs, ok := s.RootModule().Resources[n]
124+
_, ok := s.RootModule().Resources[n]
100125
if !ok {
101126
return fmt.Errorf("Not found: %s", n)
102127
}
103128

104129
conn := acctest.Provider.Meta().(*conns.AWSClient).IAMClient(ctx)
105-
params := &iam.ListAccountAliasesInput{}
106130

107-
resp, err := conn.ListAccountAliases(ctx, params)
131+
var input iam.ListAccountAliasesInput
132+
_, err := tfiam.FindAccountAlias(ctx, conn, &input)
108133

109-
if err != nil {
110-
return fmt.Errorf("error reading IAM Account Alias (%s): %w", rs.Primary.ID, err)
111-
}
112-
113-
if resp == nil {
114-
return fmt.Errorf("error reading IAM Account Alias (%s): empty response", rs.Primary.ID)
115-
}
116-
117-
if len(resp.AccountAliases) == 0 {
118-
return fmt.Errorf("Bad: Account alias %q does not exist", rs.Primary.ID)
119-
}
120-
121-
return nil
134+
return err
122135
}
123136
}
124137

0 commit comments

Comments
 (0)