diff --git a/aws/resource_aws_ssm_document.go b/aws/resource_aws_ssm_document.go index cf96d589ff5..68356bc1d6f 100644 --- a/aws/resource_aws_ssm_document.go +++ b/aws/resource_aws_ssm_document.go @@ -3,13 +3,11 @@ 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" @@ -17,7 +15,6 @@ import ( ) const ( - MINIMUM_VERSIONED_SCHEMA = 2.0 SSM_DOCUMENT_PERMISSIONS_BATCH_LIMIT = 20 ) @@ -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": { @@ -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) @@ -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 } diff --git a/aws/resource_aws_ssm_document_test.go b/aws/resource_aws_ssm_document_test.go index 7d12d312289..59b2e7c2e23 100644 --- a/aws/resource_aws_ssm_document_test.go +++ b/aws/resource_aws_ssm_document_test.go @@ -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, + }, }, }) } @@ -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( @@ -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, + }, }, }) } @@ -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, + }, }, }) } @@ -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, + }, }, }) } @@ -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( @@ -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, + }, }, }) } @@ -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"), + ), + }, }, }) } @@ -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, + }, }, }) } @@ -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( @@ -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( @@ -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 = <