1

Dynamodb is defined using aws CDK and deployed to localstack:

new Table(this, 'idlist-staging', {
      tableName: 'idlist-staging',
      readCapacity: 1,
      writeCapacity: 1,
      partitionKey: { name: 'external_id', type: AttributeType.STRING },
      pointInTimeRecovery: true,
      removalPolicy: RemovalPolicy.DESTROY,
      billingMode: BillingMode.PROVISIONED
    });

State Machine on local stack has entries like:

    "Deletion": {
      "Type": "Task",
      "Resource": "arn:aws:states:::dynamodb:deleteItem",
      "Parameters": {
        "TableName": "idlist-staging",
        "Key": {
          "external_id": {
            "S.$": "$.exid"
          }
        }
      },
      "Next": "Confirmation",
      "ResultPath": null
    },

update as requested: cdk code that constructs the state machine:

    const machine = new CfnStateMachine(this, smId, {
      stateMachineName: 'sync-machine-staging',
      // role already has Effect.Allow on dynamodb put/get/delet + db arn
      roleArn: role.roleArn,
      definitionString: JSON.stringify(
        stateMachineDefinition,
      ),
    });

What is the correct way to reference the dynamodb table? Do we still use arn:aws:states:::dynamodb:deleteItem as the resource and idlist-staging as the table because cdk will not deploy as soon as the the state machine is updated to reference dynamodb. CDK Deploys when the reference is removed from the step function.

Any help appreciated for how to either fix this or debug this.

UPDATE - in the end the above works, it was stateMachineDefinition string which was not well-formed.

yen
  • 1,769
  • 2
  • 15
  • 43

1 Answers1

2

Edit: State Machine defined with the CfnStateMachine construct

CfnStateMachine has a definitionSubstitutions prop to substitute values in:

A map (string to string) that specifies the mappings for placeholder variables in the state machine definition. This enables the customer to inject values obtained at runtime, for example from intrinsic functions, in the state machine definition. Variables can be template parameter names, resource logical IDs, resource attributes, or a variable in a key-value map.

There is a Cfn example here. The substitution targets takes the form "${tableName}"

State Machine defined with the StateMachine construct

CDK does the heavy lifting to resolve resource names between dependent constructs. Our job is to pass the tableName and tableArn to the state machine instance as variables.

Here's a working example of a stack with Table and StateMachine constructs that deploys and executes as expected in AWS (LocalStack not used).

export class MyAwesomeStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    const table = new dynamo.Table(this, 'idlist-staging', {
      tableName: 'idlist-staging',
      partitionKey: { name: 'external_id', type: dynamo.AttributeType.STRING },
      billingMode: dynamo.BillingMode.PAY_PER_REQUEST,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    const deleteItemTask = new tasks.CallAwsService(this, 'delete-table-task', {
      service: 'dynamodb',
      action: 'deleteItem',
      comment: 'call the dynamo delete item API to delete the item passed as $.exid',
      parameters: {
        TableName: table.tableName,  // <- pass the table name
        Key: { external_id: { "S.$": '$.exid' } },
      },
      iamResources: [table.tableArn], // <- pass the table arn for permissions
      outputPath: '$.deleteItem'
    });

    new sfn.StateMachine(this, 'my-step-function', {
      definition: deleteItemTask.next(new sfn.Succeed(scope, 'Done!')),
    });
  }
}

CDK generates CloudFormation output with deploy-time references. For instance, the state machine's IAM permissions statement in the generated Cfn template uses the deploy-time Fn::GetAtt:

"Statement": [
  {
    "Action": "dynamodb:deleteItem",
    "Effect": "Allow",
    "Resource": { "Fn::GetAtt": [ "idliststaging30186BA1", "Arn"]}
  }
]

In our case, the CDK handles dependencies automagically. Sometimes, however, CDK has trouble, resulting in a deploy-time error. No problem! If needed, we can explicitly set dependencies like this: myStateMachine.node.addDependency(table).

fedonev
  • 20,327
  • 2
  • 25
  • 34
  • Hey - I'm trying to replicate portions of this. our state machine is being supplied by a `definitionString` per the example in my question, it is not being constructed the way you've shown so it's taking me a bit of time... – yen Dec 02 '21 at 14:00
  • Right. I updated the answer for this scenario. – fedonev Dec 02 '21 at 14:50
  • Hey - I don't know what to do now because the code i had in my SO question ended up working, so technically it's not a valid Q anymore but You have put a lot of useful info here that I did not know that is useful for others. I'm going to upvote ur answer and hope others do as well? – yen Dec 03 '21 at 14:29