Skip to content

Commit

Permalink
feat(aws-stepfunctions-tasks): allow specifying waitForTaskToken suff…
Browse files Browse the repository at this point in the history
…ix in resourceArn (aws#2658)

* InvokeFunction props is now optional
* Payload can have multiple nesting levels
* Unit test
* Integration test
* Invoke lambda via SFN integrated service ARN
  • Loading branch information
alberto-galimberti committed Jun 4, 2019
1 parent ccf38b9 commit 9dd544b
Show file tree
Hide file tree
Showing 5 changed files with 507 additions and 17 deletions.
39 changes: 31 additions & 8 deletions packages/@aws-cdk/aws-stepfunctions-tasks/lib/invoke-function.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import iam = require('@aws-cdk/aws-iam');
import lambda = require('@aws-cdk/aws-lambda');
import sfn = require('@aws-cdk/aws-stepfunctions');
import { FieldUtils } from '../../aws-stepfunctions/lib/fields';

/**
* Properties for InvokeFunction
Expand All @@ -9,14 +10,22 @@ export interface InvokeFunctionProps {
/**
* The JSON that you want to provide to your Lambda function as input.
*/
readonly payload?: { [key: string]: string };
readonly payload?: { [key: string]: any };

/**
* Whether to pause the workflow until a task token is returned
*
* @default false
*/
readonly waitForTaskToken?: boolean;

/**
* Whether to invoke lambda via integrated service ARN "arn:aws:states:::lambda:invoke"
* or via Function ARN.
*
* @default false
*/
readonly invokeAsIntegratedService?: boolean;
}

/**
Expand All @@ -28,26 +37,40 @@ export interface InvokeFunctionProps {
export class InvokeFunction implements sfn.IStepFunctionsTask {

private readonly waitForTaskToken: boolean;
private readonly invokeAsIntegratedService: boolean;

constructor(private readonly lambdaFunction: lambda.IFunction, private readonly props: InvokeFunctionProps) {
constructor(private readonly lambdaFunction: lambda.IFunction, private readonly props: InvokeFunctionProps = {}) {
this.waitForTaskToken = props.waitForTaskToken === true;

// Invoke function as integrated service if flag is in props, or if waitForTaskToken property is true
this.invokeAsIntegratedService = props.invokeAsIntegratedService === true || this.waitForTaskToken;

if (this.waitForTaskToken && !FieldUtils.containsTaskToken(props.payload)) {
throw new Error('Task Token is missing in payload');
}
}

public bind(_task: sfn.Task): sfn.StepFunctionsTaskProperties {
const resourceArn = this.invokeAsIntegratedService
? 'arn:aws:states:::lambda:invoke' + this.waitForTaskToken ? '.waitForTaskToken' : ''
: this.lambdaFunction.functionArn;

const includeParameters = this.invokeAsIntegratedService || this.props.payload;

return {
resourceArn: this.waitForTaskToken
? 'arn:aws:states:::lambda:invoke.waitForTaskToken'
: this.lambdaFunction.functionArn,
resourceArn,
policyStatements: [new iam.PolicyStatement()
.addResource(this.lambdaFunction.functionArn)
.addActions("lambda:InvokeFunction")
],
metricPrefixSingular: 'LambdaFunction',
metricPrefixPlural: 'LambdaFunctions',
metricDimensions: { LambdaFunctionArn: this.lambdaFunction.functionArn },
parameters: {
FunctionName: this.lambdaFunction.functionName,
...this.props.payload && { Payload: this.props.payload },
...includeParameters && {
parameters: {
...this.invokeAsIntegratedService && { FunctionName: this.lambdaFunction.functionName },
...this.props.payload && { Payload: this.props.payload },
}
}
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
{
"Resources": {
"HandlerServiceRoleFCDC14AE": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": {
"Fn::Join": [
"",
[
"lambda.",
{
"Ref": "AWS::URLSuffix"
}
]
]
}
}
}
],
"Version": "2012-10-17"
},
"ManagedPolicyArns": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]
]
}
]
}
},
"Handler886CB40B": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "HandlerCodeS3Bucket8DD11ED9"
},
"S3Key": {
"Fn::Join": [
"",
[
{
"Fn::Select": [
0,
{
"Fn::Split": [
"||",
{
"Ref": "HandlerCodeS3VersionKey0BB5191E"
}
]
}
]
},
{
"Fn::Select": [
1,
{
"Fn::Split": [
"||",
{
"Ref": "HandlerCodeS3VersionKey0BB5191E"
}
]
}
]
}
]
]
}
},
"Handler": "index.main",
"Role": {
"Fn::GetAtt": [
"HandlerServiceRoleFCDC14AE",
"Arn"
]
},
"Runtime": "python3.6"
},
"DependsOn": [
"HandlerServiceRoleFCDC14AE"
]
},
"CallbackHandlerServiceRole3689695E": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": {
"Fn::Join": [
"",
[
"lambda.",
{
"Ref": "AWS::URLSuffix"
}
]
]
}
}
}
],
"Version": "2012-10-17"
},
"ManagedPolicyArns": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]
]
}
]
}
},
"CallbackHandler4434C38D": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "CallbackHandlerCodeS3Bucket806D7490"
},
"S3Key": {
"Fn::Join": [
"",
[
{
"Fn::Select": [
0,
{
"Fn::Split": [
"||",
{
"Ref": "CallbackHandlerCodeS3VersionKeyDD40A461"
}
]
}
]
},
{
"Fn::Select": [
1,
{
"Fn::Split": [
"||",
{
"Ref": "CallbackHandlerCodeS3VersionKeyDD40A461"
}
]
}
]
}
]
]
}
},
"Handler": "index.main",
"Role": {
"Fn::GetAtt": [
"CallbackHandlerServiceRole3689695E",
"Arn"
]
},
"Runtime": "python3.6"
},
"DependsOn": [
"CallbackHandlerServiceRole3689695E"
]
},
"StateMachineRoleB840431D": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": {
"Fn::Join": [
"",
[
"states.",
{
"Ref": "AWS::Region"
},
".amazonaws.com"
]
]
}
}
}
],
"Version": "2012-10-17"
}
}
},
"StateMachineRoleDefaultPolicyDF1E6607": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": "lambda:InvokeFunction",
"Effect": "Allow",
"Resource": {
"Fn::GetAtt": [
"Handler886CB40B",
"Arn"
]
}
},
{
"Action": "lambda:InvokeFunction",
"Effect": "Allow",
"Resource": {
"Fn::GetAtt": [
"CallbackHandler4434C38D",
"Arn"
]
}
}
],
"Version": "2012-10-17"
},
"PolicyName": "StateMachineRoleDefaultPolicyDF1E6607",
"Roles": [
{
"Ref": "StateMachineRoleB840431D"
}
]
}
},
"StateMachine2E01A3A5": {
"Type": "AWS::StepFunctions::StateMachine",
"Properties": {
"DefinitionString": {
"Fn::Join": [
"",
[
"{\"StartAt\":\"Invoke Handler\",\"States\":{\"Invoke Handler\":{\"Next\":\"Invoke Handler with task token\",\"Type\":\"Task\",\"Resource\":\"",
{
"Fn::GetAtt": [
"Handler886CB40B",
"Arn"
]
},
"\"},\"Invoke Handler with task token\":{\"Next\":\"Job Complete?\",\"InputPath\":\"$.guid\",\"Type\":\"Task\",\"Resource\":\"",
{
"Fn::GetAtt": [
"CallbackHandler4434C38D",
"Arn"
]
},
"\",\"ResultPath\":\"$.status\"},\"Job Complete?\":{\"Type\":\"Choice\",\"Choices\":[{\"Variable\":\"$.status\",\"StringEquals\":\"FAILED\",\"Next\":\"Job Failed\"},{\"Variable\":\"$.status\",\"StringEquals\":\"SUCCEEDED\",\"Next\":\"Final step\"}]},\"Job Failed\":{\"Type\":\"Fail\",\"Error\":\"DescribeJob returned FAILED\",\"Cause\":\"AWS Batch Job Failed\"},\"Final step\":{\"Type\":\"Pass\",\"End\":true}},\"TimeoutSeconds\":30}"
]
]
},
"RoleArn": {
"Fn::GetAtt": [
"StateMachineRoleB840431D",
"Arn"
]
}
}
}
},
"Parameters": {
"HandlerCodeS3Bucket8DD11ED9": {
"Type": "String",
"Description": "S3 bucket for asset \"aws-stepfunctions-integ/Handler/Code\""
},
"HandlerCodeS3VersionKey0BB5191E": {
"Type": "String",
"Description": "S3 key for asset version \"aws-stepfunctions-integ/Handler/Code\""
},
"HandlerCodeArtifactHashD7814EF8": {
"Type": "String",
"Description": "Artifact hash for asset \"aws-stepfunctions-integ/Handler/Code\""
},
"CallbackHandlerCodeS3Bucket806D7490": {
"Type": "String",
"Description": "S3 bucket for asset \"aws-stepfunctions-integ/CallbackHandler/Code\""
},
"CallbackHandlerCodeS3VersionKeyDD40A461": {
"Type": "String",
"Description": "S3 key for asset version \"aws-stepfunctions-integ/CallbackHandler/Code\""
},
"CallbackHandlerCodeArtifactHash2D279BFF": {
"Type": "String",
"Description": "Artifact hash for asset \"aws-stepfunctions-integ/CallbackHandler/Code\""
}
}
}
Loading

0 comments on commit 9dd544b

Please sign in to comment.