Sam local invoke not finding @ modules from lambda layer from SAR
See original GitHub issueDescription
Slightly related to #1187 but for NodeJs. The issue is not that local invoke
won’t run but that the lambda invoked can’t find any modules that are namespaced with an @
symbol within the modules. If I deploy this to AWS the lambda works fine and finds all the modules included in the layer.
Important point to make, my layer deployed to SAR is a separate template/repo than the consuming stack. Don’t know if that makes a difference but every example I’ve found so far to use layers always includes the creation inside the consuming stack.
Steps to reproduce
The layer template.yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: Lambda layer to house all shared code with backend apps
Resources:
NodeModulesLayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: !Sub 'serverless-shared-node-modules-dev'
ContentUri: ./
CompatibleRuntimes:
- nodejs8.10
- nodejs10.x
RetentionPolicy: Retain
Metadata:
AWS::ServerlessRepo::Application:
Name: serverless-shared-node-modules-dev
Description: >
Lambda layer to house all Node-based shared code with backend/serverless apps
Author: Grant
SemanticVersion: 1.0.0
ReadmeUrl: README.md
My folder structure for this layer
package.json (contains script to publish the layer)
README.md
template.yaml
nodejs
– node_modules
– package.json (contains @hapi/joi
and uuid
as dependencies)
A sample of the consuming layer’s template (it’s quite large)
Globals:
Function
RunTime: nodejs8.10
Layers:
- !GetAtt NodeModulesLayer.Outputs.LayerVersion
Resources:
NodeModulesLayer:
Type: AWS::Serverless::Application
Properties:
Location:
ApplicationId: 'arn:aws:serverlessrepo:us-east-1:<accountId>:applications/serverless-shared-node-modules-dev'
SemanticVersion: 1.0.0
TestFunction:
Type: AWS::Serverless::Function
Properties:
Handler: test.handler
CodeUri: ./
Within this test.js file:
const Joi = require('@hapi/joi');
const uuidv4 = require('uuid/v4');
exports.handler = () => {
console.log('This is great');
}
Publish the layer to SAR.
Run the TestFunction with sam local invoke:
sam local invoke -e test-event.json TestFunction
or sam local invoke -e test-event.json TestFunction -d 5858
I didn’t include the test-event.json since it doesn’t matter for this bug, considering it never gets to the handler.
Observed result
I get the following output:
sam local invoke -e test-event.json TestFunction
2019-10-29 16:29:52 Found credentials in shared credentials file: ~/.aws/credentials
2019-10-29 16:29:52 {'ResponseMetadata': {'RequestId': '<id>', 'HTTPStatusCode': 201, 'HTTPHeaders': {'date': 'Tue, 29 Oct 2019 21:29:53 GMT', 'content-type': 'application/json', 'content-length': '1657', 'connection': 'keep-alive', 'x-amzn-requestid': '<id>', 'x-amz-apigw-id': '<id>', 'x-amzn-trace-id': '<id>'}, 'RetryAttempts': 0}, 'ApplicationId': 'arn:aws:serverlessrepo:us-east-1:<accountId>:applications/serverless-shared-node-modules-dev', 'CreationTime': '2019-10-29T21:29:53.316Z', 'ExpirationTime': '2019-10-30T03:29:53.316Z', 'SemanticVersion': '1.0.0', 'Status': 'PREPARING', 'TemplateId': '<templateId>', 'TemplateUrl': '<templateUrl>'}
Invoking back-channel/index.dataHandler (nodejs8.10)
2019-10-29 16:29:53 Found credentials in shared credentials file: ~/.aws/credentials
Fetching lambci/lambda:nodejs8.10 Docker container image......
Mounting <project path> as /var/task:ro,delegated inside runtime container
START RequestId: ca1fffae-7d4b-1687-b8c3-5f3de9ef1053 Version: $LATEST
Unable to import module 'test': Error
at Function.Module._resolveFilename (module.js:547:15)
at Function.Module._load (module.js:474:25)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (/var/task/test.js:1:75)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
END RequestId: c67c6e8d-1994-1858-535d-d3bb0405eef7
REPORT RequestId: c67c6e8d-1994-1858-535d-d3bb0405eef7 Duration: 5386.11 ms Billed Duration: 5400 ms Memory Size: 384 MB Max Memory Used: 36 MB
{"errorMessage":"Cannot find module '@hapi/joi'","errorType":"Error","stackTrace":["Function.Module._load (module.js:474:25)","Module.require (module.js:596:17)","require (internal/module.js:11:18)","Object.<anonymous> (/var/task/test.js:1:75)","Module._compile (module.js:652:30)","Object.Module._extensions..js (module.js:663:10)","Module.load (module.js:565:32)","tryModuleLoad (module.js:505:12)","Function.Module._load (module.js:497:3)"]}
If you comment out the @hapi/joi
and only import uuid
for instance the handler invokes fine:
Expected result
All modules should be found, including namespaced modules (@
packages).
Additional environment details (Ex: Windows, Mac, Amazon Linux etc)
- OS: Mac 10.14.6
- shell: bash v 5.0.11
- SAM cli v 0.23.0
Issue Analytics
- State:
- Created 4 years ago
- Comments:16 (8 by maintainers)
I encountered this same problem, but with a python lambda function. I was encountering the exact same problem. So I spun up the docker image and connected via a bash terminal. What I found was that the lambda zip file was indeed copied to the /opt directory, but that it was NOT unzipped. Hence the failure.
@gallor Ok let’s back up a bit.
This will not work locally. We do not have a way (locally) to get a Layer from another stack or the
AWS::Serverless::Application
resource. You need to provide the Layer Arn statically or compose it with!Sub
in a manner that we can compose the arn.One way to do this is to deploy the resource to an put the Arn directly in the template or pass it into the template by a Paramater. You could also move the Layer Resource into the same stack and !Ref that Layer resource (assuming the Layer resource points to the code locally).
By your latest comment, It sounds like the layer was never getting downloaded, probably because we could resolve the !GetAtt.
Does this help?