From 2d4376b7f2a67fd3bed9f322d043dd6d69b47a42 Mon Sep 17 00:00:00 2001 From: Daniel Schep Date: Wed, 31 Oct 2018 09:20:32 -0400 Subject: [PATCH] Support for using Lambda Layers --- docs/providers/aws/guide/functions.md | 19 +++++ docs/providers/aws/guide/serverless.yml.md | 2 + .../aws/package/compile/functions/index.js | 4 + .../package/compile/functions/index.test.js | 82 +++++++++++++++++++ 4 files changed, 107 insertions(+) diff --git a/docs/providers/aws/guide/functions.md b/docs/providers/aws/guide/functions.md index 4502027b0..b42dce642 100644 --- a/docs/providers/aws/guide/functions.md +++ b/docs/providers/aws/guide/functions.md @@ -334,6 +334,25 @@ Real-world use cases where tagging your functions is helpful include: - Keeping track of legacy code (e.g. tag functions which use outdated runtimes: `runtime: nodejs0.10`) - ... +## Layers + +Using the `layers` configuration makes it possible for your function to use +[Lambda Layers](https://LINK-TO-AWS-DOCS-ABOUT-LAYERS) + +```yml +functions: + hello: + handler: handler.hello + layers: + - arn:aws:lambda:region:XXXXXX:layer:LayerName:Y +``` + +Layers can be used in combination with `runtime: provided` to implement your own custom runtime on +AWS Lambda. + +To publish Lambda Layers, check out the +[serverless-lambda-layers plugin](https://github.com/serverless/lambda-layers-plugin). + ## Log Group Resources By default, the framework will create LogGroups for your Lambdas. This makes it easy to clean up your log groups in the case you remove your service, and make the lambda IAM permissions much more specific and secure. diff --git a/docs/providers/aws/guide/serverless.yml.md b/docs/providers/aws/guide/serverless.yml.md index 0f7566219..30288d568 100644 --- a/docs/providers/aws/guide/serverless.yml.md +++ b/docs/providers/aws/guide/serverless.yml.md @@ -158,6 +158,8 @@ functions: - .travis.yml artifact: path/to/my-artifact.zip # Own package that should be use for this specific function. You must provide this file. individually: true # Enables individual packaging for specific function. If true you must provide package for each function. Defaults to false + layers: # An optional list Lambda Layers to use + - arn:aws:lambda:region:XXXXXX:layer:LayerName:Y # Layer Version ARN events: # The Events that trigger this Function - http: # This creates an API Gateway HTTP endpoint which can be used to trigger this function. Learn more in "events/apigateway" path: users/create # Path for this endpoint diff --git a/lib/plugins/aws/package/compile/functions/index.js b/lib/plugins/aws/package/compile/functions/index.js index 614419f10..00826d8c1 100644 --- a/lib/plugins/aws/package/compile/functions/index.js +++ b/lib/plugins/aws/package/compile/functions/index.js @@ -314,6 +314,10 @@ class AwsCompileFunctions { newFunction.DependsOn = [this.provider.naming.getLogGroupLogicalId(functionName)] .concat(newFunction.DependsOn || []); + if (functionObject.layers && _.isArray(functionObject.layers)) { + newFunction.Properties.Layers = functionObject.layers; + } + const functionLogicalId = this.provider.naming .getLambdaLogicalId(functionName); const newFunctionObject = { diff --git a/lib/plugins/aws/package/compile/functions/index.test.js b/lib/plugins/aws/package/compile/functions/index.test.js index 296c1cdb8..82bc858f2 100644 --- a/lib/plugins/aws/package/compile/functions/index.test.js +++ b/lib/plugins/aws/package/compile/functions/index.test.js @@ -2056,5 +2056,87 @@ describe('AwsCompileFunctions', () => { ).to.throw(Error); }); }); + + it('should not set unset properties when not specified in yml (layers, vpc, etc)', () => { + const s3Folder = awsCompileFunctions.serverless.service.package.artifactDirectoryName; + const s3FileName = awsCompileFunctions.serverless.service.package.artifact + .split(path.sep).pop(); + + awsCompileFunctions.serverless.service.functions = { + func: { + handler: 'func.function.handler', + name: 'new-service-dev-func', + }, + }; + const compiledFunction = { + Type: 'AWS::Lambda::Function', + DependsOn: [ + 'FuncLogGroup', + 'IamRoleLambdaExecution', + ], + Properties: { + Code: { + S3Key: `${s3Folder}/${s3FileName}`, + S3Bucket: { Ref: 'ServerlessDeploymentBucket' }, + }, + FunctionName: 'new-service-dev-func', + Handler: 'func.function.handler', + MemorySize: 1024, + Role: { 'Fn::GetAtt': ['IamRoleLambdaExecution', 'Arn'] }, + Runtime: 'nodejs4.3', + Timeout: 6, + }, + }; + + return expect(awsCompileFunctions.compileFunctions()).to.be.fulfilled + .then(() => { + expect( + awsCompileFunctions.serverless.service.provider.compiledCloudFormationTemplate + .Resources.FuncLambdaFunction + ).to.deep.equal(compiledFunction); + }); + }); + + it('should set Layers when specified', () => { + const s3Folder = awsCompileFunctions.serverless.service.package.artifactDirectoryName; + const s3FileName = awsCompileFunctions.serverless.service.package.artifact + .split(path.sep).pop(); + + awsCompileFunctions.serverless.service.functions = { + func: { + handler: 'func.function.handler', + name: 'new-service-dev-func', + layers: ['arn:aws:xxx:*:*'], + }, + }; + const compiledFunction = { + Type: 'AWS::Lambda::Function', + DependsOn: [ + 'FuncLogGroup', + 'IamRoleLambdaExecution', + ], + Properties: { + Code: { + S3Key: `${s3Folder}/${s3FileName}`, + S3Bucket: { Ref: 'ServerlessDeploymentBucket' }, + }, + FunctionName: 'new-service-dev-func', + Handler: 'func.function.handler', + MemorySize: 1024, + Role: { 'Fn::GetAtt': ['IamRoleLambdaExecution', 'Arn'] }, + Runtime: 'nodejs4.3', + Timeout: 6, + Layers: ['arn:aws:xxx:*:*'], + }, + }; + + return expect(awsCompileFunctions.compileFunctions()).to.be.fulfilled + .then(() => { + expect( + awsCompileFunctions.serverless.service.provider.compiledCloudFormationTemplate + .Resources.FuncLambdaFunction + ).to.deep.equal(compiledFunction); + }); + }); }); });