Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/aws_ssm_service_setting: Add new resource #13018

Merged
merged 9 commits into from
Jul 25, 2022
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
```