Skip to content

Add AWS Lambda Layer Support #310

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

Merged
merged 9 commits into from
Feb 7, 2019
3 changes: 0 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ class ServerlessPythonRequirements {
slimPatterns: false,
slimPatternsAppendDefaults: true,
zip: false,
inject: true,
layer: false,
cleanupZipHelper: true,
invalidateCaches: false,
Expand Down Expand Up @@ -98,8 +97,6 @@ class ServerlessPythonRequirements {
options.dockerImage = options.dockerImage || defaultImage;
}
if (options.layer) {
// If layers are being used, dependencies should not be injected.
options.inject = false;
// If layer was set as a boolean, set it to an empty object to use the layer defaults.
if (options.layer === true) {
options.layer = {};
Expand Down
3 changes: 2 additions & 1 deletion lib/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ function moveModuleUp(source, target, module) {
* @return {Promise} the combined promise for requirements injection.
*/
function injectAllRequirements(funcArtifact) {
if (!this.options.inject) {
if (this.options.layer) {
// The requirements will be placed in a Layer, so just resolve
return BbPromise.resolve();
}

Expand Down
56 changes: 45 additions & 11 deletions lib/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,62 @@ const BbPromise = require('bluebird');
const fse = require('fs-extra');
const path = require('path');
const JSZip = require('jszip');
const { writeZip, addTree } = require('./zipTree');
const {
writeZip,
addTree
} = require('./zipTree');

BbPromise.promisifyAll(fse);

/**
* Get the paths for the compatible runtimes of the layer
* @param {string[]} list of runtime paths
*/
function getRunTimeBuildPaths() {
const runtimepaths = {
'python2.7': 'python',
'python3.6': path.join('python', 'lib', 'python3.6', 'site-packages'),
'python3.7': path.join('python', 'lib', 'python3.7', 'site-packages'),
};

let runtimes = []

// Defer to Layer config first
if (this.options.layer.compatibleRuntimes) {
runtimes = this.options.layer.compatibleRuntimes;
// If none provided, assume the provider runtime
} else if (this.serverless.service.provider.runtime) {
runtimes = [this.serverless.service.provider.runtime];
// If still no runtime found, just assume latest python
} else {
runtimes = ['python3.7'];
}

return BbPromise.resolve(runtimes.map(runtime => runtimepaths[runtime]));
}

/**
* Zip up requirements to be used as layer package.
* @param {string[]} list of paths where the requirements should be put in the layer
* @return {Promise} the JSZip object constructed.
*/
function zipRequirements() {
return addTree(new JSZip(), path.join('.serverless', 'requirements')).then(
zip => writeZip(zip, path.join('.serverless', 'pythonRequirements.zip'))
);
function zipRequirements(runtimepaths) {
const rootZip = new JSZip();
const src = path.join('.serverless', 'requirements')

return BbPromise.each(runtimepaths, (runtimepath) => addTree(rootZip.folder(runtimepath), src))
.then(() => writeZip(rootZip, path.join('.serverless', 'pythonRequirementsLayer.zip')))
}

/**
* Creates a layer on the serverless service for the requirements zip.
* @return {Promise}
* @return {Promise} empty promise
*/
function createLayers() {
this.serverless.service.layers['pythonRequirements'] = Object.assign(
{
this.serverless.service.layers['pythonRequirements'] = Object.assign({
artifact: path.join('.serverless', 'pythonRequirements.zip'),
name: `${this.serverless.service.stage}-python-requirements`,
description:
'Python requirements generated by serverless-python-requirements.'
description: 'Python requirements generated by serverless-python-requirements.'
},
this.options.layer
);
Expand All @@ -46,8 +77,11 @@ function layerRequirements() {
this.serverless.cli.log('Packaging Python Requirements Lambda Layer...');

return BbPromise.bind(this)
.then(getRunTimeBuildPaths)
.then(zipRequirements)
.then(createLayers);
}

module.exports = { layerRequirements };
module.exports = {
layerRequirements
};