Skip to content

Individual Step Function Deploy #581

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
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
33 changes: 33 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/lib/index.js"
},
{
"type": "node",
"name": "Mocha Current File",
"request": "launch",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"args": [
"--timeout",
"999999",
"--colors",
"${file}"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": ["<node_internals>/**"],
"envFile": "${workspaceFolder}/.env"
}
]
}
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"conventionalCommits.scopes": [
"Individual Deploy"
]
}
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Serverless Framework v2.32.0 or later is required.
- [Tags](#tags)
- [Commands](#commands)
- [deploy](#deploy)
- [deploy individual step function](#deploy_individual_step_function)
- [invoke](#invoke)
- [IAM Role](#iam-role)
- [Tips](#tips)
Expand Down Expand Up @@ -1004,10 +1005,10 @@ stepFunctions:
stateMachines:
stateMachineScheduled:
events:
- schedule:
- schedule:
rate: cron(30 12 ? * 1-5 *)
inputTransformer:
inputPathsMap:
inputPathsMap:
time: '$.time'
stage: '$.stageVariables'
inputTemplate: '{"time": <time>, "stage" : <stage> }'
Expand Down Expand Up @@ -1351,7 +1352,17 @@ As a result, `hellostepfunc1` will only have the tag of `score: 42`, and _not_ t
### deploy

Run `sls deploy`, the defined Stepfunctions are deployed.
### deploy_individual_step_function

Run `sls deploy stepf --name <stepfunctionname>`

#### options:

- –name or -n The name of the step function in your service that you want to invoke. Required.
- –stage or -s The stage in your service you want to invoke your step function.
- –region or -r The region in your stage that you want to invoke your step function.

It will update the definition of the state machine. It will ********************************************************************not deploy the logic of lambda.******************************************************************** It will only update the lambda ARN.
### invoke

`$ sls invoke stepf --name <stepfunctionname> --data '{"foo":"bar"}'`
Expand Down
108 changes: 108 additions & 0 deletions lib/deploy/deploy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
'use strict';

const BbPromise = require('bluebird');

module.exports = {
/*
* Will get stack resources and create object and append in obj
* with key as ARN Name and value as ARN Value. The main purpose
* behind this function is get the lambda ARN associated with
* each state of step functions
*/
getLambdaStackResource() {
const resources = [];
const stackName = this.provider.naming.getStackName(this.options.stage);
return this.provider.request('CloudFormation', 'describeStacks', { StackName: stackName }, this.options.stage, this.options.region).then((result) => {
if (result) {
result.Stacks[0].Outputs.forEach((output) => {
let outputValue = output.OutputValue;
outputValue = output.OutputKey.includes('Lambda') ? outputValue.substring(0, outputValue.lastIndexOf(':')) : outputValue;
resources.push({ [output.OutputKey]: outputValue });
});
this.deployStateMachine = {};
this.deployStateMachine.getLambdaStackResource = resources;
}
return BbPromise.resolve();
});
},
/*
* Recursion function to get the states related information and lambda
* associated with it
*/
iterateStates(obj, value) {
const data = {};
data.States = {};
for (const [key, val] of Object.entries(obj)) {
if (key === 'States') {
for (const [stateKey, state] of Object.entries(val)) {
if (state.Type && state.Type === 'Task') {
if (state.Resource && (typeof state.Resource === 'object') && 'Fn::GetAtt' in state.Resource) {
const lambdaQualifiedARN = value.getLambdaQualifiedArn(state.Resource['Fn::GetAtt'][0]);
const lambdaQualifiedARNObject = value.deployStateMachine.getLambdaStackResource.find(
// eslint-disable-next-line array-callback-return, consistent-return
(ob) => {
if (lambdaQualifiedARN in ob) {
return ob;
}
},
);
if (lambdaQualifiedARNObject) {
state.Resource = lambdaQualifiedARNObject[lambdaQualifiedARN];
} else {
throw new Error('Lambda does not exist in state machine');
}
}
data.States[stateKey] = state;
} else {
data.States[stateKey] = state;
this.iterateStates(state, value);
}
}
} else if (typeof obj[key] === 'object') {
this.iterateStates(obj[key], value);
} else if (typeof obj[key] === 'string') {
data[key] = obj[key];
}
}
return data;
},
replaceAllStatesARNInDefinition(definition, value) {
return this.iterateStates(definition, value);
},
/*
* Will create a definition string for state-machine
* that needs to be updated along with
* => It should replace resource string that we fetched from
* last life cycle events step.
* 'Fn:Get'
*/
createDefinitionString() {
const stateMachineObj = this.getStateMachine(this.options.name).definition;
// eslint-disable-next-line max-len
this.deployStateMachine.definitionObject = this.replaceAllStatesARNInDefinition(stateMachineObj, this);
},
/*
* Will get call StateMachine.updateStateMachine
* and will pass ARN and definition string as params.
* 'Fn:Get'
*/
callUpdateFunction() {
// eslint-disable-next-line array-callback-return, consistent-return
const stateMachineArnObject = this.deployStateMachine.getLambdaStackResource.find((obj) => {
if (`${this.options.name}Arn` in obj) {
return obj;
}
});
const definition = JSON.stringify(this.deployStateMachine.definitionObject);
if (stateMachineArnObject) {
const stateMachineArn = stateMachineArnObject[`${this.options.name}Arn`];
// eslint-disable-next-line consistent-return
return this.provider.request('StepFunctions', 'updateStateMachine', { stateMachineArn, definition }, this.options.stage, this.options.region).then((result) => {
if (result) {
return BbPromise.resolve('Step-Function deployed');
}
});
}
throw new Error('Step function does not exist in cloud formation');
},
};
Loading