Skip to content

Commit 6ad4b89

Browse files
PeteGoostack72
authored andcommitted
provider/aws Add support for updating SSM documents (#13491)
* Add schema_version as computed ssm document attribute * Update the SSM document itself if the content has changed and it has a schema >= 2.0 * Add default_version as DocumentVersion in SSM doc update * Acceptance test for updating an SSM document * Better error handling in updating SSM documents * Add SSM document update documentation * Better names for SSM input params
1 parent 113c06a commit 6ad4b89

File tree

3 files changed

+168
-0
lines changed

3 files changed

+168
-0
lines changed

builtin/providers/aws/resource_aws_ssm_document.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package aws
33
import (
44
"fmt"
55
"log"
6+
"strconv"
67
"strings"
78
"time"
89

@@ -14,6 +15,10 @@ import (
1415
"github.com/hashicorp/terraform/helper/schema"
1516
)
1617

18+
const (
19+
MINIMUM_VERSIONED_SCHEMA = 2.0
20+
)
21+
1722
func resourceAwsSsmDocument() *schema.Resource {
1823
return &schema.Resource{
1924
Create: resourceAwsSsmDocumentCreate,
@@ -35,6 +40,10 @@ func resourceAwsSsmDocument() *schema.Resource {
3540
Required: true,
3641
ValidateFunc: validateAwsSSMDocumentType,
3742
},
43+
"schema_version": {
44+
Type: schema.TypeString,
45+
Computed: true,
46+
},
3847
"created_date": {
3948
Type: schema.TypeString,
4049
Computed: true,
@@ -173,6 +182,7 @@ func resourceAwsSsmDocumentRead(d *schema.ResourceData, meta interface{}) error
173182
d.Set("created_date", doc.CreatedDate)
174183
d.Set("default_version", doc.DefaultVersion)
175184
d.Set("description", doc.Description)
185+
d.Set("schema_version", doc.SchemaVersion)
176186

177187
if _, ok := d.GetOk("document_type"); ok {
178188
d.Set("document_type", doc.DocumentType)
@@ -238,6 +248,23 @@ func resourceAwsSsmDocumentUpdate(d *schema.ResourceData, meta interface{}) erro
238248
log.Printf("[DEBUG] Not setting document permissions on %q", d.Id())
239249
}
240250

251+
if !d.HasChange("content") {
252+
return nil
253+
}
254+
255+
if schemaVersion, ok := d.GetOk("schemaVersion"); ok {
256+
schemaNumber, _ := strconv.ParseFloat(schemaVersion.(string), 64)
257+
258+
if schemaNumber < MINIMUM_VERSIONED_SCHEMA {
259+
log.Printf("[DEBUG] Skipping document update because document version is not 2.0 %q", d.Id())
260+
return nil
261+
}
262+
}
263+
264+
if err := updateAwsSSMDocument(d, meta); err != nil {
265+
return err
266+
}
267+
241268
return resourceAwsSsmDocumentRead(d, meta)
242269
}
243270

@@ -381,6 +408,47 @@ func deleteDocumentPermissions(d *schema.ResourceData, meta interface{}) error {
381408
return nil
382409
}
383410

411+
func updateAwsSSMDocument(d *schema.ResourceData, meta interface{}) error {
412+
log.Printf("[INFO] Updating SSM Document: %s", d.Id())
413+
414+
name := d.Get("name").(string)
415+
416+
updateDocInput := &ssm.UpdateDocumentInput{
417+
Name: aws.String(name),
418+
Content: aws.String(d.Get("content").(string)),
419+
DocumentVersion: aws.String(d.Get("default_version").(string)),
420+
}
421+
422+
newDefaultVersion := d.Get("default_version").(string)
423+
424+
ssmconn := meta.(*AWSClient).ssmconn
425+
updated, err := ssmconn.UpdateDocument(updateDocInput)
426+
427+
if isAWSErr(err, "DuplicateDocumentContent", "") {
428+
log.Printf("[DEBUG] Content is a duplicate of the latest version so update is not necessary: %s", d.Id())
429+
log.Printf("[INFO] Updating the default version to the latest version %s: %s", newDefaultVersion, d.Id())
430+
431+
newDefaultVersion = d.Get("latest_version").(string)
432+
} else if err != nil {
433+
return errwrap.Wrapf("Error updating SSM document: {{err}}", err)
434+
} else {
435+
log.Printf("[INFO] Updating the default version to the new version %s: %s", newDefaultVersion, d.Id())
436+
newDefaultVersion = *updated.DocumentDescription.DocumentVersion
437+
}
438+
439+
updateDefaultInput := &ssm.UpdateDocumentDefaultVersionInput{
440+
Name: aws.String(name),
441+
DocumentVersion: aws.String(newDefaultVersion),
442+
}
443+
444+
_, err = ssmconn.UpdateDocumentDefaultVersion(updateDefaultInput)
445+
446+
if err != nil {
447+
return errwrap.Wrapf("Error updating the default document version to that of the updated document: {{err}}", err)
448+
}
449+
return nil
450+
}
451+
384452
func validateAwsSSMDocumentType(v interface{}, k string) (ws []string, errors []error) {
385453
value := v.(string)
386454
types := map[string]bool{

builtin/providers/aws/resource_aws_ssm_document_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,39 @@ func TestAccAWSSSMDocument_basic(t *testing.T) {
2929
})
3030
}
3131

32+
func TestAccAWSSSMDocument_update(t *testing.T) {
33+
name := acctest.RandString(10)
34+
resource.Test(t, resource.TestCase{
35+
PreCheck: func() { testAccPreCheck(t) },
36+
Providers: testAccProviders,
37+
CheckDestroy: testAccCheckAWSSSMDocumentDestroy,
38+
Steps: []resource.TestStep{
39+
resource.TestStep{
40+
Config: testAccAWSSSMDocument20Config(name),
41+
Check: resource.ComposeTestCheckFunc(
42+
testAccCheckAWSSSMDocumentExists("aws_ssm_document.foo"),
43+
resource.TestCheckResourceAttr(
44+
"aws_ssm_document.foo", "schema_version", "2.0"),
45+
resource.TestCheckResourceAttr(
46+
"aws_ssm_document.foo", "latest_version", "1"),
47+
resource.TestCheckResourceAttr(
48+
"aws_ssm_document.foo", "default_version", "1"),
49+
),
50+
},
51+
resource.TestStep{
52+
Config: testAccAWSSSMDocument20UpdatedConfig(name),
53+
Check: resource.ComposeTestCheckFunc(
54+
testAccCheckAWSSSMDocumentExists("aws_ssm_document.foo"),
55+
resource.TestCheckResourceAttr(
56+
"aws_ssm_document.foo", "latest_version", "2"),
57+
resource.TestCheckResourceAttr(
58+
"aws_ssm_document.foo", "default_version", "2"),
59+
),
60+
},
61+
},
62+
})
63+
}
64+
3265
func TestAccAWSSSMDocument_permission(t *testing.T) {
3366
name := acctest.RandString(10)
3467
resource.Test(t, resource.TestCase{
@@ -186,6 +219,66 @@ DOC
186219
`, rName)
187220
}
188221

222+
func testAccAWSSSMDocument20Config(rName string) string {
223+
return fmt.Sprintf(`
224+
resource "aws_ssm_document" "foo" {
225+
name = "test_document-%s"
226+
document_type = "Command"
227+
228+
content = <<DOC
229+
{
230+
"schemaVersion": "2.0",
231+
"description": "Sample version 2.0 document v2",
232+
"parameters": {
233+
234+
},
235+
"mainSteps": [
236+
{
237+
"action": "aws:runPowerShellScript",
238+
"name": "runPowerShellScript",
239+
"inputs": {
240+
"runCommand": [
241+
"Get-Process"
242+
]
243+
}
244+
}
245+
]
246+
}
247+
DOC
248+
}
249+
`, rName)
250+
}
251+
252+
func testAccAWSSSMDocument20UpdatedConfig(rName string) string {
253+
return fmt.Sprintf(`
254+
resource "aws_ssm_document" "foo" {
255+
name = "test_document-%s"
256+
document_type = "Command"
257+
258+
content = <<DOC
259+
{
260+
"schemaVersion": "2.0",
261+
"description": "Sample version 2.0 document v2",
262+
"parameters": {
263+
264+
},
265+
"mainSteps": [
266+
{
267+
"action": "aws:runPowerShellScript",
268+
"name": "runPowerShellScript",
269+
"inputs": {
270+
"runCommand": [
271+
"Get-Process -Verbose"
272+
]
273+
}
274+
}
275+
]
276+
}
277+
DOC
278+
}
279+
`, rName)
280+
}
281+
189282
func testAccAWSSSMDocumentPermissionConfig(rName string) string {
190283
return fmt.Sprintf(`
191284
resource "aws_ssm_document" "foo" {

website/source/docs/providers/aws/r/ssm_document.html.markdown

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ description: |-
1010

1111
Provides an SSM Document resource
1212

13+
~> **NOTE on updating SSM documents:** Only documents with a schema version of 2.0
14+
or greater can update their content once created, see [SSM Schema Features][1]. To update a document with an older
15+
schema version you must recreate the resource.
16+
1317
## Example Usage
1418

1519
```
@@ -56,6 +60,7 @@ The following attributes are exported:
5660
* `content` - The json content of the document.
5761
* `created_date` - The date the document was created.
5862
* `description` - The description of the document.
63+
* `schema_version` - The schema version of the document.
5964
* `document_type` - The type of document created.
6065
* `default_version` - The default version of the document.
6166
* `hash` - The sha1 or sha256 of the document content
@@ -67,6 +72,8 @@ The following attributes are exported:
6772
* `permissions` - The permissions of how this document should be shared.
6873
* `platform_types` - A list of OS platforms compatible with this SSM document, either "Windows" or "Linux".
6974

75+
[1]: http://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-ssm-docs.html#document-schemas-features
76+
7077
## Permissions
7178

7279
The permissions attribute specifies how you want to share the document. If you share a document privately,

0 commit comments

Comments
 (0)