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

tech-debt: refactor iam data source and resource to use different Read methods #18846

Merged
merged 1 commit into from
Apr 14, 2021
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
113 changes: 111 additions & 2 deletions aws/data_source_aws_iam_policy.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
package aws

import (
"fmt"
"net/url"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

func dataSourceAwsIAMPolicy() *schema.Resource {
Expand Down Expand Up @@ -40,6 +50,105 @@ func dataSourceAwsIAMPolicy() *schema.Resource {
}

func dataSourceAwsIAMPolicyRead(d *schema.ResourceData, meta interface{}) error {
d.SetId(d.Get("arn").(string))
return resourceAwsIamPolicyRead(d, meta)
conn := meta.(*AWSClient).iamconn
ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig

arn := d.Get("arn").(string)

input := &iam.GetPolicyInput{
PolicyArn: aws.String(arn),
}

// Handle IAM eventual consistency
var output *iam.GetPolicyOutput
err := resource.Retry(waiter.PropagationTimeout, func() *resource.RetryError {
var err error
output, err = conn.GetPolicy(input)

if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
return resource.RetryableError(err)
}

if err != nil {
return resource.NonRetryableError(err)
}

return nil
})

if tfresource.TimedOut(err) {
output, err = conn.GetPolicy(input)
}

if err != nil {
return fmt.Errorf("error reading IAM policy %s: %w", arn, err)
}

if output == nil || output.Policy == nil {
return fmt.Errorf("error reading IAM policy %s: empty output", arn)
}

policy := output.Policy

d.SetId(aws.StringValue(policy.Arn))

d.Set("arn", policy.Arn)
d.Set("description", policy.Description)
d.Set("name", policy.PolicyName)
d.Set("path", policy.Path)
d.Set("policy_id", policy.PolicyId)

if err := d.Set("tags", keyvaluetags.IamKeyValueTags(policy.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
return fmt.Errorf("error setting tags: %w", err)
}

// Retrieve policy

policyVersionInput := &iam.GetPolicyVersionInput{
PolicyArn: aws.String(arn),
VersionId: policy.DefaultVersionId,
}

// Handle IAM eventual consistency
var policyVersionOutput *iam.GetPolicyVersionOutput
err = resource.Retry(waiter.PropagationTimeout, func() *resource.RetryError {
var err error
policyVersionOutput, err = conn.GetPolicyVersion(policyVersionInput)

if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
return resource.RetryableError(err)
}

if err != nil {
return resource.NonRetryableError(err)
}

return nil
})

if tfresource.TimedOut(err) {
policyVersionOutput, err = conn.GetPolicyVersion(policyVersionInput)
}

if err != nil {
return fmt.Errorf("error reading IAM Policy (%s) version: %w", arn, err)
}

if policyVersionOutput == nil || policyVersionOutput.PolicyVersion == nil {
return fmt.Errorf("error reading IAM Policy (%s) version: empty output", arn)
}

policyVersion := policyVersionOutput.PolicyVersion

var policyDocument string
if policyVersion != nil {
policyDocument, err = url.QueryUnescape(aws.StringValue(policyVersion.Document))
if err != nil {
return fmt.Errorf("error parsing IAM Policy (%s) document: %w", arn, err)
}
}

d.Set("policy", policyDocument)

return nil
}
72 changes: 40 additions & 32 deletions aws/resource_aws_iam_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import (

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

func resourceAwsIamPolicy() *schema.Resource {
Expand Down Expand Up @@ -99,7 +101,7 @@ func resourceAwsIamPolicyCreate(d *schema.ResourceData, meta interface{}) error

response, err := conn.CreatePolicy(request)
if err != nil {
return fmt.Errorf("Error creating IAM policy %s: %w", name, err)
return fmt.Errorf("error creating IAM policy %s: %w", name, err)
}

d.SetId(aws.StringValue(response.Policy.Arn))
Expand All @@ -111,18 +113,17 @@ func resourceAwsIamPolicyRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).iamconn
ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig

getPolicyRequest := &iam.GetPolicyInput{
input := &iam.GetPolicyInput{
PolicyArn: aws.String(d.Id()),
}
log.Printf("[DEBUG] Getting IAM Policy: %s", getPolicyRequest)

// Handle IAM eventual consistency
var getPolicyResponse *iam.GetPolicyOutput
err := resource.Retry(waiter.PropagationTimeout, func() *resource.RetryError {
var err error
getPolicyResponse, err = conn.GetPolicy(getPolicyRequest)
getPolicyResponse, err = conn.GetPolicy(input)

if d.IsNewResource() && isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
if d.IsNewResource() && tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
return resource.RetryableError(err)
}

Expand All @@ -132,17 +133,19 @@ func resourceAwsIamPolicyRead(d *schema.ResourceData, meta interface{}) error {

return nil
})
if isResourceTimeoutError(err) {
getPolicyResponse, err = conn.GetPolicy(getPolicyRequest)

if tfresource.TimedOut(err) {
getPolicyResponse, err = conn.GetPolicy(input)
}
if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {

if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
log.Printf("[WARN] IAM Policy (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("Error reading IAM policy %s: %w", d.Id(), err)
return fmt.Errorf("error reading IAM policy %s: %w", d.Id(), err)
}

if getPolicyResponse == nil || getPolicyResponse.Policy == nil {
Expand All @@ -151,32 +154,32 @@ func resourceAwsIamPolicyRead(d *schema.ResourceData, meta interface{}) error {
return nil
}

policyRes := getPolicyResponse.Policy
d.Set("arn", policyRes.Arn)
d.Set("description", policyRes.Description)
d.Set("name", policyRes.PolicyName)
d.Set("path", policyRes.Path)
d.Set("policy_id", policyRes.PolicyId)
policy := getPolicyResponse.Policy

d.Set("arn", policy.Arn)
d.Set("description", policy.Description)
d.Set("name", policy.PolicyName)
d.Set("path", policy.Path)
d.Set("policy_id", policy.PolicyId)

if err := d.Set("tags", keyvaluetags.IamKeyValueTags(policyRes.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
if err := d.Set("tags", keyvaluetags.IamKeyValueTags(policy.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
return fmt.Errorf("error setting tags: %w", err)
}

// Retrieve policy

getPolicyVersionRequest := &iam.GetPolicyVersionInput{
PolicyArn: aws.String(d.Id()),
VersionId: policyRes.DefaultVersionId,
VersionId: policy.DefaultVersionId,
}
log.Printf("[DEBUG] Getting IAM Policy Version: %s", getPolicyVersionRequest)

// Handle IAM eventual consistency
var getPolicyVersionResponse *iam.GetPolicyVersionOutput
err = resource.Retry(waiter.PropagationTimeout, func() *resource.RetryError {
var err error
getPolicyVersionResponse, err = conn.GetPolicyVersion(getPolicyVersionRequest)

if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
return resource.RetryableError(err)
}

Expand All @@ -186,29 +189,31 @@ func resourceAwsIamPolicyRead(d *schema.ResourceData, meta interface{}) error {

return nil
})
if isResourceTimeoutError(err) {

if tfresource.TimedOut(err) {
getPolicyVersionResponse, err = conn.GetPolicyVersion(getPolicyVersionRequest)
}
if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {

if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
log.Printf("[WARN] IAM Policy (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("Error reading IAM policy version %s: %w", d.Id(), err)
return fmt.Errorf("error reading IAM policy version %s: %w", d.Id(), err)
}

policy := ""
var policyDocument string
if getPolicyVersionResponse != nil && getPolicyVersionResponse.PolicyVersion != nil {
var err error
policy, err = url.QueryUnescape(aws.StringValue(getPolicyVersionResponse.PolicyVersion.Document))
policyDocument, err = url.QueryUnescape(aws.StringValue(getPolicyVersionResponse.PolicyVersion.Document))
if err != nil {
return fmt.Errorf("error parsing policy: %w", err)
return fmt.Errorf("error parsing IAM policy (%s) document: %w", d.Id(), err)
}
}

d.Set("policy", policy)
d.Set("policy", policyDocument)

return nil
}
Expand All @@ -229,7 +234,7 @@ func resourceAwsIamPolicyUpdate(d *schema.ResourceData, meta interface{}) error
}

if _, err := conn.CreatePolicyVersion(request); err != nil {
return fmt.Errorf("Error updating IAM policy %s: %w", d.Id(), err)
return fmt.Errorf("error updating IAM policy %s: %w", d.Id(), err)
}
}

Expand All @@ -255,11 +260,14 @@ func resourceAwsIamPolicyDelete(d *schema.ResourceData, meta interface{}) error
PolicyArn: aws.String(d.Id()),
}

if _, err := conn.DeletePolicy(request); err != nil {
if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
return nil
}
return fmt.Errorf("Error deleting IAM policy %s: %w", d.Id(), err)
_, err := conn.DeletePolicy(request)

if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
return nil
}

if err != nil {
return fmt.Errorf("error deleting IAM policy %s: %w", d.Id(), err)
}

return nil
Expand Down