mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
185 lines
6.7 KiB
JavaScript
185 lines
6.7 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Action: FunctionInvoke
|
|
* - Invokes the function in the CWD
|
|
*
|
|
* Event Properties:
|
|
* - stage: (String) The function stage
|
|
* - region: (String) The function region
|
|
* - log: (Boolean) Show the log output
|
|
* - invocationType: (String) Invocation Type
|
|
*/
|
|
|
|
module.exports = function(SPlugin, serverlessPath) {
|
|
const path = require('path'),
|
|
SUtils = require( path.join( serverlessPath, 'utils' ) ),
|
|
SError = require(path.join(serverlessPath, 'ServerlessError')),
|
|
BbPromise = require('bluebird'),
|
|
SCli = require( path.join( serverlessPath, 'utils', 'cli')),
|
|
_ = require('lodash'),
|
|
chalk = require('chalk');
|
|
|
|
/**
|
|
* FunctionInvoke Class
|
|
*/
|
|
|
|
return class FunctionInvoke extends SPlugin {
|
|
|
|
constructor(S, config) {
|
|
super(S, config);
|
|
}
|
|
|
|
static getName() {
|
|
return 'serverless.core.' + FunctionInvoke.name;
|
|
}
|
|
|
|
registerActions() {
|
|
this.S.addAction(this.functionInvoke.bind(this), {
|
|
handler: 'functionInvoke',
|
|
description: 'Invokes the function',
|
|
context: 'function',
|
|
contextAction: 'invoke',
|
|
options: [
|
|
{
|
|
option: 'stage',
|
|
shortcut: 's',
|
|
description: 'The function stage'
|
|
}
|
|
, {
|
|
option: 'region',
|
|
shortcut: 'r',
|
|
description: 'The function region'
|
|
}
|
|
, {
|
|
option: 'invocationType',
|
|
shortcut: 'i',
|
|
description: 'Valid Values: Event | RequestResponse | DryRun . Default is RequestResponse'
|
|
}
|
|
, {
|
|
option: 'log',
|
|
shortcut: 'l',
|
|
description: 'Show the log output'
|
|
}
|
|
],
|
|
parameters: [
|
|
{
|
|
parameter: 'path',
|
|
description: 'Path of the function you want to run (componentName/moduleName/functionName)',
|
|
position: '0'
|
|
}
|
|
]
|
|
});
|
|
return BbPromise.resolve();
|
|
}
|
|
|
|
checkPath() {
|
|
// If a function path was not specified.
|
|
|
|
if(!this.evt.options.path) {
|
|
// If s-function.json exists in the current path, then use the current function path.
|
|
if(SUtils.fileExistsSync(path.join(process.cwd(), 's-function.json'))) {
|
|
let componentName = path.basename(path.join(process.cwd(), '..', '..'));
|
|
let moduleName = path.basename(path.join(process.cwd(), '..'));
|
|
let functionName = path.basename(process.cwd());
|
|
this.evt.options.path = componentName + "/" + moduleName + "/" + functionName;
|
|
}
|
|
else {
|
|
return BbPromise.reject(new SError('Missing required function path param. Run from within a function directory, or add a function path in this format: componentName/moduleName/functionName'));
|
|
}
|
|
}
|
|
return BbPromise.resolve()
|
|
}
|
|
|
|
/**
|
|
* Action
|
|
*/
|
|
|
|
functionInvoke(evt) {
|
|
this.evt = evt;
|
|
|
|
if (!this.S.state.meta.getStages().length) return BbPromise.reject(new SError('No existing stages in the project'));
|
|
|
|
return this.cliPromptSelectStage('Function Invoke - Choose a stage: ', evt.options.stage, false)
|
|
.then(stage => evt.options.stage = stage)
|
|
.bind(this)
|
|
.then(()=> this.cliPromptSelectRegion('Choose a Region in this Stage: ', false, true, evt.options.region, evt.options.stage))
|
|
.then(region => evt.options.region = region)
|
|
.then(this._validateAndPrepare)
|
|
.then(this._invoke)
|
|
.then(() => this.evt);
|
|
}
|
|
|
|
_validateAndPrepare() {
|
|
if (!this.evt.options.stage) return BbPromise.reject(new SError(`Stage is required`));
|
|
if (!this.evt.options.region) return BbPromise.reject(new SError(`Region is required`));
|
|
|
|
this.evt.options.invocationType = this.evt.options.invocationType || 'RequestResponse'
|
|
|
|
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.state.meta.get().stages[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.state.meta.get().stages[this.evt.options.stage].regions[this.evt.options.region]) {
|
|
return BbPromise.reject(new SError('Region "' + this.evt.options.region + '" does not exist in stage "' + this.evt.options.stage + '"'));
|
|
}
|
|
|
|
this.Lambda = require('../utils/aws/Lambda')({
|
|
region: this.evt.options.region,
|
|
accessKeyId: this.S.config.awsAdminKeyId,
|
|
secretAccessKey: this.S.config.awsAdminSecretKey
|
|
});
|
|
|
|
return this.checkPath()
|
|
.then( () => {
|
|
const func = this.S.state.getFunctions({paths: [this.evt.options.path]})[0];
|
|
this.evt.data.lambdaName = this.Lambda.sGetLambdaName(func.getProject().name, func.getComponent().name, func.getModule().name, func.name);
|
|
|
|
let functionPath = path.join(this.S.config.projectPath, this.evt.options.path);
|
|
this.evt.data.event = require(path.join(functionPath, 'event'));
|
|
})
|
|
.then(() => {
|
|
this.function = this.S.state.getFunctions({ paths: [this.evt.options.path] })[0];
|
|
// Missing function
|
|
if (!this.function) return BbPromise.reject(new SError('Function could not be found at the path specified.'));
|
|
});
|
|
}
|
|
|
|
_invoke() {
|
|
let params = {
|
|
FunctionName: this.evt.data.lambdaName,
|
|
// 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(this.evt.data.event)),
|
|
Qualifier: this.evt.options.stage
|
|
};
|
|
|
|
return this.Lambda.invokePromised(params)
|
|
.then( reply => {
|
|
let color = !reply.FunctionError ? 'white' : 'red';
|
|
|
|
if (reply.Payload) {
|
|
this.S.config.interactive && console.log(chalk[color](JSON.stringify(JSON.parse(reply.Payload), null, ' ')));
|
|
this.evt.data.payload = reply.Payload
|
|
}
|
|
|
|
if (reply.LogResult) {
|
|
console.log(chalk.gray('--------------------------------------------------------------------'))
|
|
let logResult = new Buffer(reply.LogResult, 'base64').toString()
|
|
_.each(logResult.split('\n'), (line) => {
|
|
console.log(SCli.formatLambdaLogEvent(line));
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}; |