Skip to content

Commit

Permalink
Merge pull request #39229 from kevineor/f-aws_sfn_state_machine-valid…
Browse files Browse the repository at this point in the history
…ate_definition

r/aws_sfn_state_machine: validate step-function definition at plan step
  • Loading branch information
ewbankkit authored Sep 11, 2024
2 parents 9efb574 + 3b34746 commit 00d6762
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .changelog/39229.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_sfn_state_machine: Add plan-time validation of `definition` using the AWS Step Functions [Validation API](https://docs.aws.amazon.com/step-functions/latest/apireference/API_ValidateStateMachineDefinition.html)
```
38 changes: 36 additions & 2 deletions internal/service/sfn/state_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package sfn

import (
"context"
"errors"
"fmt"
"log"
"time"
Expand All @@ -25,6 +26,7 @@ import (
"github.com/hashicorp/terraform-provider-aws/internal/errs"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
"github.com/hashicorp/terraform-provider-aws/internal/sdkv2"
tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
Expand Down Expand Up @@ -192,6 +194,7 @@ func resourceStateMachine() *schema.Resource {
},

CustomizeDiff: customdiff.Sequence(
stateMachineDefinitionValidate,
stateMachineUpdateComputedAttributesOnPublish,
verify.SetTagsDiff,
),
Expand Down Expand Up @@ -535,8 +538,7 @@ func flattenTracingConfiguration(apiObject *awstypes.TracingConfiguration) map[s
}

func stateMachineUpdateComputedAttributesOnPublish(_ context.Context, d *schema.ResourceDiff, meta interface{}) error {
publish := d.Get("publish").(bool)
if publish && stateMachineNeedsConfigUpdate(d) {
if publish := d.Get("publish").(bool); publish && stateMachineNeedsConfigUpdate(d) {
d.SetNewComputed("revision_id")
d.SetNewComputed("state_machine_version_arn")
}
Expand All @@ -558,3 +560,35 @@ func stateMachineNeedsConfigUpdate(d sdkv2.ResourceDiffer) bool {
}
return false
}

func stateMachineDefinitionValidate(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error {
conn := meta.(*conns.AWSClient).SFNClient(ctx)

if d.HasChange("definition") {
definition := d.Get("definition").(string)
if definition == "" {
return nil
}

input := &sfn.ValidateStateMachineDefinitionInput{
Definition: aws.String(definition),
Type: awstypes.StateMachineType(d.Get(names.AttrType).(string)),
}

output, err := conn.ValidateStateMachineDefinition(ctx, input)

if err != nil {
return fmt.Errorf("validating Step Functions State Machine definition: %w", err)
}

if result := output.Result; result != awstypes.ValidateStateMachineDefinitionResultCodeOk {
errs := tfslices.ApplyToAll(output.Diagnostics, func(v awstypes.ValidateStateMachineDefinitionDiagnostic) error {
return fmt.Errorf("%s (%s): %s", v.Severity, aws.ToString(v.Code), aws.ToString(v.Message))
})

return fmt.Errorf("invalid Step Functions State Machine definition: %w", errors.Join(errs...))
}
}

return nil
}
51 changes: 51 additions & 0 deletions internal/service/sfn/state_machine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,24 @@ func TestAccSFNStateMachine_encryptionConfigurationServiceOwnedKey(t *testing.T)
})
}

func TestAccSFNStateMachine_definitionValidation(t *testing.T) {
ctx := acctest.Context(t)
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.SFNServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckStateMachineDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccStateMachineConfig_invalidDefinition(rName),
ExpectError: regexache.MustCompile("invalid Step Functions State Machine definition: .+"),
},
},
})
}

func testAccCheckExists(ctx context.Context, n string, v *sfn.DescribeStateMachineOutput) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
Expand Down Expand Up @@ -1227,3 +1245,36 @@ EOF
}
`, rName, rType))
}

func testAccStateMachineConfig_invalidDefinition(rName string) string {
return acctest.ConfigCompose(testAccStateMachineConfig_base(rName), fmt.Sprintf(`
resource "aws_sfn_state_machine" "test" {
name = %[1]q
role_arn = aws_iam_role.for_sfn.arn
definition = <<EOF
{
"Comment": "A wrongly made stepfunction definition (replaced 'States' by 'Status')",
"StartAt": "HelloWorld",
"Status": {
"HelloWorld": {
"Type": "Task",
"Resource": "${aws_lambda_function.test.arn}",
"Retry": [
{
"ErrorEquals": [
"States.ALL"
],
"IntervalSeconds": 5,
"MaxAttempts": 5,
"BackoffRate": 8
}
],
"End": true
}
}
}
EOF
}
`, rName))
}

0 comments on commit 00d6762

Please sign in to comment.