FunctionDeploy: return distPath only, instead of array of file paths

This commit is contained in:
Austen Collins 2016-03-18 15:04:44 -07:00
parent a58bc3a5cf
commit c6686188e6
3 changed files with 244 additions and 237 deletions

View File

@ -1,13 +1,13 @@
'use strict';
const SError = require('./Error'),
SCli = require('./utils/cli'),
_ = require('lodash'),
BbPromise = require('bluebird'),
chalk = require('chalk'),
context = require('./utils/context'),
path = require('path'),
fs = BbPromise.promisifyAll(require('fs'));
SCli = require('./utils/cli'),
_ = require('lodash'),
BbPromise = require('bluebird'),
chalk = require('chalk'),
context = require('./utils/context'),
path = require('path'),
fs = BbPromise.promisifyAll(require('fs'));
module.exports = function(S) {
@ -34,10 +34,10 @@ module.exports = function(S) {
const handlerPath = path.join(S.getServerlessPath(), 'templates', 'nodejs', 'handler.js');
return fs.readFileAsync(handlerPath)
.then(handlerJs => BbPromise.all([
S.utils.writeFile(func.getRootPath('handler.js'), handlerJs),
S.utils.writeFile(func.getRootPath('event.json'), {})
]));
.then(handlerJs => BbPromise.all([
S.utils.writeFile(func.getRootPath('handler.js'), handlerJs),
S.utils.writeFile(func.getRootPath('event.json'), {})
]));
}
/**
@ -48,73 +48,73 @@ module.exports = function(S) {
run(func, stage, region) {
let _this = this,
functionEvent,
functionCall;
functionEvent,
functionCall;
return BbPromise.try(function () {
// Load Event
functionEvent = S.utils.readFileSync(func.getRootPath('event.json'));
// Load Event
functionEvent = S.utils.readFileSync(func.getRootPath('event.json'));
// Load Function
let handlerArr = func.handler.split('/').pop().split('.'),
functionFile = func.getRootPath(handlerArr[0] + '.js'),
functionHandler = handlerArr[1];
// Load Function
let handlerArr = func.handler.split('/').pop().split('.'),
functionFile = func.getRootPath(handlerArr[0] + '.js'),
functionHandler = handlerArr[1];
functionCall = require(functionFile)[functionHandler];
})
.then(() => _this.getEnvVars(func, stage, region))
.then(function (envVars) {
// Add ENV vars (from no stage/region) to environment
for (var key in envVars) {
process.env[key] = envVars[key];
}
})
.then(() => {
return new BbPromise(resolve => {
// Call Function
functionCall(functionEvent, context(func, (err, result) => {
SCli.log(`-----------------`);
// Show error
if (err) {
SCli.log(chalk.bold('Failed - This Error Was Returned:'));
SCli.log(err.message);
SCli.log(err.stack);
return resolve({
status: 'error',
response: err.message,
error: err
});
}
// Show success response
SCli.log(chalk.bold('Success! - This Response Was Returned:'));
SCli.log(JSON.stringify(result, null, 4));
return resolve({
status: 'success',
response: result
});
}));
functionCall = require(functionFile)[functionHandler];
})
})
.catch((err) => {
SCli.log(`-----------------`);
.then(() => _this.getEnvVars(func, stage, region))
.then(function (envVars) {
SCli.log(chalk.bold('Failed - This Error Was Thrown:'));
SCli.log(err.stack || err);
// Add ENV vars (from no stage/region) to environment
for (var key in envVars) {
process.env[key] = envVars[key];
}
})
.then(() => {
return {
status: 'error',
response: err.message,
error: err
};
});
return new BbPromise(resolve => {
// Call Function
functionCall(functionEvent, context(func, (err, result) => {
SCli.log(`-----------------`);
// Show error
if (err) {
SCli.log(chalk.bold('Failed - This Error Was Returned:'));
SCli.log(err.message);
SCli.log(err.stack);
return resolve({
status: 'error',
response: err.message,
error: err
});
}
// Show success response
SCli.log(chalk.bold('Success! - This Response Was Returned:'));
SCli.log(JSON.stringify(result, null, 4));
return resolve({
status: 'success',
response: result
});
}));
})
})
.catch((err) => {
SCli.log(`-----------------`);
SCli.log(chalk.bold('Failed - This Error Was Thrown:'));
SCli.log(err.stack || err);
return {
status: 'error',
response: err.message,
error: err
};
});
}
/**
@ -130,12 +130,14 @@ module.exports = function(S) {
let pathDist;
return this.createDistDir(func.name)
.then(function (distDir) {
pathDist = distDir
})
.then(() => this.copyFunction(func, pathDist, stage, region))
.then(() => this._addEnvVarsInline(func, pathDist, stage, region))
.then(() => this.generatePaths(func, pathDist));
.then(function (distDir) {
pathDist = distDir
})
.then(() => this.copyFunction(func, pathDist, stage, region))
.then(() => this._addEnvVarsInline(func, pathDist, stage, region))
.then(function() {
return pathDist;
});
}
/**
@ -165,14 +167,14 @@ module.exports = function(S) {
_addEnvVarsInline(func, pathDist, stage, region) {
return this.getEnvVars(func, stage, region)
.then(envVars => {
.then(envVars => {
const handlerArr = func.handler.split('.'),
handlerDir = path.dirname(func.handler),
handlerFile = handlerArr[0].split('/').pop(),
handlerMethod = handlerArr[1];
const handlerArr = func.handler.split('.'),
handlerDir = path.dirname(func.handler),
handlerFile = handlerArr[0].split('/').pop(),
handlerMethod = handlerArr[1];
const loader = `
const loader = `
var envVars = ${JSON.stringify(envVars, null, 2)};
for (var key in envVars) {
process.env[key] = envVars[key];
@ -180,11 +182,10 @@ module.exports = function(S) {
exports.handler = require("./${handlerFile}")["${handlerMethod}"];
`;
return fs.writeFileAsync(path.join(pathDist, handlerDir, '_serverless_handler.js'), loader);
});
return fs.writeFileAsync(path.join(pathDist, handlerDir, '_serverless_handler.js'), loader);
});
}
}
return RuntimeNode;
};

View File

@ -8,12 +8,13 @@
module.exports = function(S) {
const path = require('path'),
SUtils = S.utils,
SError = require(S.getServerlessPath('Error')),
BbPromise = require('bluebird'),
Zip = require('node-zip'),
fs = BbPromise.promisifyAll(require('fs'));
const path = require('path'),
SUtils = S.utils,
SError = require(S.getServerlessPath('Error')),
BbPromise = require('bluebird'),
Zip = require('node-zip'),
fs = require('fs'),
fse = BbPromise.promisifyAll(require('fs-extra'));
class CodeDeployLambda extends S.classes.Plugin {
@ -54,23 +55,23 @@ module.exports = function(S) {
// Flow
return _this._validateAndPrepare()
.bind(_this)
.then(_this._compress)
.then(_this._provision)
.then(_this._alias)
.then(function() {
.bind(_this)
.then(_this._compress)
.then(_this._provision)
.then(_this._alias)
.then(function() {
/**
* Return EVT
*/
/**
* Return EVT
*/
_this.evt.data.functioName = _this.functionName;
_this.evt.data.pathCompressed = _this.pathCompressed;
_this.evt.data.functionVersion = _this.functionVersion;
_this.evt.data.functionAliasArn = _this.functionAliasArn;
return _this.evt;
_this.evt.data.functioName = _this.functionName;
_this.evt.data.pathCompressed = _this.pathCompressed;
_this.evt.data.functionVersion = _this.functionVersion;
_this.evt.data.functionAliasArn = _this.functionAliasArn;
return _this.evt;
});
});
}
/**
@ -103,34 +104,39 @@ module.exports = function(S) {
_compress() {
let zip = new Zip();
let _this = this,
zip = new Zip();
this.evt.options.pathsPackaged.forEach(nc => {
zip.file(nc.name, fs.readFileSync(nc.path));
});
return fse.walk(_this.evt.options.pathDist)
.on('readable', function () {
let item;
while ((item = this.read())) {
console.log(item);
zip.file(item.name, S.utils.readFileSync(item.path));
}
})
.then(function () {
// Set zipfile name
this.zipName = `${this.function.getName()}_${this.evt.options.stage}_${this.evt.options.region}`;
// Set zipfile name
_this.zipName = `${_this.function.getName()}_${_this.evt.options.stage}_${_this.evt.options.region}`;
// Compress
this.zipBuffer = zip.generate({
type: 'nodebuffer',
compression: 'DEFLATE'
});
// Compress
_this.zipBuffer = zip.generate({
type: 'nodebuffer',
compression: 'DEFLATE'
});
if (this.zipBuffer.length > 52428800) {
BbPromise.reject(new SError(
'Zip file is > the 50MB Lambda queued limit (' + this.zipBuffer.length + ' bytes)',
SError.errorCodes.ZIP_TOO_BIG)
);
}
if (_this.zipBuffer.length > 52428800) {
BbPromise.reject(new SError(
'Zip file is > the 50MB Lambda queued limit (' + _this.zipBuffer.length + ' bytes)',
SError.errorCodes.ZIP_TOO_BIG));
}
// Create compressed package
this.pathCompressed = path.join(this.project.getTempPath(), this.zipName);
fs.writeFileSync(this.pathCompressed, this.zipBuffer);
SUtils.sDebug(`"${this.evt.options.stage} - ${this.evt.options.region} - ${this.functionName}": Compressed file created - ${this.pathCompressed}`);
return BbPromise.resolve();
// Create compressed package
_this.pathCompressed = path.join(_this.project.getTempPath(), _this.zipName);
fs.writeFileSync(_this.pathCompressed, _this.zipBuffer);
SUtils.sDebug(`"${_this.evt.options.stage} - ${_this.evt.options.region} - ${_this.functionName}": Compressed file created - ${_this.pathCompressed}`);
});
}
/**
@ -148,86 +154,86 @@ module.exports = function(S) {
};
return _this.aws.request('Lambda', 'getFunction', params, _this.evt.options.stage, _this.evt.options.region)
.catch(function (e) {
_this.lambda = null;
})
.then(function (data) {
_this.lambda = data;
})
.then(function () {
.catch(function (e) {
_this.lambda = null;
})
.then(function (data) {
_this.lambda = data;
})
.then(function () {
// Create or Update Lambda
if (!_this.lambda) {
// Create or Update Lambda
if (!_this.lambda) {
SUtils.sDebug(`"${_this.evt.options.stage} - ${_this.evt.options.region} - ${_this.function.functionName}": Creating Lambda function...`);
SUtils.sDebug(`"${_this.evt.options.stage} - ${_this.evt.options.region} - ${_this.function.functionName}": Creating Lambda function...`);
// Create Lambda
let params = {
Code: {
ZipFile: _this.zipBuffer
},
FunctionName: _this.functionName, /* required */
Handler: _this.function.getRuntime().getHandler(_this.function), /* required */
Role: _this.functionPopulated.customRole ? _this.functionPopulated.customRole : _this.project.getVariablesObject(_this.evt.options.stage, _this.evt.options.region).iamRoleArnLambda, /* required */
Runtime: _this.function.getRuntime().getName('aws'), /* required */
Description: 'Serverless Lambda function for project: ' + _this.project.name,
MemorySize: _this.functionPopulated.memorySize,
Publish: true, // Required by Serverless Framework & recommended best practice by AWS
Timeout: _this.functionPopulated.timeout,
VpcConfig: {
SecurityGroupIds: _this.functionPopulated.vpc.securityGroupIds,
SubnetIds: _this.functionPopulated.vpc.subnetIds
}
};
// Create Lambda
let params = {
Code: {
ZipFile: _this.zipBuffer
},
FunctionName: _this.functionName, /* required */
Handler: _this.function.getRuntime().getHandler(_this.function), /* required */
Role: _this.functionPopulated.customRole ? _this.functionPopulated.customRole : _this.project.getVariablesObject(_this.evt.options.stage, _this.evt.options.region).iamRoleArnLambda, /* required */
Runtime: _this.function.getRuntime().getName('aws'), /* required */
Description: 'Serverless Lambda function for project: ' + _this.project.name,
MemorySize: _this.functionPopulated.memorySize,
Publish: true, // Required by Serverless Framework & recommended best practice by AWS
Timeout: _this.functionPopulated.timeout,
VpcConfig: {
SecurityGroupIds: _this.functionPopulated.vpc.securityGroupIds,
SubnetIds: _this.functionPopulated.vpc.subnetIds
}
};
return _this.aws.request('Lambda', 'createFunction', params, _this.evt.options.stage, _this.evt.options.region)
.then(function (data) {
// Save Version & Lambda
_this.functionVersion = data.Version;
_this.lambda = data;
})
} else {
SUtils.sDebug(`"${_this.evt.options.stage} - ${_this.evt.options.region} - ${_this.functionName}": Updating Lambda configuration...`);
// Update Configuration
let params = {
FunctionName: _this.lambda.Configuration.FunctionName, /* required */
Description: 'Serverless Lambda function for project: ' + _this.project.name,
Handler: _this.function.getRuntime().getHandler(_this.function),
MemorySize: _this.functionPopulated.memorySize,
Role: _this.functionPopulated.customRole ? _this.functionPopulated.customRole : _this.project.getVariablesObject(_this.evt.options.stage, _this.evt.options.region).iamRoleArnLambda,
Timeout: _this.functionPopulated.timeout,
VpcConfig: {
SecurityGroupIds: _this.functionPopulated.vpc.securityGroupIds,
SubnetIds: _this.functionPopulated.vpc.subnetIds
}
};
return _this.aws.request('Lambda', 'updateFunctionConfiguration', params, _this.evt.options.stage, _this.evt.options.region)
.then(function () {
SUtils.sDebug(`"${_this.evt.options.stage} - ${_this.evt.options.region} - ${_this.functionName}": Updating Lambda function...`);
// Update Lambda Code
let params = {
FunctionName: _this.lambda.Configuration.FunctionName, /* required */
Publish: true, // Required by Serverless Framework & recommended by AWS
ZipFile: _this.zipBuffer
};
// Update Function
return _this.aws.request('Lambda', 'updateFunctionCode', params, _this.evt.options.stage, _this.evt.options.region)
return _this.aws.request('Lambda', 'createFunction', params, _this.evt.options.stage, _this.evt.options.region)
.then(function (data) {
// Save Version & Lambda
_this.functionVersion = data.Version;
_this.lambda = data;
})
} else {
SUtils.sDebug(`"${_this.evt.options.stage} - ${_this.evt.options.region} - ${_this.functionName}": Updating Lambda configuration...`);
// Update Configuration
let params = {
FunctionName: _this.lambda.Configuration.FunctionName, /* required */
Description: 'Serverless Lambda function for project: ' + _this.project.name,
Handler: _this.function.getRuntime().getHandler(_this.function),
MemorySize: _this.functionPopulated.memorySize,
Role: _this.functionPopulated.customRole ? _this.functionPopulated.customRole : _this.project.getVariablesObject(_this.evt.options.stage, _this.evt.options.region).iamRoleArnLambda,
Timeout: _this.functionPopulated.timeout,
VpcConfig: {
SecurityGroupIds: _this.functionPopulated.vpc.securityGroupIds,
SubnetIds: _this.functionPopulated.vpc.subnetIds
}
};
return _this.aws.request('Lambda', 'updateFunctionConfiguration', params, _this.evt.options.stage, _this.evt.options.region)
.then(function () {
SUtils.sDebug(`"${_this.evt.options.stage} - ${_this.evt.options.region} - ${_this.functionName}": Updating Lambda function...`);
// Update Lambda Code
let params = {
FunctionName: _this.lambda.Configuration.FunctionName, /* required */
Publish: true, // Required by Serverless Framework & recommended by AWS
ZipFile: _this.zipBuffer
};
// Update Function
return _this.aws.request('Lambda', 'updateFunctionCode', params, _this.evt.options.stage, _this.evt.options.region)
.then(function (data) {
// Save Version & Lambda
_this.functionVersion = data.Version;
_this.lambda = data;
});
});
});
}
})
}
})
}
/**
@ -246,55 +252,55 @@ module.exports = function(S) {
};
return _this.aws.request('Lambda', 'getAlias', params, _this.evt.options.stage, _this.evt.options.region)
.then(function() {
aliasedLambda = true;
}, function(e) {
aliasedLambda = false;
})
.then(function() {
.then(function() {
aliasedLambda = true;
}, function(e) {
aliasedLambda = false;
})
.then(function() {
if (aliasedLambda) {
if (aliasedLambda) {
// Update Existing Alias
// Update Existing Alias
SUtils.sDebug(`"${_this.evt.options.stage} - ${_this.evt.options.region} - ${_this.functionName}": Updating Lambda Alias for version - ${_this.functionVersion}`);
SUtils.sDebug(`"${_this.evt.options.stage} - ${_this.evt.options.region} - ${_this.functionName}": Updating Lambda Alias for version - ${_this.functionVersion}`);
let params = {
FunctionName: _this.lambda.FunctionName, /* required */
FunctionVersion: _this.functionVersion, /* required */
Name: _this.functionAlias, /* required */
Description: 'Project: '
+ _this.project.name
+ ' Stage: '
+ _this.evt.options.stage
};
let params = {
FunctionName: _this.lambda.FunctionName, /* required */
FunctionVersion: _this.functionVersion, /* required */
Name: _this.functionAlias, /* required */
Description: 'Project: '
+ _this.project.name
+ ' Stage: '
+ _this.evt.options.stage
};
return _this.aws.request('Lambda', 'updateAlias', params, _this.evt.options.stage, _this.evt.options.region);
return _this.aws.request('Lambda', 'updateAlias', params, _this.evt.options.stage, _this.evt.options.region);
} else {
} else {
// Create New Alias
// Create New Alias
SUtils.sDebug(`"${_this.evt.options.stage} - ${_this.evt.options.region} - ${_this.functionName}": Creating New Lambda Alias for version - ${_this.functionVersion}`);
SUtils.sDebug(`"${_this.evt.options.stage} - ${_this.evt.options.region} - ${_this.functionName}": Creating New Lambda Alias for version - ${_this.functionVersion}`);
let params = {
FunctionName: _this.lambda.FunctionName, /* required */
FunctionVersion: _this.functionVersion, /* required */
Name: _this.functionAlias, /* required */
Description: 'Project: '
+ _this.project.name
+ ' Stage: '
+ _this.evt.options.stage
};
let params = {
FunctionName: _this.lambda.FunctionName, /* required */
FunctionVersion: _this.functionVersion, /* required */
Name: _this.functionAlias, /* required */
Description: 'Project: '
+ _this.project.name
+ ' Stage: '
+ _this.evt.options.stage
};
return _this.aws.request('Lambda', 'createAlias', params, _this.evt.options.stage, _this.evt.options.region);
}
})
.then(function(data) {
return _this.aws.request('Lambda', 'createAlias', params, _this.evt.options.stage, _this.evt.options.region);
}
})
.then(function(data) {
// Save Alias
_this.functionAliasArn = data.AliasArn;
});
// Save Alias
_this.functionAliasArn = data.AliasArn;
});
}
}

View File

@ -112,7 +112,7 @@ module.exports = function(S) {
// Create pathsPackaged for each file ready to compress
return this.function.getRuntime().build(this.function, this.evt.options.stage, this.evt.options.region)
.then(paths => this.pathsPackaged = paths);
.then(pathDist => this.pathDist = pathDist);
}
}