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

Fix Automation SSM Document ARN for Resource and Data Source #39705

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
7 changes: 7 additions & 0 deletions .changelog/39705.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:bug
resource/aws_ssm_document: Correct `arn` for automation documents
```

```release-note:bug
data-source/aws_ssm_document: Correct `arn` for automation documents
```
32 changes: 22 additions & 10 deletions internal/service/ssm/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,24 +329,18 @@ func resourceDocumentRead(ctx context.Context, d *schema.ResourceData, meta inte
return sdkdiag.AppendErrorf(diags, "reading SSM Document (%s): %s", d.Id(), err)
}

arn := arn.ARN{
Partition: meta.(*conns.AWSClient).Partition,
Service: "ssm",
Region: meta.(*conns.AWSClient).Region,
AccountID: meta.(*conns.AWSClient).AccountID,
Resource: "document/" + aws.ToString(doc.Name),
}.String()
d.Set(names.AttrARN, arn)
documentType, name := doc.DocumentType, aws.ToString(doc.Name)
d.Set(names.AttrARN, documentARN(meta.(*conns.AWSClient), documentType, name))
d.Set(names.AttrCreatedDate, aws.ToTime(doc.CreatedDate).Format(time.RFC3339))
d.Set("default_version", doc.DefaultVersion)
d.Set(names.AttrDescription, doc.Description)
d.Set("document_format", doc.DocumentFormat)
d.Set("document_type", doc.DocumentType)
d.Set("document_type", documentType)
d.Set("document_version", doc.DocumentVersion)
d.Set("hash", doc.Hash)
d.Set("hash_type", doc.HashType)
d.Set("latest_version", doc.LatestVersion)
d.Set(names.AttrName, doc.Name)
d.Set(names.AttrName, name)
d.Set(names.AttrOwner, doc.Owner)
if err := d.Set(names.AttrParameter, flattenDocumentParameters(doc.Parameters)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting parameter: %s", err)
Expand Down Expand Up @@ -721,3 +715,21 @@ func flattenDocumentParameters(apiObjects []awstypes.DocumentParameter) []interf

return tfList
}

func documentARN(c *conns.AWSClient, documentType awstypes.DocumentType, name string) string {
arn := arn.ARN{
Partition: c.Partition,
Service: "ssm",
Region: c.Region,
AccountID: c.AccountID,
}

switch documentType {
case awstypes.DocumentTypeAutomation:
arn.Resource = "automation-definition/" + name
default:
arn.Resource = "document/" + name
}

return arn.String()
}
18 changes: 5 additions & 13 deletions internal/service/ssm/document_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"strings"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws/arn"
"github.com/aws/aws-sdk-go-v2/service/ssm"
awstypes "github.com/aws/aws-sdk-go-v2/service/ssm/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
Expand Down Expand Up @@ -75,25 +74,18 @@ func dataDocumentRead(ctx context.Context, d *schema.ResourceData, meta interfac
return sdkdiag.AppendErrorf(diags, "reading SSM Document (%s) content: %s", name, err)
}

d.SetId(aws.ToString(output.Name))

documentType, name := output.DocumentType, aws.ToString(output.Name)
d.SetId(name)
if !strings.HasPrefix(name, "AWS-") {
arn := arn.ARN{
Partition: meta.(*conns.AWSClient).Partition,
Service: "ssm",
Region: meta.(*conns.AWSClient).Region,
AccountID: meta.(*conns.AWSClient).AccountID,
Resource: "document/" + name,
}.String()
d.Set(names.AttrARN, arn)
d.Set(names.AttrARN, documentARN(meta.(*conns.AWSClient), documentType, name))
} else {
d.Set(names.AttrARN, name)
}
d.Set(names.AttrContent, output.Content)
d.Set("document_format", output.DocumentFormat)
d.Set("document_type", output.DocumentType)
d.Set("document_type", documentType)
d.Set("document_version", output.DocumentVersion)
d.Set(names.AttrName, output.Name)
d.Set(names.AttrName, name)

return diags
}
136 changes: 136 additions & 0 deletions internal/service/ssm/document_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,45 @@ func TestAccSSMDocumentDataSource_basic(t *testing.T) {
})
}

func TestAccSSMDocumentDataSource_basicAutomation(t *testing.T) {
ctx := acctest.Context(t)
dataSourceName := "data.aws_ssm_document.test"
resourceName := "aws_ssm_document.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.SSMServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccDocumentDataSourceConfig_basicAutomation(rName, "JSON"),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN),
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrName, resourceName, names.AttrName),
resource.TestCheckResourceAttrPair(dataSourceName, "document_format", resourceName, "document_format"),
resource.TestCheckResourceAttr(dataSourceName, "document_version", acctest.Ct1),
resource.TestCheckResourceAttrPair(dataSourceName, "document_type", resourceName, "document_type"),
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrContent, resourceName, names.AttrContent),
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrName, resourceName, names.AttrName),
),
},
{
Config: testAccDocumentDataSourceConfig_basicAutomation(rName, "YAML"),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN),
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrName, resourceName, names.AttrName),
resource.TestCheckResourceAttr(dataSourceName, "document_format", "YAML"),
resource.TestCheckResourceAttr(dataSourceName, "document_version", acctest.Ct1),
resource.TestCheckResourceAttrPair(dataSourceName, "document_type", resourceName, "document_type"),
resource.TestCheckResourceAttrSet(dataSourceName, names.AttrContent),
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrName, resourceName, names.AttrName),
),
},
},
})
}

func TestAccSSMDocumentDataSource_managed(t *testing.T) {
ctx := acctest.Context(t)
dataSourceName := "data.aws_ssm_document.test"
Expand Down Expand Up @@ -97,13 +136,110 @@ resource "aws_ssm_document" "test" {
DOC
}

# data.aws_ssm_documen.test.document_format can change regardless of the type of aws_ssm_document.test.document_format
# because api can return different representation of content, for example: real content is json, but can return YAML on demand.
# that's why we can give both JSON and YAML on same aws_ssm_document
data "aws_ssm_document" "test" {
name = aws_ssm_document.test.name
document_format = %[2]q
}
`, rName, documentFormat)
}

func testAccDocumentDataSourceConfig_basicAutomation(rName, documentFormat string) string {
return acctest.ConfigCompose(acctest.ConfigLatestAmazonLinux2HVMEBSX8664AMI(),
fmt.Sprintf(`
resource "aws_iam_instance_profile" "ssm_profile" {
name = %[1]q
role = aws_iam_role.ssm_role.name
}

data "aws_partition" "current" {}

resource "aws_iam_role" "ssm_role" {
name = %[1]q
path = "/"

assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.${data.aws_partition.current.dns_suffix}"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

resource "aws_ssm_document" "test" {
name = %[1]q
document_type = "Automation"

content = <<DOC
{
"description": "Systems Manager Automation Demo",
"schemaVersion": "0.3",
"assumeRole": "${aws_iam_role.ssm_role.arn}",
"mainSteps": [
{
"name": "startInstances",
"action": "aws:runInstances",
"timeoutSeconds": 1200,
"maxAttempts": 1,
"onFailure": "Abort",
"inputs": {
"ImageId": "${data.aws_ami.amzn2-ami-minimal-hvm-ebs-x86_64.id}",
"InstanceType": "t2.small",
"MinInstanceCount": 1,
"MaxInstanceCount": 1,
"IamInstanceProfileName": "${aws_iam_instance_profile.ssm_profile.name}"
}
},
{
"name": "stopInstance",
"action": "aws:changeInstanceState",
"maxAttempts": 1,
"onFailure": "Continue",
"inputs": {
"InstanceIds": [
"{{ startInstances.InstanceIds }}"
],
"DesiredState": "stopped"
}
},
{
"name": "terminateInstance",
"action": "aws:changeInstanceState",
"maxAttempts": 1,
"onFailure": "Continue",
"inputs": {
"InstanceIds": [
"{{ startInstances.InstanceIds }}"
],
"DesiredState": "terminated"
}
}
]
}
DOC
}

# data.aws_ssm_documen.test.document_format can change regardless of the type of aws_ssm_document.test.document_format
# because api can return different representation of content, for example: real content is json, but can return YAML on demand.
# that's why we can give both JSON and YAML on same aws_ssm_document
data "aws_ssm_document" "test" {
name = aws_ssm_document.test.name
document_format = %[2]q
}
`, rName, documentFormat))
}

func testAccDocumentDataSourceConfig_managed() string {
return `
data "aws_ssm_document" "test" {
Expand Down
1 change: 1 addition & 0 deletions internal/service/ssm/document_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ func TestAccSSMDocument_automation(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
testAccCheckDocumentExists(ctx, resourceName),
resource.TestCheckResourceAttr(resourceName, "document_type", "Automation"),
acctest.CheckResourceAttrRegionalARN(resourceName, names.AttrARN, "ssm", fmt.Sprintf("automation-definition/%s", rName)),
),
},
{
Expand Down
Loading