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_document: Ensure content attribute is refreshed and support resource import #9313

Merged
merged 3 commits into from
Jul 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 38 additions & 27 deletions aws/resource_aws_ssm_document.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,18 @@ package aws
import (
"fmt"
"log"
"strconv"
"strings"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)

const (
MINIMUM_VERSIONED_SCHEMA = 2.0
SSM_DOCUMENT_PERMISSIONS_BATCH_LIMIT = 20
)

Expand All @@ -27,6 +24,9 @@ func resourceAwsSsmDocument() *schema.Resource {
Read: resourceAwsSsmDocumentRead,
Update: resourceAwsSsmDocumentUpdate,
Delete: resourceAwsSsmDocumentDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"arn": {
Expand Down Expand Up @@ -204,31 +204,51 @@ func resourceAwsSsmDocumentRead(d *schema.ResourceData, meta interface{}) error

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

docInput := &ssm.DescribeDocumentInput{
Name: aws.String(d.Get("name").(string)),
describeDocumentInput := &ssm.DescribeDocumentInput{
Name: aws.String(d.Id()),
}

describeDocumentOutput, err := ssmconn.DescribeDocument(describeDocumentInput)

if isAWSErr(err, ssm.ErrCodeInvalidDocument, "") {
log.Printf("[WARN] SSM Document not found so removing from state")
d.SetId("")
return nil
}

resp, err := ssmconn.DescribeDocument(docInput)
if err != nil {
if ssmErr, ok := err.(awserr.Error); ok && ssmErr.Code() == "InvalidDocument" {
log.Printf("[WARN] SSM Document not found so removing from state")
d.SetId("")
return nil
}
return fmt.Errorf("Error describing SSM document: %s", err)
return fmt.Errorf("error describing SSM Document (%s): %s", d.Id(), err)
}

if describeDocumentOutput == nil || describeDocumentOutput.Document == nil {
return fmt.Errorf("error describing SSM Document (%s): empty result", d.Id())
}

getDocumentInput := &ssm.GetDocumentInput{
DocumentFormat: describeDocumentOutput.Document.DocumentFormat,
DocumentVersion: aws.String("$LATEST"),
Name: describeDocumentOutput.Document.Name,
}

getDocumentOutput, err := ssmconn.GetDocument(getDocumentInput)

if err != nil {
return fmt.Errorf("error getting SSM Document (%s): %s", d.Id(), err)
}

doc := resp.Document
if getDocumentOutput == nil {
return fmt.Errorf("error getting SSM Document (%s): empty result", d.Id())
}

doc := describeDocumentOutput.Document

d.Set("content", getDocumentOutput.Content)
d.Set("created_date", doc.CreatedDate)
d.Set("default_version", doc.DefaultVersion)
d.Set("description", doc.Description)
d.Set("schema_version", doc.SchemaVersion)

if _, ok := d.GetOk("document_type"); ok {
d.Set("document_type", doc.DocumentType)
}

d.Set("document_format", doc.DocumentFormat)
d.Set("document_type", doc.DocumentType)
d.Set("document_version", doc.DocumentVersion)
d.Set("hash", doc.Hash)
d.Set("hash_type", doc.HashType)
Expand Down Expand Up @@ -319,15 +339,6 @@ func resourceAwsSsmDocumentUpdate(d *schema.ResourceData, meta interface{}) erro
return nil
}

if schemaVersion, ok := d.GetOk("schemaVersion"); ok {
schemaNumber, _ := strconv.ParseFloat(schemaVersion.(string), 64)

if schemaNumber < MINIMUM_VERSIONED_SCHEMA {
log.Printf("[DEBUG] Skipping document update because document version is not 2.0 %q", d.Id())
return nil
}
}

if err := updateAwsSSMDocument(d, meta); err != nil {
return err
}
Expand Down
135 changes: 135 additions & 0 deletions aws/resource_aws_ssm_document_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ func TestAccAWSSSMDocument_basic(t *testing.T) {
"aws_ssm_document.foo", "tags.Name", "My Document"),
),
},
{
ResourceName: "aws_ssm_document.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
Expand All @@ -55,6 +60,11 @@ func TestAccAWSSSMDocument_update(t *testing.T) {
"aws_ssm_document.foo", "default_version", "1"),
),
},
{
ResourceName: "aws_ssm_document.foo",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccAWSSSMDocument20UpdatedConfig(name),
Check: resource.ComposeTestCheckFunc(
Expand Down Expand Up @@ -86,6 +96,11 @@ func TestAccAWSSSMDocument_permission_public(t *testing.T) {
"aws_ssm_document.foo", "permissions.account_ids", "all"),
),
},
{
ResourceName: "aws_ssm_document.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
Expand All @@ -106,6 +121,11 @@ func TestAccAWSSSMDocument_permission_private(t *testing.T) {
"aws_ssm_document.foo", "permissions.type", "Share"),
),
},
{
ResourceName: "aws_ssm_document.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
Expand All @@ -126,6 +146,11 @@ func TestAccAWSSSMDocument_permission_batching(t *testing.T) {
"aws_ssm_document.foo", "permissions.type", "Share"),
),
},
{
ResourceName: "aws_ssm_document.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
Expand All @@ -149,6 +174,11 @@ func TestAccAWSSSMDocument_permission_change(t *testing.T) {
resource.TestCheckResourceAttr("aws_ssm_document.foo", "permissions.account_ids", idsInitial),
),
},
{
ResourceName: "aws_ssm_document.foo",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccAWSSSMDocumentPrivatePermissionConfig(name, idsRemove),
Check: resource.ComposeTestCheckFunc(
Expand Down Expand Up @@ -196,6 +226,11 @@ func TestAccAWSSSMDocument_params(t *testing.T) {
"aws_ssm_document.foo", "parameter.2.type", "String"),
),
},
{
ResourceName: "aws_ssm_document.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
Expand All @@ -215,6 +250,43 @@ func TestAccAWSSSMDocument_automation(t *testing.T) {
"aws_ssm_document.foo", "document_type", "Automation"),
),
},
{
ResourceName: "aws_ssm_document.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccAWSSSMDocument_SchemaVersion_1(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_ssm_document.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSSMDocumentDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSSSMDocumentConfigSchemaVersion1(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSSMDocumentExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "schema_version", "1.0"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccAWSSSMDocumentConfigSchemaVersion1Update(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSSMDocumentExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "schema_version", "1.0"),
),
},
},
})
}
Expand All @@ -234,6 +306,11 @@ func TestAccAWSSSMDocument_session(t *testing.T) {
"aws_ssm_document.foo", "document_type", "Session"),
),
},
{
ResourceName: "aws_ssm_document.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
Expand Down Expand Up @@ -275,6 +352,11 @@ mainSteps:
resource.TestCheckResourceAttr("aws_ssm_document.foo", "document_format", "YAML"),
),
},
{
ResourceName: "aws_ssm_document.foo",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccAWSSSMDocumentConfig_DocumentFormat_YAML(name, content2),
Check: resource.ComposeTestCheckFunc(
Expand Down Expand Up @@ -304,6 +386,11 @@ func TestAccAWSSSMDocument_Tags(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccAWSSSMDocumentConfig_Tags_Multiple(rName, "key1", "value1updated", "key2", "value2"),
Check: resource.ComposeTestCheckFunc(
Expand Down Expand Up @@ -719,6 +806,54 @@ DOC
`, rName, content)
}

func testAccAWSSSMDocumentConfigSchemaVersion1(rName string) string {
return fmt.Sprintf(`
resource "aws_ssm_document" "test" {
name = %[1]q
document_type = "Session"

content = <<DOC
{
"schemaVersion": "1.0",
"description": "Document to hold regional settings for Session Manager",
"sessionType": "Standard_Stream",
"inputs": {
"s3BucketName": "test",
"s3KeyPrefix": "test",
"s3EncryptionEnabled": true,
"cloudWatchLogGroupName": "/logs/sessions",
"cloudWatchEncryptionEnabled": false
}
}
DOC
}
`, rName)
}

func testAccAWSSSMDocumentConfigSchemaVersion1Update(rName string) string {
return fmt.Sprintf(`
resource "aws_ssm_document" "test" {
name = %[1]q
document_type = "Session"

content = <<DOC
{
"schemaVersion": "1.0",
"description": "Document to hold regional settings for Session Manager",
"sessionType": "Standard_Stream",
"inputs": {
"s3BucketName": "test",
"s3KeyPrefix": "test",
"s3EncryptionEnabled": true,
"cloudWatchLogGroupName": "/logs/sessions-updated",
"cloudWatchEncryptionEnabled": false
}
}
DOC
}
`, rName)
}

func testAccAWSSSMDocumentConfig_Tags_Single(rName, key1, value1 string) string {
return fmt.Sprintf(`
resource "aws_ssm_document" "foo" {
Expand Down
8 changes: 8 additions & 0 deletions website/docs/r/ssm_document.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,11 @@ The permissions mapping supports the following:

* `type` - The permission type for the document. The permission type can be `Share`.
* `account_ids` - The AWS user accounts that should have access to the document. The account IDs can either be a group of account IDs or `All`.

## Import

SSM Documents can be imported using the name, e.g.

```
$ terraform import aws_ssm_document.example example
```