Skip to content

Commit c5a285c

Browse files
authored
Merge pull request #35310 from DanielRieske/f/add-configuration-argument-access-analyzer
Add `configuration` block to `aws_accessanalyzer_analyzer` resource
2 parents 3d67697 + 7adb2ff commit c5a285c

File tree

5 files changed

+151
-8
lines changed

5 files changed

+151
-8
lines changed

.changelog/35310.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
resource/aws_accessanalyzer_analyzer: Add `configuration` configuration block
3+
```

internal/service/accessanalyzer/accessanalyzer_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func TestAccAccessAnalyzer_serial(t *testing.T) {
1919
testCases := map[string]map[string]func(t *testing.T){
2020
"Analyzer": {
2121
"basic": testAccAnalyzer_basic,
22+
"configuration": testAccAnalyzer_configuration,
2223
"disappears": testAccAnalyzer_disappears,
2324
"tags": testAccAnalyzer_tags,
2425
"Type_Organization": testAccAnalyzer_Type_Organization,

internal/service/accessanalyzer/analyzer.go

+91-8
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,31 @@ func resourceAnalyzer() *schema.Resource {
6262
Type: schema.TypeString,
6363
Computed: true,
6464
},
65+
"configuration": {
66+
Type: schema.TypeList,
67+
Optional: true,
68+
ForceNew: true,
69+
MaxItems: 1,
70+
Elem: &schema.Resource{
71+
Schema: map[string]*schema.Schema{
72+
"unused_access": {
73+
Type: schema.TypeList,
74+
Optional: true,
75+
ForceNew: true,
76+
MaxItems: 1,
77+
Elem: &schema.Resource{
78+
Schema: map[string]*schema.Schema{
79+
"unused_access_age": {
80+
Type: schema.TypeInt,
81+
Optional: true,
82+
ForceNew: true,
83+
},
84+
},
85+
},
86+
},
87+
},
88+
},
89+
},
6590
names.AttrTags: tftags.TagsSchema(),
6691
names.AttrTagsAll: tftags.TagsSchemaComputed(),
6792
"type": {
@@ -89,18 +114,16 @@ func resourceAnalyzerCreate(ctx context.Context, d *schema.ResourceData, meta in
89114
Type: types.Type(d.Get("type").(string)),
90115
}
91116

117+
if v, ok := d.GetOk("configuration"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil {
118+
input.Configuration = expandAnalyzerConfiguration(v.([]interface{})[0].(map[string]interface{}))
119+
}
120+
92121
// Handle Organizations eventual consistency.
93-
_, err := tfresource.RetryWhen(ctx, organizationCreationTimeout,
122+
_, err := tfresource.RetryWhenIsAErrorMessageContains[*types.ValidationException](ctx, organizationCreationTimeout,
94123
func() (interface{}, error) {
95124
return conn.CreateAnalyzer(ctx, input)
96125
},
97-
func(err error) (bool, error) {
98-
if errs.IsAErrorMessageContains[*types.ValidationException](err, "You must create an organization") {
99-
return true, err
100-
}
101-
102-
return false, err
103-
},
126+
"You must create an organization",
104127
)
105128

106129
if err != nil {
@@ -130,6 +153,13 @@ func resourceAnalyzerRead(ctx context.Context, d *schema.ResourceData, meta inte
130153

131154
d.Set("analyzer_name", analyzer.Name)
132155
d.Set("arn", analyzer.Arn)
156+
if analyzer.Configuration != nil {
157+
if err := d.Set("configuration", []interface{}{flattenConfiguration(analyzer.Configuration)}); err != nil {
158+
return sdkdiag.AppendErrorf(diags, "setting configuration: %s", err)
159+
}
160+
} else {
161+
d.Set("configuration", nil)
162+
}
133163
d.Set("type", analyzer.Type)
134164

135165
setTagsOut(ctx, analyzer.Tags)
@@ -190,3 +220,56 @@ func findAnalyzerByName(ctx context.Context, conn *accessanalyzer.Client, name s
190220

191221
return output.Analyzer, nil
192222
}
223+
224+
func expandAnalyzerConfiguration(tfMap map[string]interface{}) types.AnalyzerConfiguration {
225+
if tfMap == nil {
226+
return nil
227+
}
228+
229+
apiObject := &types.AnalyzerConfigurationMemberUnusedAccess{}
230+
231+
if v, ok := tfMap["unused_access"].([]interface{}); ok && len(v) > 0 && v[0] != nil {
232+
apiObject.Value = expandUnusedAccess(v[0].(map[string]interface{}))
233+
}
234+
235+
return apiObject
236+
}
237+
238+
func expandUnusedAccess(tfMap map[string]interface{}) types.UnusedAccessConfiguration {
239+
apiObject := types.UnusedAccessConfiguration{}
240+
241+
if v, ok := tfMap["unused_access_age"].(int); ok && v != 0 {
242+
apiObject.UnusedAccessAge = aws.Int32(int32(v))
243+
}
244+
245+
return apiObject
246+
}
247+
248+
func flattenConfiguration(apiObject types.AnalyzerConfiguration) map[string]interface{} {
249+
if apiObject == nil {
250+
return nil
251+
}
252+
253+
tfMap := map[string]interface{}{}
254+
255+
switch v := apiObject.(type) {
256+
case *types.AnalyzerConfigurationMemberUnusedAccess:
257+
tfMap["unused_access"] = []interface{}{flattenUnusedAccessConfiguration(&v.Value)}
258+
}
259+
260+
return tfMap
261+
}
262+
263+
func flattenUnusedAccessConfiguration(apiObject *types.UnusedAccessConfiguration) map[string]interface{} {
264+
if apiObject == nil {
265+
return nil
266+
}
267+
268+
tfMap := map[string]interface{}{}
269+
270+
if v := apiObject.UnusedAccessAge; v != nil {
271+
tfMap["unused_access_age"] = aws.ToInt32(v)
272+
}
273+
274+
return tfMap
275+
}

internal/service/accessanalyzer/analyzer_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ func testAccAnalyzer_basic(t *testing.T) {
3838
testAccCheckAnalyzerExists(ctx, resourceName, &analyzer),
3939
resource.TestCheckResourceAttr(resourceName, "analyzer_name", rName),
4040
acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "access-analyzer", fmt.Sprintf("analyzer/%s", rName)),
41+
resource.TestCheckResourceAttr(resourceName, "configuration.#", "0"),
4142
resource.TestCheckResourceAttr(resourceName, "tags.%", "0"),
4243
resource.TestCheckResourceAttr(resourceName, "type", string(types.TypeAccount)),
4344
),
@@ -156,6 +157,37 @@ func testAccAnalyzer_Type_Organization(t *testing.T) {
156157
})
157158
}
158159

160+
func testAccAnalyzer_configuration(t *testing.T) {
161+
ctx := acctest.Context(t)
162+
var analyzer types.AnalyzerSummary
163+
164+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
165+
resourceName := "aws_accessanalyzer_analyzer.test"
166+
167+
resource.Test(t, resource.TestCase{
168+
PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) },
169+
ErrorCheck: acctest.ErrorCheck(t, names.AccessAnalyzerEndpointID),
170+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
171+
CheckDestroy: testAccCheckAnalyzerDestroy(ctx),
172+
Steps: []resource.TestStep{
173+
{
174+
Config: testAccAnalyzerConfig_configuration(rName),
175+
Check: resource.ComposeTestCheckFunc(
176+
testAccCheckAnalyzerExists(ctx, resourceName, &analyzer),
177+
resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"),
178+
resource.TestCheckResourceAttr(resourceName, "configuration.0.unused_access.#", "1"),
179+
resource.TestCheckResourceAttr(resourceName, "configuration.0.unused_access.0.unused_access_age", "180"),
180+
),
181+
},
182+
{
183+
ResourceName: resourceName,
184+
ImportState: true,
185+
ImportStateVerify: true,
186+
},
187+
},
188+
})
189+
}
190+
159191
func testAccCheckAnalyzerDestroy(ctx context.Context) resource.TestCheckFunc {
160192
return func(s *terraform.State) error {
161193
conn := acctest.Provider.Meta().(*conns.AWSClient).AccessAnalyzerClient(ctx)
@@ -256,3 +288,18 @@ resource "aws_accessanalyzer_analyzer" "test" {
256288
}
257289
`, rName)
258290
}
291+
292+
func testAccAnalyzerConfig_configuration(rName string) string {
293+
return fmt.Sprintf(`
294+
resource "aws_accessanalyzer_analyzer" "test" {
295+
analyzer_name = %[1]q
296+
type = "ACCOUNT_UNUSED_ACCESS"
297+
298+
configuration {
299+
unused_access {
300+
unused_access_age = 180
301+
}
302+
}
303+
}
304+
`, rName)
305+
}

website/docs/r/accessanalyzer_analyzer.html.markdown

+9
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,18 @@ The following arguments are required:
4343

4444
The following arguments are optional:
4545

46+
* `configuration` - (Optional) A block that specifies the configuration of the analyzer. [Documented below](#configuration-argument-reference)
4647
* `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level.
4748
* `type` - (Optional) Type of Analyzer. Valid values are `ACCOUNT`, `ORGANIZATION`, `ACCOUNT_UNUSED_ACCESS `, `ORGANIZATION_UNUSED_ACCESS`. Defaults to `ACCOUNT`.
4849

50+
### `configuration` Argument Reference
51+
52+
* `unused_access` - A block that specifies the configuration of an unused access analyzer for an AWS organization or account. [Documented below](#unused_access-argument-reference)
53+
54+
### `unused_access` Argument Reference
55+
56+
* `unused_access_age` - The specified access age in days for which to generate findings for unused access.
57+
4958
## Attribute Reference
5059

5160
This resource exports the following attributes in addition to the arguments above:

0 commit comments

Comments
 (0)