Skip to content

Commit a97f654

Browse files
authored
Merge pull request #28989 from hashicorp/f-aws_auditmanager_framework_data_source
New Data Source: `aws_auditmanager_framework`
2 parents c56e835 + 24e0294 commit a97f654

File tree

3 files changed

+305
-0
lines changed

3 files changed

+305
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
package auditmanager
2+
3+
import (
4+
"context"
5+
6+
"github.com/aws/aws-sdk-go-v2/aws"
7+
"github.com/aws/aws-sdk-go-v2/service/auditmanager"
8+
awstypes "github.com/aws/aws-sdk-go-v2/service/auditmanager/types"
9+
"github.com/hashicorp/terraform-plugin-framework/datasource"
10+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
11+
"github.com/hashicorp/terraform-plugin-framework/diag"
12+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
13+
"github.com/hashicorp/terraform-plugin-framework/types"
14+
sdkv2resource "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
15+
"github.com/hashicorp/terraform-provider-aws/internal/conns"
16+
"github.com/hashicorp/terraform-provider-aws/internal/enum"
17+
"github.com/hashicorp/terraform-provider-aws/internal/flex"
18+
"github.com/hashicorp/terraform-provider-aws/internal/framework"
19+
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
20+
)
21+
22+
func init() {
23+
_sp.registerFrameworkDataSourceFactory(newDataSourceFramework)
24+
}
25+
26+
func newDataSourceFramework(context.Context) (datasource.DataSourceWithConfigure, error) {
27+
return &dataSourceFramework{}, nil
28+
}
29+
30+
type dataSourceFramework struct {
31+
framework.DataSourceWithConfigure
32+
}
33+
34+
func (d *dataSourceFramework) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { // nosemgrep:ci.meta-in-func-name
35+
response.TypeName = "aws_auditmanager_framework"
36+
}
37+
38+
func (d *dataSourceFramework) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
39+
resp.Schema = schema.Schema{
40+
Attributes: map[string]schema.Attribute{
41+
"arn": framework.ARNAttributeComputedOnly(),
42+
"compliance_type": schema.StringAttribute{
43+
Computed: true,
44+
},
45+
"description": schema.StringAttribute{
46+
Computed: true,
47+
},
48+
"framework_type": schema.StringAttribute{
49+
Required: true,
50+
Validators: []validator.String{
51+
enum.FrameworkValidate[awstypes.FrameworkType](),
52+
},
53+
},
54+
"id": framework.IDAttribute(),
55+
"name": schema.StringAttribute{
56+
Required: true,
57+
},
58+
"tags": tftags.TagsAttributeComputedOnly(),
59+
},
60+
Blocks: map[string]schema.Block{
61+
"control_sets": schema.SetNestedBlock{
62+
NestedObject: schema.NestedBlockObject{
63+
Attributes: map[string]schema.Attribute{
64+
"id": framework.IDAttribute(),
65+
"name": schema.StringAttribute{
66+
Computed: true,
67+
},
68+
},
69+
Blocks: map[string]schema.Block{
70+
"controls": schema.SetNestedBlock{
71+
NestedObject: schema.NestedBlockObject{
72+
Attributes: map[string]schema.Attribute{
73+
"id": schema.StringAttribute{
74+
Computed: true,
75+
},
76+
},
77+
},
78+
},
79+
},
80+
},
81+
},
82+
},
83+
}
84+
}
85+
86+
func (d *dataSourceFramework) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
87+
conn := d.Meta().AuditManagerClient()
88+
89+
var data dataSourceFrameworkData
90+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
91+
if resp.Diagnostics.HasError() {
92+
return
93+
}
94+
95+
frameworkMetadata, err := FindFrameworkByName(ctx, conn, data.Name.ValueString(), data.FrameworkType.ValueString())
96+
if err != nil {
97+
resp.Diagnostics.AddError("finding framework by name", err.Error())
98+
return
99+
}
100+
101+
// Framework metadata from the ListFrameworks API does not contain all information available
102+
// about a framework. Use framework ID to get complete information.
103+
framework, err := FindFrameworkByID(ctx, conn, aws.ToString(frameworkMetadata.Id))
104+
if err != nil {
105+
resp.Diagnostics.AddError("finding framework by ID", err.Error())
106+
return
107+
}
108+
109+
resp.Diagnostics.Append(data.refreshFromOutput(ctx, d.Meta(), framework)...)
110+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
111+
}
112+
113+
func FindFrameworkByName(ctx context.Context, conn *auditmanager.Client, name, frameworkType string) (*awstypes.AssessmentFrameworkMetadata, error) {
114+
in := &auditmanager.ListAssessmentFrameworksInput{
115+
FrameworkType: awstypes.FrameworkType(frameworkType),
116+
}
117+
pages := auditmanager.NewListAssessmentFrameworksPaginator(conn, in)
118+
119+
for pages.HasMorePages() {
120+
page, err := pages.NextPage(ctx)
121+
if err != nil {
122+
return nil, err
123+
}
124+
125+
for _, framework := range page.FrameworkMetadataList {
126+
if name == aws.ToString(framework.Name) {
127+
return &framework, nil
128+
}
129+
}
130+
}
131+
132+
return nil, &sdkv2resource.NotFoundError{
133+
LastRequest: in,
134+
}
135+
}
136+
137+
type dataSourceFrameworkData struct {
138+
ARN types.String `tfsdk:"arn"`
139+
ComplianceType types.String `tfsdk:"compliance_type"`
140+
ControlSets types.Set `tfsdk:"control_sets"`
141+
Description types.String `tfsdk:"description"`
142+
FrameworkType types.String `tfsdk:"framework_type"`
143+
ID types.String `tfsdk:"id"`
144+
Name types.String `tfsdk:"name"`
145+
Tags types.Map `tfsdk:"tags"`
146+
}
147+
148+
// refreshFromOutput writes state data from an AWS response object
149+
func (rd *dataSourceFrameworkData) refreshFromOutput(ctx context.Context, meta *conns.AWSClient, out *awstypes.Framework) diag.Diagnostics {
150+
var diags diag.Diagnostics
151+
152+
if out == nil {
153+
return diags
154+
}
155+
156+
rd.ID = types.StringValue(aws.ToString(out.Id))
157+
rd.Name = types.StringValue(aws.ToString(out.Name))
158+
cs, d := flattenFrameworkControlSets(ctx, out.ControlSets)
159+
diags.Append(d...)
160+
rd.ControlSets = cs
161+
162+
rd.ComplianceType = flex.StringToFramework(ctx, out.ComplianceType)
163+
rd.Description = flex.StringToFramework(ctx, out.Description)
164+
rd.FrameworkType = flex.StringValueToFramework(ctx, out.Type)
165+
rd.ARN = flex.StringToFramework(ctx, out.Arn)
166+
167+
ignoreTagsConfig := meta.IgnoreTagsConfig
168+
tags := KeyValueTags(out.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig)
169+
rd.Tags = flex.FlattenFrameworkStringValueMapLegacy(ctx, tags.Map())
170+
171+
return diags
172+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package auditmanager_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9+
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
10+
"github.com/hashicorp/terraform-provider-aws/names"
11+
)
12+
13+
func TestAccAuditManagerFrameworkDataSource_standard(t *testing.T) {
14+
// Standard frameworks are managed by AWS and will exist in the account automatically
15+
// once AuditManager is enabled.
16+
name := "Essential Eight"
17+
dataSourceName := "data.aws_auditmanager_framework.test"
18+
19+
resource.ParallelTest(t, resource.TestCase{
20+
PreCheck: func() {
21+
acctest.PreCheck(t)
22+
acctest.PreCheckPartitionHasService(names.AuditManagerEndpointID, t)
23+
},
24+
ErrorCheck: acctest.ErrorCheck(t, names.AuditManagerEndpointID),
25+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
26+
Steps: []resource.TestStep{
27+
{
28+
Config: testAccFrameworkDataSourceConfig_standard(name),
29+
Check: resource.ComposeTestCheckFunc(
30+
resource.TestCheckResourceAttr(dataSourceName, "name", name),
31+
resource.TestCheckResourceAttr(dataSourceName, "control_sets.#", "8"),
32+
),
33+
},
34+
},
35+
})
36+
}
37+
38+
func TestAccAuditManagerFrameworkDataSource_custom(t *testing.T) {
39+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
40+
dataSourceName := "data.aws_auditmanager_framework.test"
41+
42+
resource.ParallelTest(t, resource.TestCase{
43+
PreCheck: func() {
44+
acctest.PreCheck(t)
45+
acctest.PreCheckPartitionHasService(names.AuditManagerEndpointID, t)
46+
},
47+
ErrorCheck: acctest.ErrorCheck(t, names.AuditManagerEndpointID),
48+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
49+
Steps: []resource.TestStep{
50+
{
51+
Config: testAccFrameworkDataSourceConfig_custom(rName),
52+
Check: resource.ComposeTestCheckFunc(
53+
resource.TestCheckResourceAttr(dataSourceName, "name", rName),
54+
resource.TestCheckResourceAttr(dataSourceName, "control_sets.#", "1"),
55+
resource.TestCheckResourceAttr(dataSourceName, "control_sets.0.name", rName),
56+
resource.TestCheckResourceAttr(dataSourceName, "control_sets.0.controls.#", "1"),
57+
),
58+
},
59+
},
60+
})
61+
}
62+
63+
func testAccFrameworkDataSourceConfig_standard(rName string) string {
64+
return fmt.Sprintf(`
65+
data "aws_auditmanager_framework" "test" {
66+
name = %[1]q
67+
framework_type = "Standard"
68+
}
69+
`, rName)
70+
}
71+
72+
func testAccFrameworkDataSourceConfig_custom(rName string) string {
73+
return fmt.Sprintf(`
74+
resource "aws_auditmanager_control" "test" {
75+
name = %[1]q
76+
77+
control_mapping_sources {
78+
source_name = %[1]q
79+
source_set_up_option = "Procedural_Controls_Mapping"
80+
source_type = "MANUAL"
81+
}
82+
}
83+
84+
resource "aws_auditmanager_framework" "test" {
85+
name = %[1]q
86+
87+
control_sets {
88+
name = %[1]q
89+
controls {
90+
id = aws_auditmanager_control.test.id
91+
}
92+
}
93+
}
94+
95+
data "aws_auditmanager_framework" "test" {
96+
name = aws_auditmanager_framework.test.name
97+
framework_type = "Custom"
98+
}
99+
`, rName)
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
subcategory: "Audit Manager"
3+
layout: "aws"
4+
page_title: "AWS: aws_auditmanager_framework"
5+
description: |-
6+
Terraform data source for managing an AWS Audit Manager Framework.
7+
---
8+
9+
# Data Source: aws_auditmanager_framework
10+
11+
Terraform data source for managing an AWS Audit Manager Framework.
12+
13+
## Example Usage
14+
15+
### Basic Usage
16+
17+
```terraform
18+
data "aws_auditmanager_framework" "example" {
19+
name = "Essential Eight"
20+
framework_type = "Standard"
21+
}
22+
```
23+
24+
## Argument Reference
25+
26+
The following arguments are required:
27+
28+
* `name` - (Required) Name of the framework.
29+
* `type` - (Required) Type of framework. Valid values are `Custom` and `Standard`.
30+
31+
## Attributes Reference
32+
33+
See the [`aws_auditmanager_framework` resource](/docs/providers/aws/r/auditmanager_framework.html) for details on the returned attributes - they are identical.

0 commit comments

Comments
 (0)