Skip to content

Commit

Permalink
Merge pull request #13018 from chroju/add/ssm_service_setting
Browse files Browse the repository at this point in the history
resource/aws_ssm_service_setting: Add new resource
  • Loading branch information
YakDriver authored Jul 25, 2022
2 parents 99eac74 + 8b93a37 commit daf6ea6
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/13018.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_ssm_service_setting
```
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2027,6 +2027,7 @@ func Provider() *schema.Provider {
"aws_ssm_patch_baseline": ssm.ResourcePatchBaseline(),
"aws_ssm_patch_group": ssm.ResourcePatchGroup(),
"aws_ssm_resource_data_sync": ssm.ResourceResourceDataSync(),
"aws_ssm_service_setting": ssm.ResourceServiceSetting(),

"aws_ssoadmin_account_assignment": ssoadmin.ResourceAccountAssignment(),
"aws_ssoadmin_managed_policy_attachment": ssoadmin.ResourceManagedPolicyAttachment(),
Expand Down
18 changes: 18 additions & 0 deletions internal/service/ssm/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,21 @@ func FindPatchGroup(conn *ssm.SSM, patchGroup, baselineId string) (*ssm.PatchGro

return result, err
}

func FindServiceSettingByARN(conn *ssm.SSM, arn string) (*ssm.ServiceSetting, error) {
input := &ssm.GetServiceSettingInput{
SettingId: aws.String(arn),
}

output, err := conn.GetServiceSetting(input)

if err != nil {
return nil, err
}

if output == nil || output.ServiceSetting == nil {
return nil, fmt.Errorf("finding %s: empty result", arn)
}

return output.ServiceSetting, nil
}
110 changes: 110 additions & 0 deletions internal/service/ssm/service_setting.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package ssm

import (
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/names"
)

const (
ResNameServiceSetting = "Service Setting"
)

func ResourceServiceSetting() *schema.Resource {
return &schema.Resource{
Create: resourceServiceSettingUpdate,
Read: resourceServiceSettingRead,
Update: resourceServiceSettingUpdate,
Delete: resourceServiceSettingReset,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"setting_id": {
Type: schema.TypeString,
Required: true,
},
"setting_value": {
Type: schema.TypeString,
Required: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceServiceSettingUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).SSMConn

log.Printf("[DEBUG] SSM service setting create: %s", d.Get("setting_id").(string))

updateServiceSettingInput := &ssm.UpdateServiceSettingInput{
SettingId: aws.String(d.Get("setting_id").(string)),
SettingValue: aws.String(d.Get("setting_value").(string)),
}

if _, err := conn.UpdateServiceSetting(updateServiceSettingInput); err != nil {
return names.Error(names.SSM, names.ErrActionUpdating, ResNameServiceSetting, d.Get("setting_id").(string), err)
}

d.SetId(d.Get("setting_id").(string))

if _, err := waitServiceSettingUpdated(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil {
return names.Error(names.SSM, names.ErrActionWaitingForUpdate, ResNameServiceSetting, d.Id(), err)
}

return resourceServiceSettingRead(d, meta)
}

func resourceServiceSettingRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).SSMConn

log.Printf("[DEBUG] Reading SSM Activation: %s", d.Id())

output, err := FindServiceSettingByARN(conn, d.Id())
if err != nil {
return names.Error(names.SSM, names.ErrActionReading, ResNameServiceSetting, d.Id(), err)
}

// AWS SSM service setting API requires the entire ARN as input,
// but setting_id in the output is only a part of ARN.
d.Set("setting_id", output.ARN)
d.Set("setting_value", output.SettingValue)
d.Set("arn", output.ARN)
d.Set("status", output.Status)

return nil
}

func resourceServiceSettingReset(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).SSMConn

log.Printf("[DEBUG] Deleting SSM Service Setting: %s", d.Id())

resetServiceSettingInput := &ssm.ResetServiceSettingInput{
SettingId: aws.String(d.Get("setting_id").(string)),
}

_, err := conn.ResetServiceSetting(resetServiceSettingInput)
if err != nil {
return names.Error(names.SSM, names.ErrActionDeleting, ResNameServiceSetting, d.Id(), err)
}

if err := waitServiceSettingReset(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil {
return names.Error(names.SSM, names.ErrActionWaitingForDeletion, ResNameServiceSetting, d.Id(), err)
}

return nil
}
106 changes: 106 additions & 0 deletions internal/service/ssm/service_setting_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package ssm_test

import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
tfssm "github.com/hashicorp/terraform-provider-aws/internal/service/ssm"
"github.com/hashicorp/terraform-provider-aws/names"
)

func TestAccSSMServiceSetting_basic(t *testing.T) {
var setting ssm.ServiceSetting
resourceName := "aws_ssm_service_setting.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, ssm.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccServiceSettingDestroy,
Steps: []resource.TestStep{
{
Config: testAccServiceSettingConfig_basic("false"),
Check: resource.ComposeTestCheckFunc(
testAccServiceSettingExists(resourceName, &setting),
resource.TestCheckResourceAttr(resourceName, "setting_value", "false"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccServiceSettingConfig_basic("true"),
Check: resource.ComposeTestCheckFunc(
testAccServiceSettingExists(resourceName, &setting),
resource.TestCheckResourceAttr(resourceName, "setting_value", "true"),
),
},
},
})
}

func testAccServiceSettingDestroy(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).SSMConn

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_ssm_service_setting" {
continue
}

output, err := conn.GetServiceSetting(&ssm.GetServiceSettingInput{
SettingId: aws.String(rs.Primary.Attributes["setting_id"]),
})
_, ok := err.(awserr.Error)
if !ok {
return err
}
if output.ServiceSetting.Status != aws.String("default") {
return names.Error(names.SSM, names.ErrActionCheckingDestroyed, tfssm.ResNameServiceSetting, rs.Primary.Attributes["setting_id"], err)
}
}

return nil
}

func testAccServiceSettingExists(n string, res *ssm.ServiceSetting) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

conn := acctest.Provider.Meta().(*conns.AWSClient).SSMConn

output, err := tfssm.FindServiceSettingByARN(conn, rs.Primary.Attributes["setting_id"])

if err != nil {
return names.Error(names.SSM, names.ErrActionReading, tfssm.ResNameServiceSetting, rs.Primary.Attributes["setting_id"], err)
}

*res = *output

return nil
}
}

func testAccServiceSettingConfig_basic(settingValue string) string {
return fmt.Sprintf(`
data "aws_partition" "current" {}
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
resource "aws_ssm_service_setting" "test" {
setting_id = "arn:${data.aws_partition.current.partition}:ssm:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:servicesetting/ssm/parameter-store/high-throughput-enabled"
setting_value = %[1]q
}
`, settingValue)
}
12 changes: 12 additions & 0 deletions internal/service/ssm/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,15 @@ func statusDocument(conn *ssm.SSM, name string) resource.StateRefreshFunc {
return output, aws.StringValue(output.Status), nil
}
}

func statusServiceSetting(conn *ssm.SSM, arn string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := FindServiceSettingByARN(conn, arn)

if tfresource.NotFound(err) {
return nil, "", nil
}

return output, aws.StringValue(output.Status), nil
}
}
30 changes: 30 additions & 0 deletions internal/service/ssm/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,33 @@ func waitDocumentActive(conn *ssm.SSM, name string) (*ssm.DocumentDescription, e

return nil, err
}

func waitServiceSettingUpdated(conn *ssm.SSM, arn string, timeout time.Duration) (*ssm.ServiceSetting, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{"PendingUpdate", ""},
Target: []string{"Customized", "Default"},
Refresh: statusServiceSetting(conn, arn),
Timeout: timeout,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*ssm.ServiceSetting); ok {
return output, err
}

return nil, err
}

func waitServiceSettingReset(conn *ssm.SSM, arn string, timeout time.Duration) error {
stateConf := &resource.StateChangeConf{
Pending: []string{"Customized", "PendingUpdate", ""},
Target: []string{"Default"},
Refresh: statusServiceSetting(conn, arn),
Timeout: timeout,
}

_, err := stateConf.WaitForState()

return err
}
42 changes: 42 additions & 0 deletions website/docs/r/ssm_service_setting.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
subcategory: "SSM (Systems Manager)"
layout: "aws"
page_title: "AWS: aws_ssm_service_setting"
description: |-
Defines how a user interacts with or uses a service or a feature of a service.
---

# Resource: aws_ssm_service_setting

This setting defines how a user interacts with or uses a service or a feature of a service.

## Example Usage

```terraform
resource "aws_ssm_service_setting" "test_setting" {
service_id = "arn:aws:ssm:us-east-1:123456789012:servicesetting/ssm/parameter-store/high-throughput-enabled"
service_value = "true"
}
```

## Argument Reference

The following arguments are supported:

* `service_id` - (Required) ID of the service setting.
* `service_value` - (Required) Value of the service setting.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:

* `arn` - ARN of the service setting.
* `status` - Status of the service setting. Value can be `Default`, `Customized` or `PendingUpdate`.

## Import

AWS SSM Service Setting can be imported using the `setting_id`, e.g.

```sh
$ terraform import aws_ssm_service_setting.example arn:aws:ssm:us-east-1:123456789012:servicesetting/ssm/parameter-store/high-throughput-enabled
```

0 comments on commit daf6ea6

Please sign in to comment.