Skip to content
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
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@ $ sls invoke stepf --name <stepfunctionname> --data '{"foo":"bar"}'
- --path or -p The path to a json file with input data to be passed to the invoked step function.

## IAM Role

The IAM roles required to run Statemachine are automatically generated. It is also possible to specify ARN directly.

Here's an example:
Expand All @@ -637,6 +638,28 @@ stepFunctions:
role: arn:aws:iam::xxxxxxxx:role/yourRole
definition:
```

It is also possible to use the [CloudFormation intrinsic functions](https://docs.aws.amazon.com/en_en/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html) to reference resources from elsewhere:

```yml
stepFunctions:
stateMachines:
hello:
role:
Ref: StateMachineRole
definition:
...

resources:
Resources:
StateMachineRole:
Type: AWS::IAM::Role
Properties:
...
```

The short form of the intrinsic functions (i.e. `!Sub`, `!Ref`) is not supported at the moment.

## Tips
### How to specify the stateMachine ARN to environment variables
Here is serverless.yml sample to specify the stateMachine ARN to environment variables.
Expand Down
32 changes: 20 additions & 12 deletions lib/deploy/stepFunctions/compileStateMachines.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
const _ = require('lodash');
const BbPromise = require('bluebird');

function isIntrinsic(obj) {
const isObject = typeof obj === 'object';
return isObject && Object.keys(obj).some((k) => k.startsWith('Fn::') || k.startsWith('Ref'));
}

module.exports = {
isIntrinsic,
compileStateMachines() {
if (this.isStateMachines()) {
this.getAllStateMachines().forEach((stateMachineName) => {
Expand Down Expand Up @@ -37,15 +43,18 @@ module.exports = {
' Please check the README for more info.',
].join('');
throw new this.serverless.classes
.Error(errorMessage);
.Error(errorMessage);
}
} else if (isIntrinsic(stateMachineObj.role)) {
RoleArn = stateMachineObj.role;
} else {
const errorMessage = [
`role property in stateMachine "${stateMachineName}" is not an string`,
`role property in stateMachine "${stateMachineName}" is neither a string`,
' nor a CloudFormation intrinsic function',
' Please check the README for more info.',
].join('');
throw new this.serverless.classes
.Error(errorMessage);
.Error(errorMessage);
}
} else {
RoleArn = {
Expand All @@ -61,15 +70,14 @@ module.exports = {
stateMachineObj);
const stateMachineOutputLogicalId = this
.getStateMachineOutputLogicalId(stateMachineName, stateMachineObj);
const stateMachineTemplate =
{
Type: 'AWS::StepFunctions::StateMachine',
Properties: {
DefinitionString,
RoleArn,
},
DependsOn,
};
const stateMachineTemplate = {
Type: 'AWS::StepFunctions::StateMachine',
Properties: {
DefinitionString,
RoleArn,
},
DependsOn,
};

const newStateMachineObject = {
[stateMachineLogicalId]: stateMachineTemplate,
Expand Down
39 changes: 39 additions & 0 deletions lib/deploy/stepFunctions/compileStateMachines.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,45 @@ describe('#compileStateMachines', () => {
).to.equal('StateMachineBeta2');
});

it('should respect CloudFormation intrinsic functions for role property', () => {
serverless.service.stepFunctions = {
stateMachines: {
myStateMachine1: {
name: 'stateMachineWithIntrinsicRole1',
definition: 'definition1\n',
role: { 'Fn::Attr': ['RoleID', 'Arn'] },
},
myStateMachine2: {
name: 'stateMachineWithIntrinsicRole2',
definition: 'definition1\n',
role: { Ref: 'CloudformationId' },
},
},
};
serverlessStepFunctions.compileStateMachines();
expect(serverlessStepFunctions.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.StateMachineWithIntrinsicRole1.Properties.RoleArn
).to.deep.equal({ 'Fn::Attr': ['RoleID', 'Arn'] });
expect(serverlessStepFunctions.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.StateMachineWithIntrinsicRole2.Properties.RoleArn
).to.deep.equal({ Ref: 'CloudformationId' });
});

it('should throw error if role property is neither string nor intrinsic functions', () => {
serverless.service.stepFunctions = {
stateMachines: {
myStateMachine1: {
name: 'stateMachineWithIntrinsicRole',
definition: 'definition1\n',
role: { XXX: ['RoleID', 'Arn'] },
},
},
};
expect(() => serverlessStepFunctions.compileStateMachines()).to.throw(Error);
});

it('should throw error when definition property is not given', () => {
serverless.service.stepFunctions = {
stateMachines: {
Expand Down