diff --git a/.changelog/32844.txt b/.changelog/32844.txt new file mode 100644 index 00000000000..609c733a7bd --- /dev/null +++ b/.changelog/32844.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_sfn_state_machine: Fix `Provider produced inconsistent final plan` errors for `publish` +``` \ No newline at end of file diff --git a/internal/service/sfn/generate.go b/internal/service/sfn/generate.go index 9265e0a2428..5b3d8d3fe08 100644 --- a/internal/service/sfn/generate.go +++ b/internal/service/sfn/generate.go @@ -1,6 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 +//go:generate go run ../../generate/listpages/main.go -ListOps=ListStateMachineVersions //go:generate go run ../../generate/tags/main.go -ListTags -ServiceTagsSlice -UpdateTags //go:generate go run ../../generate/servicepackage/main.go // ONLY generate directives and package declaration! Do not add anything else to this file. diff --git a/internal/service/sfn/list_pages_gen.go b/internal/service/sfn/list_pages_gen.go new file mode 100644 index 00000000000..cd37e2773e3 --- /dev/null +++ b/internal/service/sfn/list_pages_gen.go @@ -0,0 +1,28 @@ +// Code generated by "internal/generate/listpages/main.go -ListOps=ListStateMachineVersions"; DO NOT EDIT. + +package sfn + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/sfn" + "github.com/aws/aws-sdk-go/service/sfn/sfniface" +) + +func listStateMachineVersionsPages(ctx context.Context, conn sfniface.SFNAPI, input *sfn.ListStateMachineVersionsInput, fn func(*sfn.ListStateMachineVersionsOutput, bool) bool) error { + for { + output, err := conn.ListStateMachineVersionsWithContext(ctx, input) + if err != nil { + return err + } + + lastPage := aws.StringValue(output.NextToken) == "" + if !fn(output, lastPage) || lastPage { + break + } + + input.NextToken = output.NextToken + } + return nil +} diff --git a/internal/service/sfn/state_machine.go b/internal/service/sfn/state_machine.go index 55349230ca8..e215469d4ec 100644 --- a/internal/service/sfn/state_machine.go +++ b/internal/service/sfn/state_machine.go @@ -200,7 +200,6 @@ func resourceStateMachineCreate(ctx context.Context, d *schema.ResourceData, met arn := aws.StringValue(outputRaw.(*sfn.CreateStateMachineOutput).StateMachineArn) d.SetId(arn) - d.Set("state_machine_version_arn", outputRaw.(*sfn.CreateStateMachineOutput).StateMachineVersionArn) return resourceStateMachineRead(ctx, d, meta) } @@ -228,7 +227,6 @@ func resourceStateMachineRead(ctx context.Context, d *schema.ResourceData, meta } d.Set("definition", output.Definition) d.Set("description", output.Description) - if output.LoggingConfiguration != nil { if err := d.Set("logging_configuration", []interface{}{flattenLoggingConfiguration(output.LoggingConfiguration)}); err != nil { return diag.Errorf("setting logging_configuration: %s", err) @@ -238,6 +236,7 @@ func resourceStateMachineRead(ctx context.Context, d *schema.ResourceData, meta } d.Set("name", output.Name) d.Set("name_prefix", create.NamePrefixFromName(aws.StringValue(output.Name))) + d.Set("publish", d.Get("publish").(bool)) d.Set("role_arn", output.RoleArn) d.Set("revision_id", output.RevisionId) d.Set("status", output.Status) @@ -250,6 +249,23 @@ func resourceStateMachineRead(ctx context.Context, d *schema.ResourceData, meta } d.Set("type", output.Type) + input := &sfn.ListStateMachineVersionsInput{ + StateMachineArn: aws.String(d.Id()), + } + listVersionsOutput, err := conn.ListStateMachineVersionsWithContext(ctx, input) + + if err != nil { + return diag.Errorf("listing Step Functions State Machine (%s) Versions: %s", d.Id(), err) + } + + // The results are sorted in descending order of the version creation time. + // https://docs.aws.amazon.com/step-functions/latest/apireference/API_ListStateMachineVersions.html + if len(listVersionsOutput.StateMachineVersions) > 0 { + d.Set("state_machine_version_arn", listVersionsOutput.StateMachineVersions[0].StateMachineVersionArn) + } else { + d.Set("state_machine_version_arn", nil) + } + return nil } @@ -281,7 +297,7 @@ func resourceStateMachineUpdate(ctx context.Context, d *schema.ResourceData, met } } - out, err := conn.UpdateStateMachineWithContext(ctx, input) + _, err := conn.UpdateStateMachineWithContext(ctx, input) if err != nil { return diag.Errorf("updating Step Functions State Machine (%s): %s", d.Id(), err) @@ -310,8 +326,6 @@ func resourceStateMachineUpdate(ctx context.Context, d *schema.ResourceData, met if err != nil { return diag.Errorf("waiting for Step Functions State Machine (%s) update: %s", d.Id(), err) } - - d.Set("state_machine_version_arn", out.StateMachineVersionArn) } return resourceStateMachineRead(ctx, d, meta) diff --git a/internal/service/sfn/state_machine_test.go b/internal/service/sfn/state_machine_test.go index 1355db4632e..56221850902 100644 --- a/internal/service/sfn/state_machine_test.go +++ b/internal/service/sfn/state_machine_test.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "regexp" + "strings" "testing" "github.com/aws/aws-sdk-go/service/sfn" @@ -35,7 +36,7 @@ func TestAccSFNStateMachine_createUpdate(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccStateMachineConfig_basic(rName, 5), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckExists(ctx, resourceName, &sm), acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "states", fmt.Sprintf("stateMachine:%s", rName)), resource.TestCheckResourceAttr(resourceName, "status", sfn.StateMachineStatusActive), @@ -50,6 +51,8 @@ func TestAccSFNStateMachine_createUpdate(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "logging_configuration.0.level", "OFF"), resource.TestCheckResourceAttr(resourceName, "logging_configuration.0.log_destination", ""), resource.TestCheckResourceAttr(resourceName, "publish", "false"), + resource.TestCheckResourceAttr(resourceName, "revision_id", ""), + resource.TestCheckResourceAttr(resourceName, "state_machine_version_arn", ""), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestCheckResourceAttr(resourceName, "tracing_configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "tracing_configuration.0.enabled", "false"), @@ -57,14 +60,13 @@ func TestAccSFNStateMachine_createUpdate(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"publish", "state_machine_version_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, { Config: testAccStateMachineConfig_basic(rName, 10), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckExists(ctx, resourceName, &sm), acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "states", fmt.Sprintf("stateMachine:%s", rName)), resource.TestCheckResourceAttr(resourceName, "status", sfn.StateMachineStatusActive), @@ -77,6 +79,7 @@ func TestAccSFNStateMachine_createUpdate(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "logging_configuration.0.level", "OFF"), resource.TestCheckResourceAttr(resourceName, "logging_configuration.0.log_destination", ""), resource.TestCheckResourceAttr(resourceName, "publish", "false"), + resource.TestCheckResourceAttr(resourceName, "state_machine_version_arn", ""), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestCheckResourceAttr(resourceName, "tracing_configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "tracing_configuration.0.enabled", "false"), @@ -101,26 +104,41 @@ func TestAccSFNStateMachine_expressUpdate(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccStateMachineConfig_typed(rName, "EXPRESS", 5), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckExists(ctx, resourceName, &sm), resource.TestCheckResourceAttr(resourceName, "status", sfn.StateMachineStatusActive), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttrSet(resourceName, "creation_date"), resource.TestCheckResourceAttrSet(resourceName, "definition"), resource.TestMatchResourceAttr(resourceName, "definition", regexp.MustCompile(`.*\"MaxAttempts\": 5.*`)), + resource.TestCheckResourceAttr(resourceName, "revision_id", ""), resource.TestCheckResourceAttrSet(resourceName, "role_arn"), + resource.TestCheckResourceAttrWith(resourceName, "state_machine_version_arn", func(value string) error { + if !strings.HasSuffix(value, ":1") { + return fmt.Errorf("incorrect version number: %s", value) + } + + return nil + }), resource.TestCheckResourceAttr(resourceName, "type", "EXPRESS"), ), }, { Config: testAccStateMachineConfig_typed(rName, "EXPRESS", 10), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckExists(ctx, resourceName, &sm), resource.TestCheckResourceAttr(resourceName, "status", sfn.StateMachineStatusActive), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttrSet(resourceName, "creation_date"), resource.TestMatchResourceAttr(resourceName, "definition", regexp.MustCompile(`.*\"MaxAttempts\": 10.*`)), resource.TestCheckResourceAttrSet(resourceName, "role_arn"), + resource.TestCheckResourceAttrWith(resourceName, "state_machine_version_arn", func(value string) error { + if !strings.HasSuffix(value, ":2") { + return fmt.Errorf("incorrect version number: %s", value) + } + + return nil + }), resource.TestCheckResourceAttr(resourceName, "type", "EXPRESS"), ), }, @@ -142,7 +160,7 @@ func TestAccSFNStateMachine_standardUpdate(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccStateMachineConfig_typed(rName, "STANDARD", 5), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckExists(ctx, resourceName, &sm), resource.TestCheckResourceAttr(resourceName, "status", sfn.StateMachineStatusActive), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -150,26 +168,35 @@ func TestAccSFNStateMachine_standardUpdate(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "definition"), resource.TestMatchResourceAttr(resourceName, "definition", regexp.MustCompile(`.*\"MaxAttempts\": 5.*`)), resource.TestCheckResourceAttr(resourceName, "publish", "true"), - //resource.TestCheckResourceAttrSet(resourceName, "version_description"), - //resource.TestCheckResourceAttrSet(resourceName, "revision_id"), - //resource.TestCheckResourceAttrSet(resourceName, "state_machine_version_arn"), + resource.TestCheckResourceAttr(resourceName, "revision_id", ""), resource.TestCheckResourceAttrSet(resourceName, "role_arn"), + resource.TestCheckResourceAttrWith(resourceName, "state_machine_version_arn", func(value string) error { + if !strings.HasSuffix(value, ":1") { + return fmt.Errorf("incorrect version number: %s", value) + } + + return nil + }), resource.TestCheckResourceAttr(resourceName, "type", "STANDARD"), ), }, { Config: testAccStateMachineConfig_typed(rName, "STANDARD", 10), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckExists(ctx, resourceName, &sm), resource.TestCheckResourceAttr(resourceName, "status", sfn.StateMachineStatusActive), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttrSet(resourceName, "creation_date"), resource.TestMatchResourceAttr(resourceName, "definition", regexp.MustCompile(`.*\"MaxAttempts\": 10.*`)), resource.TestCheckResourceAttr(resourceName, "publish", "true"), - //resource.TestCheckResourceAttrSet(resourceName, "version_description"), - //resource.TestCheckResourceAttrSet(resourceName, "revision_id"), - //resource.TestCheckResourceAttrSet(resourceName, "state_machine_version_arn"), resource.TestCheckResourceAttrSet(resourceName, "role_arn"), + resource.TestCheckResourceAttrWith(resourceName, "state_machine_version_arn", func(value string) error { + if !strings.HasSuffix(value, ":2") { + return fmt.Errorf("incorrect version number: %s", value) + } + + return nil + }), resource.TestCheckResourceAttr(resourceName, "type", "STANDARD"), ), }, @@ -198,10 +225,9 @@ func TestAccSFNStateMachine_nameGenerated(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"publish", "state_machine_version_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -228,10 +254,9 @@ func TestAccSFNStateMachine_namePrefix(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"publish", "state_machine_version_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -254,13 +279,14 @@ func TestAccSFNStateMachine_publish(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckExists(ctx, resourceName, &sm), resource.TestCheckResourceAttr(resourceName, "publish", "true"), + resource.TestCheckResourceAttrSet(resourceName, "state_machine_version_arn"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"publish", "state_machine_version_arn"}, + ImportStateVerifyIgnore: []string{"publish"}, }, }, }) @@ -287,10 +313,9 @@ func TestAccSFNStateMachine_tags(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"publish", "state_machine_version_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, { Config: testAccStateMachineConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), @@ -334,10 +359,9 @@ func TestAccSFNStateMachine_tracing(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"publish", "state_machine_version_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, { Config: testAccStateMachineConfig_tracingEnable(rName), diff --git a/internal/service/sfn/state_machine_versions_data_source.go b/internal/service/sfn/state_machine_versions_data_source.go index 6c62e0e81dd..babbb6b089a 100644 --- a/internal/service/sfn/state_machine_versions_data_source.go +++ b/internal/service/sfn/state_machine_versions_data_source.go @@ -11,6 +11,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/verify" ) // @SDKDataSource("aws_sfn_state_machine_versions") @@ -19,52 +21,50 @@ func DataSourceStateMachineVersions() *schema.Resource { ReadWithoutTimeout: dataSourceStateMachineVersionsRead, Schema: map[string]*schema.Schema{ + "statemachine_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, "statemachine_versions": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "statemachine_arn": { - Type: schema.TypeString, - Required: true, - }, }, } } -const ( - DSNameStateMachineVersions = "StateMachine versions Data Source" -) - func dataSourceStateMachineVersionsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SFNConn(ctx) - in := &sfn.ListStateMachineVersionsInput{ - StateMachineArn: aws.String(d.Get("statemachine_arn").(string)), + smARN := d.Get("statemachine_arn").(string) + input := &sfn.ListStateMachineVersionsInput{ + StateMachineArn: aws.String(smARN), } + var smvARNs []string - var statemachine_version_arns []string - - for { - output, err := conn.ListStateMachineVersionsWithContext(ctx, in) - if err != nil { - return diag.Errorf("listing Step Functions State Machine versions: %s", err) - } - for _, in := range output.StateMachineVersions { - statemachine_version_arns = append(statemachine_version_arns, *in.StateMachineVersionArn) + err := listStateMachineVersionsPages(ctx, conn, input, func(page *sfn.ListStateMachineVersionsOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - if output.NextToken == nil { - break + + for _, v := range page.StateMachineVersions { + if v != nil { + smvARNs = append(smvARNs, aws.StringValue(v.StateMachineVersionArn)) + } } - in.NextToken = output.NextToken - } - if n := len(statemachine_version_arns); n == 0 { - return diag.Errorf("no Step Functions State Machine versions matched") + return !lastPage + }) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "listing Step Functions State Machine (%s) Versions: %s", smARN, err) } - d.SetId(d.Get("statemachine_arn").(string)) - d.Set("statemachine_versions", statemachine_version_arns) + d.SetId(smARN) + d.Set("statemachine_versions", smvARNs) - return nil + return diags } diff --git a/internal/service/sfn/state_machine_versions_data_source_test.go b/internal/service/sfn/state_machine_versions_data_source_test.go index 848b118ea6b..9a97da68549 100644 --- a/internal/service/sfn/state_machine_versions_data_source_test.go +++ b/internal/service/sfn/state_machine_versions_data_source_test.go @@ -38,8 +38,6 @@ func testAccStateMachineVersionsDataSourceConfig_basic(rName string) string { return acctest.ConfigCompose(testAccStateMachineAliasConfig_base(rName, 5), ` data "aws_sfn_state_machine_versions" "test" { statemachine_arn = aws_sfn_state_machine.test.arn - - depends_on = [aws_sfn_state_machine.test] } `) }