mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
205 lines
7.4 KiB
JavaScript
205 lines
7.4 KiB
JavaScript
'use strict';
|
||
|
||
/**
|
||
* Action: FunctionRun
|
||
* - Runs the function in the CWD for local testing
|
||
*/
|
||
|
||
module.exports = function(SPlugin, serverlessPath) {
|
||
const path = require('path'),
|
||
SError = require(path.join(serverlessPath, 'Error')),
|
||
BbPromise = require('bluebird'),
|
||
chalk = require('chalk'),
|
||
SCli = require( path.join( serverlessPath, 'utils', 'cli'));
|
||
let SUtils;
|
||
|
||
/**
|
||
* FunctionRun Class
|
||
*/
|
||
|
||
class FunctionRun extends SPlugin {
|
||
|
||
constructor(S, config) {
|
||
super(S, config);
|
||
SUtils = S.utils;
|
||
}
|
||
|
||
static getName() {
|
||
return 'serverless.core.' + FunctionRun.name;
|
||
}
|
||
|
||
registerActions() {
|
||
this.S.addAction(this.functionRun.bind(this), {
|
||
handler: 'functionRun',
|
||
description: `Runs the service locally. Reads the service’s runtime and passes it off to a runtime-specific runner`,
|
||
context: 'function',
|
||
contextAction: 'run',
|
||
options: [
|
||
{
|
||
option: 'region',
|
||
shortcut: 'r',
|
||
description: 'region you want to run your function in'
|
||
},
|
||
{
|
||
option: 'stage',
|
||
shortcut: 's',
|
||
description: 'stage you want to run your function in'
|
||
},
|
||
{
|
||
option: 'invocationType',
|
||
shortcut: 'i',
|
||
description: 'Valid Values: Event | RequestResponse | DryRun . Default is RequestResponse'
|
||
},
|
||
{
|
||
option: 'log',
|
||
shortcut: 'l',
|
||
description: 'Show the log output'
|
||
}
|
||
],
|
||
parameters: [
|
||
{
|
||
parameter: 'name',
|
||
description: 'The name of the function you want to run',
|
||
position: '0'
|
||
}
|
||
]
|
||
});
|
||
return BbPromise.resolve();
|
||
}
|
||
|
||
/**
|
||
* Action
|
||
*/
|
||
|
||
functionRun(evt) {
|
||
|
||
let _this = this;
|
||
_this.evt = evt;
|
||
|
||
// Flow
|
||
return _this._validateAndPrepare()
|
||
.bind(_this)
|
||
.then(function() {
|
||
// Run local or deployed
|
||
if (_this.evt.options.stage) {
|
||
return _this._runDeployed();
|
||
} else {
|
||
return _this._runLocal();
|
||
}
|
||
})
|
||
.then(() => this.evt);
|
||
}
|
||
|
||
/**
|
||
* Validate And Prepare
|
||
*/
|
||
|
||
_validateAndPrepare() {
|
||
|
||
let _this = this;
|
||
|
||
// If CLI and path is not specified, deploy from CWD if Function
|
||
if (_this.S.cli && !_this.evt.options.name) {
|
||
// Get all functions in CWD
|
||
if (!SUtils.fileExistsSync(path.join(process.cwd(), 's-function.json'))) {
|
||
return BbPromise.reject(new SError('You must be in a function folder to run it'));
|
||
}
|
||
_this.evt.options.name = process.cwd().split(path.sep)[process.cwd().split(path.sep).length - 1];
|
||
}
|
||
|
||
|
||
_this.function = _this.S.getProject().getFunction(_this.evt.options.name);
|
||
|
||
// Missing function
|
||
if (!_this.function) return BbPromise.reject(new SError(`Function ${_this.evt.options.name} does not exist in your project.`));
|
||
|
||
return BbPromise.resolve();
|
||
}
|
||
|
||
/**
|
||
* Run Local
|
||
*/
|
||
|
||
_runLocal() {
|
||
if (!this.evt.options.name) {
|
||
return BbPromise.reject(new SError('Please provide a function name to run'));
|
||
}
|
||
SCli.log(`Running ${this.evt.options.name}...`);
|
||
return this.function.run()
|
||
.then(result => this.evt.data.result = result);
|
||
}
|
||
|
||
/**
|
||
* Run Deployed
|
||
*/
|
||
|
||
_runDeployed() {
|
||
let _this = this;
|
||
|
||
_this.evt.options.invocationType = _this.evt.options.invocationType || 'RequestResponse';
|
||
_this.evt.options.region = _this.evt.options.region || _this.S.getProject().getAllRegions(_this.evt.options.stage)[0].name;
|
||
|
||
if (_this.evt.options.invocationType !== 'RequestResponse') {
|
||
_this.evt.options.logType = 'None';
|
||
} else {
|
||
_this.evt.options.logType = _this.evt.options.log ? 'Tail' : 'None'
|
||
}
|
||
|
||
// validate stage: make sure stage exists
|
||
if (!_this.S.getProject().validateStageExists(_this.evt.options.stage)) {
|
||
return BbPromise.reject(new SError('Stage ' + _this.evt.options.stage + ' does not exist in your project', SError.errorCodes.UNKNOWN));
|
||
}
|
||
|
||
// validate region: make sure region exists in stage
|
||
if (!_this.S.getProject().validateRegionExists(_this.evt.options.stage, _this.evt.options.region)) {
|
||
return BbPromise.reject(new SError('Region "' + _this.evt.options.region + '" does not exist in stage "' + _this.evt.options.stage + '"'));
|
||
}
|
||
|
||
// Invoke Lambda
|
||
|
||
let params = {
|
||
FunctionName: _this.function.getDeployedName({ stage: _this.evt.options.stage, region: _this.evt.options.region }),
|
||
// ClientContext: new Buffer(JSON.stringify({x: 1, y: [3,4]})).toString('base64'),
|
||
InvocationType: _this.evt.options.invocationType,
|
||
LogType: _this.evt.options.logType,
|
||
Payload: new Buffer(JSON.stringify(SUtils.readFileSync(_this.function.getRootPath('event.json')))),
|
||
Qualifier: _this.evt.options.stage
|
||
};
|
||
|
||
return this.S.getProvider('aws')
|
||
.request('Lambda', 'invoke', params, _this.evt.options.stage, _this.evt.options.region)
|
||
.then( reply => {
|
||
|
||
let color = !reply.FunctionError ? 'white' : 'red';
|
||
|
||
if (reply.Payload) {
|
||
let payload = JSON.parse(reply.Payload)
|
||
_this.S.config.interactive && console.log(chalk[color](JSON.stringify(payload, null, ' ')));
|
||
_this.evt.data.result = {
|
||
status: 'success',
|
||
response: payload
|
||
};
|
||
}
|
||
|
||
if (reply.LogResult) {
|
||
console.log(chalk.gray('--------------------------------------------------------------------'));
|
||
let logResult = new Buffer(reply.LogResult, 'base64').toString();
|
||
logResult.split('\n').forEach( line => {
|
||
console.log(SCli.formatLambdaLogEvent(line));
|
||
});
|
||
}
|
||
})
|
||
.catch(function(e) {
|
||
_this.evt.data.result = {
|
||
status: 'error',
|
||
message: e.message,
|
||
stack: e.stack
|
||
};
|
||
|
||
BbPromise.reject(e);
|
||
});
|
||
}
|
||
}
|
||
|
||
return( FunctionRun );
|
||
}; |