Skip to content

Commit

Permalink
d/aws_ssm_patch_baselines: new data source (#39779)
Browse files Browse the repository at this point in the history
This data source will allow practitioners to list all AWS SSM patch baselines, with optional filters.

```console
% make testacc PKG=ssm TESTS=TestAccSSMPatchBaselinesDataSource_
make: Verifying source code with gofmt...
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go1.23.2 test ./internal/service/ssm/... -v -count 1 -parallel 20 -run='TestAccSSMPatchBaselinesDataSource_'  -timeout 360m
2024/10/17 14:31:44 Initializing Terraform AWS Provider...

--- PASS: TestAccSSMPatchBaselinesDataSource_filter (9.70s)
--- PASS: TestAccSSMPatchBaselinesDataSource_defaultBaselines (9.70s)
--- PASS: TestAccSSMPatchBaselinesDataSource_basic (9.70s)
PASS
ok      github.com/hashicorp/terraform-provider-aws/internal/service/ssm        15.980s
```
  • Loading branch information
jar-b authored Oct 21, 2024
1 parent 972f2ad commit 70c945e
Show file tree
Hide file tree
Showing 5 changed files with 341 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .changelog/39779.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-data-source
aws_ssm_patch_baselines
```
140 changes: 140 additions & 0 deletions internal/service/ssm/patch_baselines_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package ssm

import (
"context"

"github.com/aws/aws-sdk-go-v2/service/ssm"
awstypes "github.com/aws/aws-sdk-go-v2/service/ssm/types"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/framework"
"github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @FrameworkDataSource("aws_ssm_patch_baselines", name="Patch Baselines")
func newDataSourcePatchBaselines(context.Context) (datasource.DataSourceWithConfigure, error) {
return &dataSourcePatchBaselines{}, nil
}

const (
DSNamePatchBaselines = "Patch Baselines Data Source"
)

type dataSourcePatchBaselines struct {
framework.DataSourceWithConfigure
}

func (d *dataSourcePatchBaselines) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { // nosemgrep:ci.meta-in-func-name
resp.TypeName = "aws_ssm_patch_baselines"
}

func (d *dataSourcePatchBaselines) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"baseline_identities": schema.ListAttribute{
CustomType: fwtypes.NewListNestedObjectTypeOf[baselineIdentityModel](ctx),
Computed: true,
ElementType: fwtypes.NewObjectTypeOf[baselineIdentityModel](ctx),
},
"default_baselines": schema.BoolAttribute{
Optional: true,
},
},
Blocks: map[string]schema.Block{
names.AttrFilter: schema.ListNestedBlock{
CustomType: fwtypes.NewListNestedObjectTypeOf[filterModel](ctx),
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
names.AttrKey: schema.StringAttribute{
Required: true,
},
names.AttrValues: schema.SetAttribute{
CustomType: fwtypes.SetOfStringType,
Required: true,
},
},
},
},
},
}
}
func (d *dataSourcePatchBaselines) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
conn := d.Meta().SSMClient(ctx)

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

input := ssm.DescribePatchBaselinesInput{}
resp.Diagnostics.Append(flex.Expand(ctx, data, &input)...)
if resp.Diagnostics.HasError() {
return
}

out, err := findPatchBaselines(ctx, conn, &input)
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.SSM, create.ErrActionReading, DSNamePatchBaselines, "", err),
err.Error(),
)
return
}

if data.DefaultBaselines.ValueBool() {
out = tfslices.Filter(out, func(v awstypes.PatchBaselineIdentity) bool {
return v.DefaultBaseline
})
}

resp.Diagnostics.Append(flex.Flatten(ctx, out, &data.BaselineIdentities)...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func findPatchBaselines(ctx context.Context, conn *ssm.Client, input *ssm.DescribePatchBaselinesInput) ([]awstypes.PatchBaselineIdentity, error) {
var baselines []awstypes.PatchBaselineIdentity
pages := ssm.NewDescribePatchBaselinesPaginator(conn, input)
for pages.HasMorePages() {
page, err := pages.NextPage(ctx)

if err != nil {
return nil, err
}

baselines = append(baselines, page.BaselineIdentities...)
}

return baselines, nil
}

type dataSourcePatchBaselinesModel struct {
BaselineIdentities fwtypes.ListNestedObjectValueOf[baselineIdentityModel] `tfsdk:"baseline_identities"`
Filter fwtypes.ListNestedObjectValueOf[filterModel] `tfsdk:"filter"`
DefaultBaselines types.Bool `tfsdk:"default_baselines"`
}

type baselineIdentityModel struct {
BaselineDescription types.String `tfsdk:"baseline_description"`
BaselineID types.String `tfsdk:"baseline_id"`
BaselineName types.String `tfsdk:"baseline_name"`
DefaultBaseline types.Bool `tfsdk:"default_baseline"`
OperatingSystem types.String `tfsdk:"operating_system"`
}

type filterModel struct {
Key types.String `tfsdk:"key"`
Values fwtypes.SetOfString `tfsdk:"values"`
}
132 changes: 132 additions & 0 deletions internal/service/ssm/patch_baselines_data_source_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package ssm_test

import (
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/names"
)

func TestAccSSMPatchBaselinesDataSource_basic(t *testing.T) {
ctx := acctest.Context(t)
dataSourceName := "data.aws_ssm_patch_baselines.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.SSMEndpointID)
},
ErrorCheck: acctest.ErrorCheck(t, names.SSMServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccPatchBaselinesDataSourceConfig_basic(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckTypeSetElemNestedAttrs(dataSourceName, "baseline_identities.*", map[string]string{
"baseline_name": "AWS-UbuntuDefaultPatchBaseline",
"default_baseline": acctest.CtTrue,
"operating_system": "UBUNTU",
}),
resource.TestCheckTypeSetElemNestedAttrs(dataSourceName, "baseline_identities.*", map[string]string{
"baseline_name": "AWS-WindowsPredefinedPatchBaseline-OS",
"default_baseline": acctest.CtFalse,
"operating_system": "WINDOWS",
}),
),
},
},
})
}

func TestAccSSMPatchBaselinesDataSource_defaultBaselines(t *testing.T) {
ctx := acctest.Context(t)
dataSourceName := "data.aws_ssm_patch_baselines.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.SSMEndpointID)
},
ErrorCheck: acctest.ErrorCheck(t, names.SSMServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccPatchBaselinesDataSourceConfig_defaultBaselines(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckTypeSetElemNestedAttrs(dataSourceName, "baseline_identities.*", map[string]string{
"baseline_name": "AWS-UbuntuDefaultPatchBaseline",
"default_baseline": acctest.CtTrue,
"operating_system": "UBUNTU",
}),
),
},
},
})
}

func TestAccSSMPatchBaselinesDataSource_filter(t *testing.T) {
ctx := acctest.Context(t)
dataSourceName := "data.aws_ssm_patch_baselines.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.SSMEndpointID)
},
ErrorCheck: acctest.ErrorCheck(t, names.SSMServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccPatchBaselinesDataSourceConfig_filter(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckTypeSetElemNestedAttrs(dataSourceName, "baseline_identities.*", map[string]string{
"baseline_name": "AWS-DefaultPatchBaseline",
"default_baseline": acctest.CtTrue,
"operating_system": "WINDOWS",
}),
resource.TestCheckTypeSetElemNestedAttrs(dataSourceName, "baseline_identities.*", map[string]string{
"baseline_name": "AWS-WindowsPredefinedPatchBaseline-OS",
"default_baseline": acctest.CtFalse,
"operating_system": "WINDOWS",
}),
),
},
},
})
}

func testAccPatchBaselinesDataSourceConfig_basic() string {
return `
data "aws_ssm_patch_baselines" "test" {}
`
}

func testAccPatchBaselinesDataSourceConfig_defaultBaselines() string {
return `
data "aws_ssm_patch_baselines" "test" {
default_baselines = true
}
`
}

func testAccPatchBaselinesDataSourceConfig_filter() string {
return `
data "aws_ssm_patch_baselines" "test" {
filter {
key = "OWNER"
values = ["AWS"]
}
filter {
key = "OPERATING_SYSTEM"
values = ["WINDOWS"]
}
}
`
}
7 changes: 6 additions & 1 deletion internal/service/ssm/service_package_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions website/docs/d/ssm_patch_baselines.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
subcategory: "SSM (Systems Manager)"
layout: "aws"
page_title: "AWS: aws_ssm_patch_baselines"
description: |-
Terraform data source for retrieving AWS SSM (Systems Manager) Patch Baselines.
---

# Data Source: aws_ssm_patch_baselines

Terraform data source for retrieving AWS SSM (Systems Manager) Patch Baselines.

## Example Usage

### Basic Usage

```terraform
data "aws_ssm_patch_baselines" "example" {}
```

### With Filters

```terraform
data "aws_ssm_patch_baselines" "example" {
filter {
key = "OWNER"
values = ["AWS"]
}
filter {
key = "OPERATING_SYSTEM"
values = ["WINDOWS"]
}
}
```

## Argument Reference

The following arguments are optional:

* `filter` - (Optional) Key-value pairs used to filter the results. See [`filter`](#filter-argument-reference) below.
* `default_baselines` - (Optional) Only return baseline identities where `default_baseline` is `true`.

### `filter` Argument Reference

* `key` - (Required) Filter key. See the [AWS SSM documentation](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_DescribePatchBaselines.html) for valid values.
* `values` - (Required) Filter values. See the [AWS SSM documentation](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_DescribePatchBaselines.html) for example values.

## Attribute Reference

This data source exports the following attributes in addition to the arguments above:

* `baseline_identities` - List of baseline identities. See [`baseline_identities`](#baseline_identities-attribute-reference) below.

### `baseline_identities` Attribute Reference

* `baseline_description` - Description of the patch baseline.
* `baseline_id` - ID of the patch baseline.
* `baseline_name` - Name of the patch baseline.
* `default_baseline` - Indicates whether this is the default baseline. AWS Systems Manager supports creating multiple default patch baselines. For example, you can create a default patch baseline for each operating system.
* `operating_system` - Operating system the patch baseline applies to.

0 comments on commit 70c945e

Please sign in to comment.