Skip to content

Commit

Permalink
Merge pull request #28967 from hashicorp/f-aws_auditmanager_control_d…
Browse files Browse the repository at this point in the history
…ata_source

New Data Source: `aws_auditmanager_control`
  • Loading branch information
jar-b committed Jan 18, 2023
2 parents dedc569 + d243235 commit 8e0e9fb
Show file tree
Hide file tree
Showing 4 changed files with 366 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/28967.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-data-source
aws_auditmanager_control
```
208 changes: 208 additions & 0 deletions internal/service/auditmanager/control_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
package auditmanager

import (
"context"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/auditmanager"
awstypes "github.com/aws/aws-sdk-go-v2/service/auditmanager/types"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
sdkv2resource "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/enum"
"github.com/hashicorp/terraform-provider-aws/internal/flex"
"github.com/hashicorp/terraform-provider-aws/internal/framework"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
)

func init() {
_sp.registerFrameworkDataSourceFactory(newDataSourceControl)
}

func newDataSourceControl(context.Context) (datasource.DataSourceWithConfigure, error) {
return &dataSourceControl{}, nil
}

type dataSourceControl struct {
framework.DataSourceWithConfigure
}

func (d *dataSourceControl) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { // nosemgrep:ci.meta-in-func-name
response.TypeName = "aws_auditmanager_control"
}

func (d *dataSourceControl) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"action_plan_instructions": schema.StringAttribute{
Computed: true,
},
"action_plan_title": schema.StringAttribute{
Computed: true,
},
"arn": framework.ARNAttributeComputedOnly(),
"description": schema.StringAttribute{
Computed: true,
},
"id": framework.IDAttribute(),
"name": schema.StringAttribute{
Required: true,
},
"tags": tftags.TagsAttributeComputedOnly(),
"testing_information": schema.StringAttribute{
Computed: true,
},
"type": schema.StringAttribute{
Required: true,
Validators: []validator.String{
enum.FrameworkValidate[awstypes.ControlType](),
},
},
},
Blocks: map[string]schema.Block{
"control_mapping_sources": schema.SetNestedBlock{
Validators: []validator.Set{
setvalidator.SizeAtLeast(1),
},
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"source_description": schema.StringAttribute{
Computed: true,
},
"source_frequency": schema.StringAttribute{
Computed: true,
},
"source_id": framework.IDAttribute(),
"source_name": schema.StringAttribute{
Computed: true,
},
"source_set_up_option": schema.StringAttribute{
Computed: true,
},
"source_type": schema.StringAttribute{
Computed: true,
},
"troubleshooting_text": schema.StringAttribute{
Computed: true,
},
},
Blocks: map[string]schema.Block{
"source_keyword": schema.ListNestedBlock{
Validators: []validator.List{
listvalidator.SizeAtMost(1),
},
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"keyword_input_type": schema.StringAttribute{
Computed: true,
},
"keyword_value": schema.StringAttribute{
Computed: true,
},
},
},
},
},
},
},
},
}
}

func (d *dataSourceControl) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
conn := d.Meta().AuditManagerClient()

var data dataSourceControlData
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

controlMetadata, err := FindControlByName(ctx, conn, data.Name.ValueString(), data.Type.ValueString())
if err != nil {
resp.Diagnostics.AddError("finding control by name", err.Error())
return
}

// Control metadata from the ListControls API does not contain all information available
// about a control. Use control ID to get complete information.
control, err := FindControlByID(ctx, conn, aws.ToString(controlMetadata.Id))
if err != nil {
resp.Diagnostics.AddError("finding control by ID", err.Error())
return
}

resp.Diagnostics.Append(data.refreshFromOutput(ctx, d.Meta(), control)...)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func FindControlByName(ctx context.Context, conn *auditmanager.Client, name, controlType string) (*awstypes.ControlMetadata, error) {
in := &auditmanager.ListControlsInput{
ControlType: awstypes.ControlType(controlType),
}
pages := auditmanager.NewListControlsPaginator(conn, in)

for pages.HasMorePages() {
page, err := pages.NextPage(ctx)
if err != nil {
return nil, err
}

for _, control := range page.ControlMetadataList {
if name == aws.ToString(control.Name) {
return &control, nil
}
}
}

return nil, &sdkv2resource.NotFoundError{
LastRequest: in,
}
}

type dataSourceControlData struct {
ActionPlanInstructions types.String `tfsdk:"action_plan_instructions"`
ActionPlanTitle types.String `tfsdk:"action_plan_title"`
ARN types.String `tfsdk:"arn"`
ControlMappingSources types.Set `tfsdk:"control_mapping_sources"`
Description types.String `tfsdk:"description"`
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Tags types.Map `tfsdk:"tags"`
TestingInformation types.String `tfsdk:"testing_information"`
Type types.String `tfsdk:"type"`
}

// refreshFromOutput writes state data from an AWS response object
func (rd *dataSourceControlData) refreshFromOutput(ctx context.Context, meta *conns.AWSClient, out *awstypes.Control) diag.Diagnostics {
var diags diag.Diagnostics

if out == nil {
return diags
}

rd.ID = types.StringValue(aws.ToString(out.Id))
rd.Name = types.StringValue(aws.ToString(out.Name))
cms, d := flattenControlMappingSources(ctx, out.ControlMappingSources)
diags.Append(d...)
rd.ControlMappingSources = cms

rd.ActionPlanInstructions = flex.StringToFramework(ctx, out.ActionPlanInstructions)
rd.ActionPlanTitle = flex.StringToFramework(ctx, out.ActionPlanTitle)
rd.Description = flex.StringToFramework(ctx, out.Description)
rd.TestingInformation = flex.StringToFramework(ctx, out.TestingInformation)
rd.ARN = flex.StringToFramework(ctx, out.Arn)
rd.Type = types.StringValue(string(out.Type))

ignoreTagsConfig := meta.IgnoreTagsConfig
tags := KeyValueTags(out.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig)
rd.Tags = flex.FlattenFrameworkStringValueMapLegacy(ctx, tags.Map())

return diags
}
91 changes: 91 additions & 0 deletions internal/service/auditmanager/control_data_source_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package auditmanager_test

import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go-v2/service/auditmanager/types"
sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/names"
)

func TestAccAuditManagerControlDataSource_standard(t *testing.T) {
// Standard controls are managed by AWS and will exist in the account automatically
// once AuditManager is enabled.
name := "1. Risk Management"
dataSourceName := "data.aws_auditmanager_control.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
acctest.PreCheckPartitionHasService(names.AuditManagerEndpointID, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.AuditManagerEndpointID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccControlDataSourceConfig_standard(name),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "name", name),
resource.TestCheckResourceAttr(dataSourceName, "control_mapping_sources.#", "3"),
),
},
},
})
}

func TestAccAuditManagerControlDataSource_custom(t *testing.T) {
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
dataSourceName := "data.aws_auditmanager_control.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
acctest.PreCheckPartitionHasService(names.AuditManagerEndpointID, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.AuditManagerEndpointID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccControlDataSourceConfig_custom(rName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "name", rName),
resource.TestCheckResourceAttr(dataSourceName, "control_mapping_sources.#", "1"),
resource.TestCheckResourceAttr(dataSourceName, "control_mapping_sources.0.source_name", rName),
resource.TestCheckResourceAttr(dataSourceName, "control_mapping_sources.0.source_set_up_option", string(types.SourceSetUpOptionProceduralControlsMapping)),
resource.TestCheckResourceAttr(dataSourceName, "control_mapping_sources.0.source_type", string(types.SourceTypeManual)),
),
},
},
})
}

func testAccControlDataSourceConfig_standard(rName string) string {
return fmt.Sprintf(`
data "aws_auditmanager_control" "test" {
name = %[1]q
type = "Standard"
}
`, rName)
}

func testAccControlDataSourceConfig_custom(rName string) string {
return fmt.Sprintf(`
resource "aws_auditmanager_control" "test" {
name = %[1]q
control_mapping_sources {
source_name = %[1]q
source_set_up_option = "Procedural_Controls_Mapping"
source_type = "MANUAL"
}
}
data "aws_auditmanager_control" "test" {
name = aws_auditmanager_control.test.name
type = "Custom"
}
`, rName)
}
64 changes: 64 additions & 0 deletions website/docs/d/auditmanager_control.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
subcategory: "Audit Manager"
layout: "aws"
page_title: "AWS: aws_auditmanager_control"
description: |-
Terraform data source for managing an AWS Audit Manager Control.
---

# Data Source: aws_auditmanager_control

Terraform data source for managing an AWS Audit Manager Control.

## Example Usage

### Basic Usage

```terraform
data "aws_auditmanager_control" "example" {
name = "1. Risk Management"
type = "Standard"
}
```

### With Framework Resource

```terraform
data "aws_auditmanager_control" "example" {
name = "1. Risk Management"
type = "Standard"
}
data "aws_auditmanager_control" "example2" {
name = "2. Personnel"
type = "Standard"
}
resource "aws_auditmanager_framework" "example" {
name = "example"
control_sets {
name = "example"
controls {
id = data.aws_auditmanager_control.example.id
}
}
control_sets {
name = "example2"
controls {
id = data.aws_auditmanager_control.example2.id
}
}
}
```

## Argument Reference

The following arguments are required:

* `name` - (Required) Name of the control.
* `type` - (Required) Type of control. Valid values are `Custom` and `Standard`.

## Attributes Reference

See the [`aws_auditmanager_control` resource](/docs/providers/aws/r/auditmanager_control.html) for details on the returned attributes - they are identical.

0 comments on commit 8e0e9fb

Please sign in to comment.