Skip to content

Commit c7e4e9e

Browse files
authored
Merge pull request #310 from david-mk-lawrence/build-as-aws-lambda-layer
Add AWS Lambda Layer Support
2 parents f206a79 + 79c078f commit c7e4e9e

File tree

4 files changed

+107
-0
lines changed

4 files changed

+107
-0
lines changed

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,38 @@ custom:
163163
```
164164
This will remove all folders within the installed requirements that match
165165
the names in `slimPatterns`
166+
167+
### Lamba Layer
168+
Another method for dealing with large dependencies is to put them into a
169+
[Lambda Layer](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html).
170+
Simply add the `layer` option to the configuration.
171+
```yaml
172+
custom:
173+
pythonRequirements:
174+
layer: true
175+
```
176+
The requirements will be zipped up and a layer will be created automatically.
177+
Now just add the reference to the functions that will use the layer.
178+
```yaml
179+
functions:
180+
hello:
181+
handler: handler.hello
182+
layers:
183+
- {Ref: PythonRequirementsLambdaLayer}
184+
```
185+
If the layer requires additional or custom configuration, add them onto the `layer` option.
186+
```yaml
187+
custom:
188+
pythonRequirements:
189+
layer:
190+
name: ${self:provider.stage}-layerName
191+
description: Python requirements lamba layer
192+
compatibleRuntimes:
193+
- python3.7
194+
licenseInfo: GPLv3
195+
allowedAccounts:
196+
- '*'
197+
```
166198
## Omitting Packages
167199
You can omit a package from deployment with the `noDeploy` option. Note that
168200
dependencies of omitted packages must explicitly be omitted too. By default,
@@ -423,3 +455,4 @@ zipinfo .serverless/xxx.zip
423455
* [@andrewfarley](https://github.com/andrewfarley) - Implemented download caching and static caching
424456
* [@bweigel](https://github.com/bweigel) - adding the `slimPatternsAppendDefaults` option & fixing per-function packaging when some functions don't have requirements & Porting tests from bats to js!
425457
* [@squaresurf](https://github.com/squaresurf) - adding usePoetry option
458+
* [@david-mk-lawrence](https://github.com/david-mk-lawrence) - added Lambda Layer support

index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const {
1010
packRequirements
1111
} = require('./lib/zip');
1212
const { injectAllRequirements } = require('./lib/inject');
13+
const { layerRequirements } = require('./lib/layer');
1314
const { installAllRequirements } = require('./lib/pip');
1415
const { pipfileToRequirements } = require('./lib/pipenv');
1516
const { pyprojectTomlToRequirements } = require('./lib/poetry');
@@ -32,6 +33,7 @@ class ServerlessPythonRequirements {
3233
slimPatterns: false,
3334
slimPatternsAppendDefaults: true,
3435
zip: false,
36+
layer: false,
3537
cleanupZipHelper: true,
3638
invalidateCaches: false,
3739
fileName: 'requirements.txt',
@@ -96,6 +98,12 @@ class ServerlessPythonRequirements {
9698
}`;
9799
options.dockerImage = options.dockerImage || defaultImage;
98100
}
101+
if (options.layer) {
102+
// If layer was set as a boolean, set it to an empty object to use the layer defaults.
103+
if (options.layer === true) {
104+
options.layer = {};
105+
}
106+
}
99107
return options;
100108
}
101109

@@ -170,6 +178,7 @@ class ServerlessPythonRequirements {
170178
}
171179
return BbPromise.bind(this)
172180
.then(removeVendorHelper)
181+
.then(layerRequirements)
173182
.then(() =>
174183
injectAllRequirements.bind(this)(
175184
arguments[1].functionObj &&

lib/inject.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ function moveModuleUp(source, target, module) {
7272
* @return {Promise} the combined promise for requirements injection.
7373
*/
7474
function injectAllRequirements(funcArtifact) {
75+
if (this.options.layer) {
76+
// The requirements will be placed in a Layer, so just resolve
77+
return BbPromise.resolve();
78+
}
79+
7580
this.serverless.cli.log('Injecting required Python packages to package...');
7681

7782
if (this.serverless.service.package.individually) {

lib/layer.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
const BbPromise = require('bluebird');
2+
const fse = require('fs-extra');
3+
const path = require('path');
4+
const JSZip = require('jszip');
5+
const { writeZip, addTree } = require('./zipTree');
6+
7+
BbPromise.promisifyAll(fse);
8+
9+
/**
10+
* Zip up requirements to be used as layer package.
11+
* @return {Promise} the JSZip object constructed.
12+
*/
13+
function zipRequirements() {
14+
const rootZip = new JSZip();
15+
const src = path.join('.serverless', 'requirements');
16+
const runtimepath = 'python';
17+
18+
return addTree(rootZip.folder(runtimepath), src).then(() =>
19+
writeZip(rootZip, path.join('.serverless', 'pythonRequirements.zip'))
20+
);
21+
}
22+
23+
/**
24+
* Creates a layer on the serverless service for the requirements zip.
25+
* @return {Promise} empty promise
26+
*/
27+
function createLayers() {
28+
this.serverless.service.layers['pythonRequirements'] = Object.assign(
29+
{
30+
artifact: path.join('.serverless', 'pythonRequirements.zip'),
31+
name: `${this.serverless.service.stage}-python-requirements`,
32+
description:
33+
'Python requirements generated by serverless-python-requirements.',
34+
compatibleRuntimes: [this.serverless.service.provider.runtime]
35+
},
36+
this.options.layer
37+
);
38+
39+
return BbPromise.resolve();
40+
}
41+
42+
/**
43+
* Creates a layer from the installed requirements.
44+
* @return {Promise} the combined promise for requirements layer.
45+
*/
46+
function layerRequirements() {
47+
if (!this.options.layer) {
48+
return BbPromise.resolve();
49+
}
50+
51+
this.serverless.cli.log('Packaging Python Requirements Lambda Layer...');
52+
53+
return BbPromise.bind(this)
54+
.then(zipRequirements)
55+
.then(createLayers);
56+
}
57+
58+
module.exports = {
59+
layerRequirements
60+
};

0 commit comments

Comments
 (0)