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

r/sfn_state_machine - iam role eventual consistency + wait for delete + add arn attribute #12005

Merged
merged 10 commits into from
Jul 1, 2020
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
28 changes: 28 additions & 0 deletions aws/internal/service/sfn/waiter/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package waiter

import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/sfn"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

// StateMachineStatus fetches the Operation and its Status
func StateMachineStatus(conn *sfn.SFN, stateMachineArn string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
input := &sfn.DescribeStateMachineInput{
StateMachineArn: aws.String(stateMachineArn),
}

output, err := conn.DescribeStateMachine(input)

if err != nil {
return nil, "", err
}

if output == nil {
return nil, "", nil
}

return output, aws.StringValue(output.Status), nil
DrFaust92 marked this conversation as resolved.
Show resolved Hide resolved
}
}
31 changes: 31 additions & 0 deletions aws/internal/service/sfn/waiter/waiter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package waiter

import (
"time"

"github.com/aws/aws-sdk-go/service/sfn"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

const (
// Maximum amount of time to wait for an Operation to return Success
StateMachineDeleteTimeout = 5 * time.Minute
)

// StateMachineDeleted waits for an Operation to return Success
func StateMachineDeleted(conn *sfn.SFN, stateMachineArn string) (*sfn.DescribeStateMachineOutput, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{sfn.StateMachineStatusActive, sfn.StateMachineStatusDeleting},
Target: []string{},
Refresh: StateMachineStatus(conn, stateMachineArn),
Timeout: StateMachineDeleteTimeout,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*sfn.DescribeStateMachineOutput); ok {
return output, err
}

return nil, err
}
61 changes: 39 additions & 22 deletions aws/resource_aws_sfn_state_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import (
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/sfn"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sfn/waiter"
)

func resourceAwsSfnStateMachine() *schema.Resource {
Expand Down Expand Up @@ -54,6 +54,10 @@ func resourceAwsSfnStateMachine() *schema.Resource {
Computed: true,
},
"tags": tagsSchema(),
"arn": {
Type: schema.TypeString,
Computed: true,
},
},
}
}
Expand All @@ -69,17 +73,21 @@ func resourceAwsSfnStateMachineCreate(d *schema.ResourceData, meta interface{})
Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().SfnTags(),
}

var activity *sfn.CreateStateMachineOutput
var stateMachine *sfn.CreateStateMachineOutput

err := resource.Retry(5*time.Minute, func() *resource.RetryError {
var err error
activity, err = conn.CreateStateMachine(params)
stateMachine, err = conn.CreateStateMachine(params)

if err != nil {
// Note: the instance may be in a deleting mode, hence the retry
// when creating the step function. This can happen when we are
// updating the resource (since there is no update API call).
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "StateMachineDeleting" {
if isAWSErr(err, sfn.ErrCodeStateMachineDeleting, "") {
return resource.RetryableError(err)
}
//This is done to deal with IAM eventual consistency
if isAWSErr(err, "AccessDeniedException", "") {
return resource.RetryableError(err)
}

Expand All @@ -89,14 +97,14 @@ func resourceAwsSfnStateMachineCreate(d *schema.ResourceData, meta interface{})
return nil
})
if isResourceTimeoutError(err) {
activity, err = conn.CreateStateMachine(params)
stateMachine, err = conn.CreateStateMachine(params)
}

if err != nil {
return fmt.Errorf("Error creating Step Function State Machine: %s", err)
}

d.SetId(*activity.StateMachineArn)
d.SetId(aws.StringValue(stateMachine.StateMachineArn))

return resourceAwsSfnStateMachineRead(d, meta)
}
Expand All @@ -112,15 +120,15 @@ func resourceAwsSfnStateMachineRead(d *schema.ResourceData, meta interface{}) er
})
if err != nil {

if awserr, ok := err.(awserr.Error); ok {
if awserr.Code() == "NotFoundException" || awserr.Code() == "StateMachineDoesNotExist" {
d.SetId("")
return nil
}
if isAWSErr(err, sfn.ErrCodeStateMachineDoesNotExist, "") {
log.Printf("[WARN] SFN State Machine (%s) not found, removing from state", d.Id())
d.SetId("")
DrFaust92 marked this conversation as resolved.
Show resolved Hide resolved
return nil
}
return err
}

d.Set("arn", sm.StateMachineArn)
d.Set("definition", sm.Definition)
d.Set("name", sm.Name)
d.Set("role_arn", sm.RoleArn)
Expand All @@ -146,21 +154,23 @@ func resourceAwsSfnStateMachineRead(d *schema.ResourceData, meta interface{}) er
func resourceAwsSfnStateMachineUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).sfnconn

params := &sfn.UpdateStateMachineInput{
StateMachineArn: aws.String(d.Id()),
Definition: aws.String(d.Get("definition").(string)),
RoleArn: aws.String(d.Get("role_arn").(string)),
}
if d.HasChanges("definition", "role_arn") {
params := &sfn.UpdateStateMachineInput{
StateMachineArn: aws.String(d.Id()),
Definition: aws.String(d.Get("definition").(string)),
RoleArn: aws.String(d.Get("role_arn").(string)),
}

_, err := conn.UpdateStateMachine(params)
_, err := conn.UpdateStateMachine(params)

log.Printf("[DEBUG] Updating Step Function State Machine: %#v", params)
log.Printf("[DEBUG] Updating Step Function State Machine: %#v", params)

if err != nil {
if isAWSErr(err, "StateMachineDoesNotExist", "State Machine Does Not Exist") {
return fmt.Errorf("Error updating Step Function State Machine: %s", err)
if err != nil {
if isAWSErr(err, sfn.ErrCodeStateMachineDoesNotExist, "State Machine Does Not Exist") {
return fmt.Errorf("Error updating Step Function State Machine: %s", err)
}
return err
}
return err
}

if d.HasChange("tags") {
Expand All @@ -187,5 +197,12 @@ func resourceAwsSfnStateMachineDelete(d *schema.ResourceData, meta interface{})
return fmt.Errorf("Error deleting SFN state machine: %s", err)
}

if _, err := waiter.StateMachineDeleted(conn, d.Id()); err != nil {
if isAWSErr(err, sfn.ErrCodeStateMachineDoesNotExist, "") {
return nil
}
return fmt.Errorf("error waiting for SFN State Machine (%s) deletion: %w", d.Id(), err)
}

return nil
}
Loading