From 13d57415ca314ea46d807655f1ec6003669ea0ab Mon Sep 17 00:00:00 2001 From: chroju Date: Sat, 25 Apr 2020 22:09:08 +0900 Subject: [PATCH 1/6] Resource/aws_ssm_service_setting: Add new resource --- aws/provider.go | 1 + aws/resource_aws_ssm_service_setting.go | 115 +++++++++++++++++++ aws/resource_aws_ssm_service_setting_test.go | 105 +++++++++++++++++ website/ssm_service_setting.markdown | 44 +++++++ 4 files changed, 265 insertions(+) create mode 100644 aws/resource_aws_ssm_service_setting.go create mode 100644 aws/resource_aws_ssm_service_setting_test.go create mode 100644 website/ssm_service_setting.markdown diff --git a/aws/provider.go b/aws/provider.go index 2c804cdc3c7..df4788fcd69 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -796,6 +796,7 @@ func Provider() terraform.ResourceProvider { "aws_ssm_patch_group": resourceAwsSsmPatchGroup(), "aws_ssm_parameter": resourceAwsSsmParameter(), "aws_ssm_resource_data_sync": resourceAwsSsmResourceDataSync(), + "aws_ssm_service_setting": resourceAwsSsmServiceSetting(), "aws_storagegateway_cache": resourceAwsStorageGatewayCache(), "aws_storagegateway_cached_iscsi_volume": resourceAwsStorageGatewayCachedIscsiVolume(), "aws_storagegateway_gateway": resourceAwsStorageGatewayGateway(), diff --git a/aws/resource_aws_ssm_service_setting.go b/aws/resource_aws_ssm_service_setting.go new file mode 100644 index 00000000000..c33d03c8bb1 --- /dev/null +++ b/aws/resource_aws_ssm_service_setting.go @@ -0,0 +1,115 @@ +package aws + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ssm" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceAwsSsmServiceSetting() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSsmServiceSettingUpdate, + Read: resourceAwsSsmServiceSettingRead, + Update: resourceAwsSsmServiceSettingUpdate, + Delete: resourceAwsSsmServiceSettingReset, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "setting_id": { + Type: schema.TypeString, + Required: true, + }, + "setting_value": { + Type: schema.TypeString, + Required: true, + }, + "last_modified_date": { + Type: schema.TypeString, + Computed: true, + }, + "last_modified_user": { + Type: schema.TypeString, + Computed: true, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsSsmServiceSettingUpdate(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*AWSClient).ssmconn + + log.Printf("[DEBUG] SSM service setting create: %s", d.Id()) + + updateServiceSettingInput := &ssm.UpdateServiceSettingInput{ + SettingId: aws.String(d.Get("setting_id").(string)), + SettingValue: aws.String(d.Get("setting_value").(string)), + } + + if _, err := ssmconn.UpdateServiceSetting(updateServiceSettingInput); err != nil { + return fmt.Errorf("Error updating SSM service setting: %s", err) + } + + d.SetId(d.Get("setting_id").(string)) + + return resourceAwsSsmServiceSettingRead(d, meta) +} + +func resourceAwsSsmServiceSettingRead(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*AWSClient).ssmconn + + log.Printf("[DEBUG] Reading SSM Activation: %s", d.Id()) + + params := &ssm.GetServiceSettingInput{ + SettingId: aws.String(d.Id()), + } + + resp, err := ssmconn.GetServiceSetting(params) + + if err != nil { + return fmt.Errorf("Error reading SSM service setting: %s", err) + } + + serviceSetting := resp.ServiceSetting + // 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", serviceSetting.ARN) + d.Set("setting_value", serviceSetting.SettingValue) + d.Set("arn", serviceSetting.ARN) + d.Set("last_modified_date", aws.TimeValue(serviceSetting.LastModifiedDate).Format(time.RFC3339)) + d.Set("last_modified_user", serviceSetting.LastModifiedUser) + d.Set("status", serviceSetting.Status) + + return nil +} + +func resourceAwsSsmServiceSettingReset(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*AWSClient).ssmconn + + log.Printf("[DEBUG] Deleting SSM Service Setting: %s", d.Id()) + + resetServiceSettingInput := &ssm.ResetServiceSettingInput{ + SettingId: aws.String(d.Get("setting_id").(string)), + } + + _, err := ssmconn.ResetServiceSetting(resetServiceSettingInput) + + if err != nil { + return fmt.Errorf("Error deleting SSM Service Setting: %s", err) + } + + return nil +} diff --git a/aws/resource_aws_ssm_service_setting_test.go b/aws/resource_aws_ssm_service_setting_test.go new file mode 100644 index 00000000000..98bf3ce7e41 --- /dev/null +++ b/aws/resource_aws_ssm_service_setting_test.go @@ -0,0 +1,105 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go/service/sts" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccAWSSSMServiceSetting_basic(t *testing.T) { + var setting ssm.GetServiceSettingOutput + resourceName := "aws_ssm_service_setting.test" + awsSession := session.New() + stssvc := sts.New(awsSession) + result, _ := stssvc.GetCallerIdentity(&sts.GetCallerIdentityInput{}) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSSMServiceSettingDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSSMServiceSetting(aws.StringValue(result.Account), aws.StringValue(awsSession.Config.Region), "false"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSSMServiceSettingExists(resourceName, &setting), + resource.TestCheckResourceAttr(resourceName, "setting_value", "false"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSSMServiceSetting(aws.StringValue(result.Account), aws.StringValue(awsSession.Config.Region), "true"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSSMServiceSettingExists(resourceName, &setting), + resource.TestCheckResourceAttr(resourceName, "setting_value", "true"), + ), + }, + }, + }) +} + +func testAccCheckAWSSSMServiceSettingDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*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 fmt.Errorf("SSM Service Setting still customized") + } + } + + return nil +} + +func testAccCheckAWSSSMServiceSettingExists(n string, res *ssm.GetServiceSettingOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := testAccProvider.Meta().(*AWSClient).ssmconn + + resp, err := conn.GetServiceSetting(&ssm.GetServiceSettingInput{ + SettingId: aws.String(rs.Primary.Attributes["setting_id"]), + }) + if err != nil { + return err + } + + *res = *resp + + return nil + } +} + +func testAccAWSSSMServiceSetting(accountID, region, value string) string { + return fmt.Sprintf(testSettingTemplate, region, accountID, value) +} + +const testSettingTemplate = ` +resource "aws_ssm_service_setting" "test" { + setting_id = "arn:aws:ssm:%s:%s:servicesetting/ssm/parameter-store/high-throughput-enabled" + setting_value = "%s" +} +` diff --git a/website/ssm_service_setting.markdown b/website/ssm_service_setting.markdown new file mode 100644 index 00000000000..0a06ad56f67 --- /dev/null +++ b/website/ssm_service_setting.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "SSM" +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 SSM service. +--- + +# Resource: aws_ssm_service_setting + +Defines how a user interacts with or uses a service or a feature of a SSM service. + +## Example Usage + +```hcl +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) The ID of the service setting. +* `service_value` - (Required) The value of the service setting. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The ARN of the service setting. +* `last_modified_date` - The last time the service setting was modified. +* `last_modified_user` - The ARN of the last modified user. This field is populated only if the setting value was overwritten. +* `status` - The status of the service setting. The 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 +``` From 01b92bed20d961182813907d5674185ad2c958eb Mon Sep 17 00:00:00 2001 From: chroju Date: Thu, 14 Jul 2022 22:49:05 +0900 Subject: [PATCH 2/6] Fix pre-refactor changes --- internal/provider/provider.go | 1 + internal/service/ssm/service_setting.go | 29 ++++++------- internal/service/ssm/service_setting_test.go | 41 +++++++++++-------- .../r/ssm_service_setting.html.markdown} | 4 +- 4 files changed, 41 insertions(+), 34 deletions(-) rename website/{ssm_service_setting.markdown => docs/r/ssm_service_setting.html.markdown} (96%) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index bc9edde328f..89c43b0394a 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -2009,6 +2009,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(), diff --git a/internal/service/ssm/service_setting.go b/internal/service/ssm/service_setting.go index c33d03c8bb1..4a44ebc6fab 100644 --- a/internal/service/ssm/service_setting.go +++ b/internal/service/ssm/service_setting.go @@ -1,4 +1,4 @@ -package aws +package ssm import ( "fmt" @@ -7,15 +7,16 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ssm" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" ) -func resourceAwsSsmServiceSetting() *schema.Resource { +func ResourceServiceSetting() *schema.Resource { return &schema.Resource{ - Create: resourceAwsSsmServiceSettingUpdate, - Read: resourceAwsSsmServiceSettingRead, - Update: resourceAwsSsmServiceSettingUpdate, - Delete: resourceAwsSsmServiceSettingReset, + Create: resourceServiceSettingUpdate, + Read: resourceServiceSettingRead, + Update: resourceServiceSettingUpdate, + Delete: resourceServiceSettingReset, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, @@ -49,8 +50,8 @@ func resourceAwsSsmServiceSetting() *schema.Resource { } } -func resourceAwsSsmServiceSettingUpdate(d *schema.ResourceData, meta interface{}) error { - ssmconn := meta.(*AWSClient).ssmconn +func resourceServiceSettingUpdate(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*conns.AWSClient).SSMConn log.Printf("[DEBUG] SSM service setting create: %s", d.Id()) @@ -65,11 +66,11 @@ func resourceAwsSsmServiceSettingUpdate(d *schema.ResourceData, meta interface{} d.SetId(d.Get("setting_id").(string)) - return resourceAwsSsmServiceSettingRead(d, meta) + return resourceServiceSettingRead(d, meta) } -func resourceAwsSsmServiceSettingRead(d *schema.ResourceData, meta interface{}) error { - ssmconn := meta.(*AWSClient).ssmconn +func resourceServiceSettingRead(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*conns.AWSClient).SSMConn log.Printf("[DEBUG] Reading SSM Activation: %s", d.Id()) @@ -96,8 +97,8 @@ func resourceAwsSsmServiceSettingRead(d *schema.ResourceData, meta interface{}) return nil } -func resourceAwsSsmServiceSettingReset(d *schema.ResourceData, meta interface{}) error { - ssmconn := meta.(*AWSClient).ssmconn +func resourceServiceSettingReset(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*conns.AWSClient).SSMConn log.Printf("[DEBUG] Deleting SSM Service Setting: %s", d.Id()) diff --git a/internal/service/ssm/service_setting_test.go b/internal/service/ssm/service_setting_test.go index 98bf3ce7e41..c313018dbdf 100644 --- a/internal/service/ssm/service_setting_test.go +++ b/internal/service/ssm/service_setting_test.go @@ -1,4 +1,4 @@ -package aws +package ssm_test import ( "fmt" @@ -9,11 +9,13 @@ import ( "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/ssm" "github.com/aws/aws-sdk-go/service/sts" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "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" ) -func TestAccAWSSSMServiceSetting_basic(t *testing.T) { +func TestAccSSMServiceSetting_basic(t *testing.T) { var setting ssm.GetServiceSettingOutput resourceName := "aws_ssm_service_setting.test" awsSession := session.New() @@ -21,14 +23,15 @@ func TestAccAWSSSMServiceSetting_basic(t *testing.T) { result, _ := stssvc.GetCallerIdentity(&sts.GetCallerIdentityInput{}) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSSSMServiceSettingDestroy, + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ssm.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccServiceSettingDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSSMServiceSetting(aws.StringValue(result.Account), aws.StringValue(awsSession.Config.Region), "false"), + Config: testAccServiceSettingConfig_basic(aws.StringValue(result.Account), aws.StringValue(awsSession.Config.Region), "false"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSSMServiceSettingExists(resourceName, &setting), + testAccServiceSettingExists(resourceName, &setting), resource.TestCheckResourceAttr(resourceName, "setting_value", "false"), ), }, @@ -38,9 +41,9 @@ func TestAccAWSSSMServiceSetting_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSSSMServiceSetting(aws.StringValue(result.Account), aws.StringValue(awsSession.Config.Region), "true"), + Config: testAccServiceSettingConfig_basic(aws.StringValue(result.Account), aws.StringValue(awsSession.Config.Region), "true"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSSMServiceSettingExists(resourceName, &setting), + testAccServiceSettingExists(resourceName, &setting), resource.TestCheckResourceAttr(resourceName, "setting_value", "true"), ), }, @@ -48,8 +51,8 @@ func TestAccAWSSSMServiceSetting_basic(t *testing.T) { }) } -func testAccCheckAWSSSMServiceSettingDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).ssmconn +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" { @@ -71,14 +74,14 @@ func testAccCheckAWSSSMServiceSettingDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSSSMServiceSettingExists(n string, res *ssm.GetServiceSettingOutput) resource.TestCheckFunc { +func testAccServiceSettingExists(n string, res *ssm.GetServiceSettingOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - conn := testAccProvider.Meta().(*AWSClient).ssmconn + conn := acctest.Provider.Meta().(*conns.AWSClient).SSMConn resp, err := conn.GetServiceSetting(&ssm.GetServiceSettingInput{ SettingId: aws.String(rs.Primary.Attributes["setting_id"]), @@ -93,13 +96,15 @@ func testAccCheckAWSSSMServiceSettingExists(n string, res *ssm.GetServiceSetting } } -func testAccAWSSSMServiceSetting(accountID, region, value string) string { +func testAccServiceSettingConfig_basic(accountID, region, value string) string { return fmt.Sprintf(testSettingTemplate, region, accountID, value) } const testSettingTemplate = ` +data "aws_partition" "current" {} + resource "aws_ssm_service_setting" "test" { - setting_id = "arn:aws:ssm:%s:%s:servicesetting/ssm/parameter-store/high-throughput-enabled" - setting_value = "%s" + setting_id = "arn:${data.aws_partition.current.partition}:ssm:%s:%s:servicesetting/ssm/parameter-store/high-throughput-enabled" + setting_value = "%s" } ` diff --git a/website/ssm_service_setting.markdown b/website/docs/r/ssm_service_setting.html.markdown similarity index 96% rename from website/ssm_service_setting.markdown rename to website/docs/r/ssm_service_setting.html.markdown index 0a06ad56f67..5b5158b7580 100644 --- a/website/ssm_service_setting.markdown +++ b/website/docs/r/ssm_service_setting.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "SSM" +subcategory: "SSM (Systems Manager)" layout: "aws" page_title: "AWS: aws_ssm_service_setting" description: |- @@ -12,7 +12,7 @@ Defines how a user interacts with or uses a service or a feature of a SSM servic ## Example Usage -```hcl +```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" From 158e33aea58c8ac711eb17629323c86b3d77850e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 25 Jul 2022 15:02:14 -0400 Subject: [PATCH 3/6] ssm: Protov5providerfactories --- internal/service/ssm/service_setting_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/ssm/service_setting_test.go b/internal/service/ssm/service_setting_test.go index c313018dbdf..51de0d3c09f 100644 --- a/internal/service/ssm/service_setting_test.go +++ b/internal/service/ssm/service_setting_test.go @@ -23,10 +23,10 @@ func TestAccSSMServiceSetting_basic(t *testing.T) { result, _ := stssvc.GetCallerIdentity(&sts.GetCallerIdentityInput{}) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, ssm.EndpointsID), - ProviderFactories: acctest.ProviderFactories, - CheckDestroy: testAccServiceSettingDestroy, + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ssm.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccServiceSettingDestroy, Steps: []resource.TestStep{ { Config: testAccServiceSettingConfig_basic(aws.StringValue(result.Account), aws.StringValue(awsSession.Config.Region), "false"), From 7c3d73ec4df4b9fd085a0497758e14e1f7e8df6a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 25 Jul 2022 18:07:05 -0400 Subject: [PATCH 4/6] ssm: Clean up service setting --- internal/service/ssm/find.go | 19 ++++++ internal/service/ssm/service_setting.go | 68 +++++++++---------- internal/service/ssm/service_setting_test.go | 42 ++++++------ internal/service/ssm/status.go | 12 ++++ internal/service/ssm/wait.go | 30 ++++++++ .../docs/r/ssm_service_setting.html.markdown | 14 ++-- 6 files changed, 117 insertions(+), 68 deletions(-) diff --git a/internal/service/ssm/find.go b/internal/service/ssm/find.go index 44d5b17fcda..76fe185ab77 100644 --- a/internal/service/ssm/find.go +++ b/internal/service/ssm/find.go @@ -86,3 +86,22 @@ func FindPatchGroup(conn *ssm.SSM, patchGroup, baselineId string) (*ssm.PatchGro return result, err } + +// FindServiceSetting returns the Document corresponding to the specified name. +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 +} diff --git a/internal/service/ssm/service_setting.go b/internal/service/ssm/service_setting.go index 4a44ebc6fab..bfe72fbe80d 100644 --- a/internal/service/ssm/service_setting.go +++ b/internal/service/ssm/service_setting.go @@ -1,14 +1,17 @@ package ssm import ( - "fmt" "log" - "time" "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 { @@ -22,6 +25,10 @@ func ResourceServiceSetting() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, "setting_id": { Type: schema.TypeString, Required: true, @@ -30,18 +37,6 @@ func ResourceServiceSetting() *schema.Resource { Type: schema.TypeString, Required: true, }, - "last_modified_date": { - Type: schema.TypeString, - Computed: true, - }, - "last_modified_user": { - Type: schema.TypeString, - Computed: true, - }, - "arn": { - Type: schema.TypeString, - Computed: true, - }, "status": { Type: schema.TypeString, Computed: true, @@ -51,54 +46,50 @@ func ResourceServiceSetting() *schema.Resource { } func resourceServiceSettingUpdate(d *schema.ResourceData, meta interface{}) error { - ssmconn := meta.(*conns.AWSClient).SSMConn + conn := meta.(*conns.AWSClient).SSMConn - log.Printf("[DEBUG] SSM service setting create: %s", d.Id()) + 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 := ssmconn.UpdateServiceSetting(updateServiceSettingInput); err != nil { - return fmt.Errorf("Error updating SSM service setting: %s", err) + 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 { - ssmconn := meta.(*conns.AWSClient).SSMConn + conn := meta.(*conns.AWSClient).SSMConn log.Printf("[DEBUG] Reading SSM Activation: %s", d.Id()) - params := &ssm.GetServiceSettingInput{ - SettingId: aws.String(d.Id()), - } - - resp, err := ssmconn.GetServiceSetting(params) - + output, err := FindServiceSettingByARN(conn, d.Id()) if err != nil { - return fmt.Errorf("Error reading SSM service setting: %s", err) + return names.Error(names.SSM, names.ErrActionReading, ResNameServiceSetting, d.Id(), err) } - serviceSetting := resp.ServiceSetting // 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", serviceSetting.ARN) - d.Set("setting_value", serviceSetting.SettingValue) - d.Set("arn", serviceSetting.ARN) - d.Set("last_modified_date", aws.TimeValue(serviceSetting.LastModifiedDate).Format(time.RFC3339)) - d.Set("last_modified_user", serviceSetting.LastModifiedUser) - d.Set("status", serviceSetting.Status) + 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 { - ssmconn := meta.(*conns.AWSClient).SSMConn + conn := meta.(*conns.AWSClient).SSMConn log.Printf("[DEBUG] Deleting SSM Service Setting: %s", d.Id()) @@ -106,10 +97,13 @@ func resourceServiceSettingReset(d *schema.ResourceData, meta interface{}) error SettingId: aws.String(d.Get("setting_id").(string)), } - _, err := ssmconn.ResetServiceSetting(resetServiceSettingInput) - + _, err := conn.ResetServiceSetting(resetServiceSettingInput) if err != nil { - return fmt.Errorf("Error deleting SSM Service Setting: %s", err) + 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 diff --git a/internal/service/ssm/service_setting_test.go b/internal/service/ssm/service_setting_test.go index 51de0d3c09f..a04f1761404 100644 --- a/internal/service/ssm/service_setting_test.go +++ b/internal/service/ssm/service_setting_test.go @@ -6,21 +6,18 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aws/aws-sdk-go/service/sts" "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.GetServiceSettingOutput + var setting ssm.ServiceSetting resourceName := "aws_ssm_service_setting.test" - awsSession := session.New() - stssvc := sts.New(awsSession) - result, _ := stssvc.GetCallerIdentity(&sts.GetCallerIdentityInput{}) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -29,7 +26,7 @@ func TestAccSSMServiceSetting_basic(t *testing.T) { CheckDestroy: testAccServiceSettingDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceSettingConfig_basic(aws.StringValue(result.Account), aws.StringValue(awsSession.Config.Region), "false"), + Config: testAccServiceSettingConfig_basic("false"), Check: resource.ComposeTestCheckFunc( testAccServiceSettingExists(resourceName, &setting), resource.TestCheckResourceAttr(resourceName, "setting_value", "false"), @@ -41,7 +38,7 @@ func TestAccSSMServiceSetting_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccServiceSettingConfig_basic(aws.StringValue(result.Account), aws.StringValue(awsSession.Config.Region), "true"), + Config: testAccServiceSettingConfig_basic("true"), Check: resource.ComposeTestCheckFunc( testAccServiceSettingExists(resourceName, &setting), resource.TestCheckResourceAttr(resourceName, "setting_value", "true"), @@ -67,14 +64,14 @@ func testAccServiceSettingDestroy(s *terraform.State) error { return err } if output.ServiceSetting.Status != aws.String("default") { - return fmt.Errorf("SSM Service Setting still customized") + return names.Error(names.SSM, names.ErrActionCheckingDestroyed, tfssm.ResNameServiceSetting, rs.Primary.Attributes["setting_id"], err) } } return nil } -func testAccServiceSettingExists(n string, res *ssm.GetServiceSettingOutput) resource.TestCheckFunc { +func testAccServiceSettingExists(n string, res *ssm.ServiceSetting) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -83,28 +80,27 @@ func testAccServiceSettingExists(n string, res *ssm.GetServiceSettingOutput) res conn := acctest.Provider.Meta().(*conns.AWSClient).SSMConn - resp, err := conn.GetServiceSetting(&ssm.GetServiceSettingInput{ - SettingId: aws.String(rs.Primary.Attributes["setting_id"]), - }) + output, err := tfssm.FindServiceSettingByARN(conn, rs.Primary.Attributes["setting_id"]) + if err != nil { - return err + return names.Error(names.SSM, names.ErrActionReading, tfssm.ResNameServiceSetting, rs.Primary.Attributes["setting_id"], err) } - *res = *resp + *res = *output return nil } } -func testAccServiceSettingConfig_basic(accountID, region, value string) string { - return fmt.Sprintf(testSettingTemplate, region, accountID, value) -} - -const testSettingTemplate = ` +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:%s:%s:servicesetting/ssm/parameter-store/high-throughput-enabled" - setting_value = "%s" + 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) } -` diff --git a/internal/service/ssm/status.go b/internal/service/ssm/status.go index f32b506c890..e3f20568fb1 100644 --- a/internal/service/ssm/status.go +++ b/internal/service/ssm/status.go @@ -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 + } +} diff --git a/internal/service/ssm/wait.go b/internal/service/ssm/wait.go index 38d4804a8db..0d02874234c 100644 --- a/internal/service/ssm/wait.go +++ b/internal/service/ssm/wait.go @@ -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) { //nolint:unparam + 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 { //nolint:unparam + stateConf := &resource.StateChangeConf{ + Pending: []string{"Customized", "PendingUpdate", ""}, + Target: []string{"Default"}, + Refresh: statusServiceSetting(conn, arn), + Timeout: timeout, + } + + _, err := stateConf.WaitForState() + + return err +} diff --git a/website/docs/r/ssm_service_setting.html.markdown b/website/docs/r/ssm_service_setting.html.markdown index 5b5158b7580..76251ca1c60 100644 --- a/website/docs/r/ssm_service_setting.html.markdown +++ b/website/docs/r/ssm_service_setting.html.markdown @@ -3,12 +3,12 @@ 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 SSM service. + Defines how a user interacts with or uses a service or a feature of a service. --- # Resource: aws_ssm_service_setting -Defines how a user interacts with or uses a service or a feature of a SSM service. +This setting defines how a user interacts with or uses a service or a feature of a service. ## Example Usage @@ -23,17 +23,15 @@ resource "aws_ssm_service_setting" "test_setting" { The following arguments are supported: -* `service_id` - (Required) The ID of the service setting. -* `service_value` - (Required) The value of the service setting. +* `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` - The ARN of the service setting. -* `last_modified_date` - The last time the service setting was modified. -* `last_modified_user` - The ARN of the last modified user. This field is populated only if the setting value was overwritten. -* `status` - The status of the service setting. The value can be Default, Customized or PendingUpdate. +* `arn` - ARN of the service setting. +* `status` - Status of the service setting. Value can be `Default`, `Customized` or `PendingUpdate`. ## Import From 2b2de7b3831d69b40ff35761134a015482e522c4 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 25 Jul 2022 18:11:19 -0400 Subject: [PATCH 5/6] Add changelog --- .changelog/13018.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/13018.txt diff --git a/.changelog/13018.txt b/.changelog/13018.txt new file mode 100644 index 00000000000..7ec742bd129 --- /dev/null +++ b/.changelog/13018.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_ssm_service_setting +``` \ No newline at end of file From 8b93a379cd276d14e4efdc9d5106dd5fa03bef3f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 25 Jul 2022 18:13:07 -0400 Subject: [PATCH 6/6] ssm/service_setting: Cleanup --- internal/service/ssm/find.go | 1 - internal/service/ssm/wait.go | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/service/ssm/find.go b/internal/service/ssm/find.go index 76fe185ab77..55e3f36984b 100644 --- a/internal/service/ssm/find.go +++ b/internal/service/ssm/find.go @@ -87,7 +87,6 @@ func FindPatchGroup(conn *ssm.SSM, patchGroup, baselineId string) (*ssm.PatchGro return result, err } -// FindServiceSetting returns the Document corresponding to the specified name. func FindServiceSettingByARN(conn *ssm.SSM, arn string) (*ssm.ServiceSetting, error) { input := &ssm.GetServiceSettingInput{ SettingId: aws.String(arn), diff --git a/internal/service/ssm/wait.go b/internal/service/ssm/wait.go index 0d02874234c..f5afec5db7c 100644 --- a/internal/service/ssm/wait.go +++ b/internal/service/ssm/wait.go @@ -71,7 +71,7 @@ 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) { //nolint:unparam +func waitServiceSettingUpdated(conn *ssm.SSM, arn string, timeout time.Duration) (*ssm.ServiceSetting, error) { stateConf := &resource.StateChangeConf{ Pending: []string{"PendingUpdate", ""}, Target: []string{"Customized", "Default"}, @@ -88,7 +88,7 @@ func waitServiceSettingUpdated(conn *ssm.SSM, arn string, timeout time.Duration) return nil, err } -func waitServiceSettingReset(conn *ssm.SSM, arn string, timeout time.Duration) error { //nolint:unparam +func waitServiceSettingReset(conn *ssm.SSM, arn string, timeout time.Duration) error { stateConf := &resource.StateChangeConf{ Pending: []string{"Customized", "PendingUpdate", ""}, Target: []string{"Default"},