Skip to content

Commit d91e423

Browse files
committed
update project structure
1 parent b58379a commit d91e423

File tree

4 files changed

+272
-295
lines changed

4 files changed

+272
-295
lines changed

index.js

Lines changed: 272 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,47 @@
11
'use strict';
22
const BbPromise = require('bluebird');
3-
const deploy = require('./lib/deploy');
4-
const remove = require('./lib/remove');
5-
const invoke = require('./lib/invoke');
3+
const path = require('path');
4+
const _ = require('lodash');
65

76
class ServerlessStepFunctions {
87
constructor(serverless, options) {
98
this.serverless = serverless;
109
this.options = options;
1110
this.provider = this.serverless.getProvider('aws');
11+
this.awsStateLanguage = {};
12+
this.functionArns = {};
13+
const region = this.options.region || 'us-east-1';
1214

13-
Object.assign(
14-
this,
15-
deploy,
16-
remove,
17-
invoke
18-
);
15+
this.iamRoleName = `serverless-step-functions-executerole-${region}`;
16+
this.iamPolicyName = `serverless-step-functions-executepolicy-${region}`;
17+
18+
this.iamPolicyStatement = `{
19+
"Version": "2012-10-17",
20+
"Statement": [
21+
{
22+
"Effect": "Allow",
23+
"Action": [
24+
"lambda:InvokeFunction"
25+
],
26+
"Resource": "*"
27+
}
28+
]
29+
}
30+
`;
31+
32+
this.assumeRolePolicyDocument = `{
33+
"Version": "2012-10-17",
34+
"Statement": [
35+
{
36+
"Effect": "Allow",
37+
"Principal": {
38+
"Service": "states.${region}.amazonaws.com"
39+
},
40+
"Action": "sts:AssumeRole"
41+
}
42+
]
43+
}
44+
`;
1945

2046
this.commands = {
2147
deploy: {
@@ -84,5 +110,242 @@ class ServerlessStepFunctions {
84110
.then(this.invoke),
85111
};
86112
}
113+
114+
deploy() {
115+
this.serverless.cli.log(`Start to deploy ${this.options.state} step function...`);
116+
BbPromise.bind(this)
117+
.then(this.yamlParse)
118+
.then(this.getStateMachineArn)
119+
.then(this.getFunctionArns)
120+
.then(this.compile)
121+
.then(this.getIamRole)
122+
.then(this.deleteStateMachine)
123+
.then(this.createStateMachine);
124+
125+
return BbPromise.resolve();
126+
}
127+
128+
remove() {
129+
BbPromise.bind(this)
130+
.then(this.getStateMachineArn)
131+
.then(this.deleteStateMachine)
132+
.then(() => {
133+
this.serverless.cli.log(`Remove ${this.options.state}`);
134+
return BbPromise.resolve();
135+
});
136+
137+
return BbPromise.resolve();
138+
}
139+
140+
invoke() {
141+
BbPromise.bind(this)
142+
.then(this.getStateMachineArn)
143+
.then(this.startExecution)
144+
.then(this.describeExecution);
145+
146+
return BbPromise.resolve();
147+
}
148+
149+
getIamRole() {
150+
return this.provider.request('IAM',
151+
'getRole',
152+
{
153+
RoleName: this.iamRoleName,
154+
},
155+
this.options.stage,
156+
this.options.region)
157+
.then((result) => {
158+
this.iamRoleArn = result.Role.Arn;
159+
return BbPromise.resolve();
160+
}).catch((error) => {
161+
if (error.statusCode === 404) {
162+
return this.createIamRole();
163+
}
164+
return BbPromise.reject();
165+
});
166+
}
167+
168+
getFunctionArns() {
169+
return this.provider.request('STS',
170+
'getCallerIdentity',
171+
{},
172+
this.options.stage,
173+
this.options.region)
174+
.then((result) => {
175+
const region = this.options.region || 'us-east-1';
176+
_.forEach(this.serverless.service.functions, (value, key) => {
177+
this.functionArns[key]
178+
= `arn:aws:lambda:${region}:${result.Account}:function:${value.name}`;
179+
});
180+
return BbPromise.resolve();
181+
});
182+
}
183+
184+
createIamRole() {
185+
return this.provider.request('IAM',
186+
'createRole',
187+
{
188+
AssumeRolePolicyDocument: this.assumeRolePolicyDocument,
189+
RoleName: this.iamRoleName,
190+
},
191+
this.options.stage,
192+
this.options.region)
193+
.then((result) => {
194+
this.iamRoleArn = result.Role.Arn;
195+
return this.provider.request('IAM',
196+
'createPolicy',
197+
{
198+
PolicyDocument: this.iamPolicyStatement,
199+
PolicyName: this.iamPolicyName,
200+
},
201+
this.options.stage,
202+
this.options.region);
203+
})
204+
.then((result) => this.provider.request('IAM',
205+
'attachRolePolicy',
206+
{
207+
PolicyArn: result.Policy.Arn,
208+
RoleName: this.iamRoleName,
209+
},
210+
this.options.stage,
211+
this.options.region)
212+
)
213+
.then(() => BbPromise.resolve());
214+
}
215+
216+
getStateMachineArn() {
217+
return this.provider.request('STS',
218+
'getCallerIdentity',
219+
{},
220+
this.options.stage,
221+
this.options.region)
222+
.then((result) => {
223+
const region = this.options.region || 'us-east-1';
224+
const stage = this.options.stage || 'dev';
225+
this.stateMachineArn =
226+
`arn:aws:states:${region}:${result.Account}:stateMachine:${this.options.state}-${stage}`;
227+
return BbPromise.resolve();
228+
});
229+
}
230+
231+
yamlParse() {
232+
const servicePath = this.serverless.config.servicePath;
233+
234+
if (!servicePath) {
235+
return BbPromise.resolve();
236+
}
237+
238+
let serverlessYmlPath = path.join(servicePath, 'serverless.yml');
239+
if (!this.serverless.utils.fileExistsSync(serverlessYmlPath)) {
240+
serverlessYmlPath = path
241+
.join(this.serverless.config.servicePath, 'serverless.yaml');
242+
}
243+
244+
return this.serverless.yamlParser
245+
.parse(serverlessYmlPath)
246+
.then((serverlessFileParam) => {
247+
this.stepFunctions = serverlessFileParam.stepFunctions;
248+
return BbPromise.resolve();
249+
});
250+
}
251+
252+
compile() {
253+
if (!this.stepFunctions) {
254+
return BbPromise.resolve();
255+
}
256+
257+
if (typeof this.stepFunctions[this.options.state] === 'undefined') {
258+
const errorMessage = [
259+
`Step function "${this.options.state}" is not exists`,
260+
].join('');
261+
throw new this.serverless.classes.Error(errorMessage);
262+
}
263+
264+
_.forEach(this.stepFunctions[this.options.state].States, (value, key) => {
265+
if (value.Resource && !value.Resource.match(/arn:aws:lambda/)) {
266+
this.stepFunctions[this.options.state].States[key].Resource
267+
= this.functionArns[value.Resource];
268+
}
269+
});
270+
271+
this.awsStateLanguage[this.options.state] =
272+
JSON.stringify(this.stepFunctions[this.options.state]);
273+
return BbPromise.resolve();
274+
}
275+
276+
deleteStateMachine() {
277+
return this.provider.request('StepFunctions',
278+
'deleteStateMachine',
279+
{
280+
stateMachineArn: this.stateMachineArn,
281+
},
282+
this.options.stage,
283+
this.options.region)
284+
.then(() => BbPromise.resolve());
285+
}
286+
287+
createStateMachine() {
288+
const stage = this.options.stage || 'dev';
289+
return this.provider.request('StepFunctions',
290+
'createStateMachine',
291+
{
292+
definition: this.awsStateLanguage[this.options.state],
293+
name: `${this.options.state}-${stage}`,
294+
roleArn: this.iamRoleArn,
295+
},
296+
this.options.stage,
297+
this.options.region)
298+
.then(() => {
299+
this.serverless.cli.consoleLog('');
300+
this.serverless.cli.log(`Finish to deploy ${this.options.state}-${stage} step function`);
301+
return BbPromise.resolve();
302+
}).catch((error) => {
303+
if (error.message.match(/State Machine is being deleted/)) {
304+
this.serverless.cli.printDot();
305+
setTimeout(this.createStateMachine.bind(this), 5000);
306+
} else {
307+
throw new this.serverless.classes.Error(error.message);
308+
}
309+
});
310+
}
311+
312+
startExecution() {
313+
this.serverless.cli.log(`Start function ${this.options.state}...`);
314+
315+
return this.provider.request('StepFunctions',
316+
'startExecution',
317+
{
318+
stateMachineArn: this.stateMachineArn,
319+
input: this.options.data,
320+
},
321+
this.options.stage,
322+
this.options.region)
323+
.then((result) => {
324+
this.executionArn = result.executionArn;
325+
return BbPromise.resolve();
326+
}).catch((error) => {
327+
throw new this.serverless.classes.Error(error.message);
328+
});
329+
}
330+
331+
describeExecution() {
332+
return this.provider.request('StepFunctions',
333+
'describeExecution',
334+
{
335+
executionArn: this.executionArn,
336+
},
337+
this.options.stage,
338+
this.options.region)
339+
.then((result) => {
340+
if (result.status === 'RUNNING') {
341+
this.serverless.cli.printDot();
342+
setTimeout(this.describeExecution.bind(this), 5000);
343+
} else {
344+
this.serverless.cli.consoleLog('');
345+
this.serverless.cli.consoleLog(result);
346+
}
347+
return BbPromise.resolve();
348+
});
349+
}
87350
}
88351
module.exports = ServerlessStepFunctions;

0 commit comments

Comments
 (0)