aws-sam-cli icon indicating copy to clipboard operation
aws-sam-cli copied to clipboard

sam build and sam local invoke differences regarding of LaverVersion in NodeJS

Open kstro21 opened this issue 4 years ago • 2 comments

Description

ContentUri property of AWS::Serverless::LayerVersion behaves differently depending on the command used and it is annoying. Currently, I have to use 2 different values, once to sam local invoke and another to run sam build.

Steps to reproduce

Here is the layer definition.

  CommonDependenciesLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: 'dev-common-dependencies-layer'
      Description: 'Common dependencies for dev env'
      ContentUri: './dependencies-layer'
      CompatibleRuntimes:
        - nodejs10.x
        - nodejs12.x
      RetentionPolicy: Retain
    Metadata:
      BuildMethod: nodejs10.x

Notice I'm using BuildMethod to build the layer when invoking sam build. The dependencies-layer folder looks like this

- dependencies-layer/
  |- node_modules
  |- package.json
  |- package-lock.json

I can invoke sam build then sam deploy and it works.

Now if I try to invoke a function that depends on the layer, it won't find any packages. We all know that the structure for a NodeJS layer is as follow:

- dependencies-layer/
  |- nodejs
    |- node_modules
    |- package.json
    |- package-lock.json

If I create the folder structure shown above, now sam local invoke works, but then sam build fails because the folder dependencies-layer does not contain a package.json.

There are a few ways we can handle this, like creating the folder nodejs copying the package.json in it then invoking npm install before sam local invoke. Or having both structures so both versions of the commands are happy but then we will have to maintain 2 versions of package.json. Or using a symlink, or using, etc.

Currently, I'm using a parameter, updated the value of ContentUri: !Ref MyParam and using sam local invoke --parameter-overrides MyParam=./dependencies-layer while the default value of the param is Default: './dependencies-layer/nodejs' but it feels like a hack.

Expected result

I would like that they both get to a mutual agreement so we don't have to do any extra step to make it work. I'm talking about sam build and sam local invoke

Additional environment details (Ex: Windows, Mac, Amazon Linux etc)

  1. OS: Amazon Linux
  2. sam --version: 1.2.0

kstro21 avatar Sep 15 '20 16:09 kstro21

Any progress?

kstro21 avatar Dec 04 '20 18:12 kstro21

Any update on this?

lc-101 avatar May 11 '22 18:05 lc-101

Hi all,

This should have been fixed since I can't re-produce this issue locally.

I have a function and layer in my template.yaml;

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs14.x
      Layers:
        - !Ref CommonDependenciesLayer

  CommonDependenciesLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: 'dev-common-dependencies-layer'
      Description: 'Common dependencies for dev env'
      ContentUri: './dependencies'
      CompatibleRuntimes:
        - nodejs14.x
        - nodejs16.x
      RetentionPolicy: Retain
    Metadata:
      BuildMethod: nodejs14.x

I am using axios as dependency, which is only defined in dependencies layer now;

const axios = require('axios')
const url = 'http://checkip.amazonaws.com/';
let response;

exports.lambdaHandler = async (event, context) => {
    try {
        const ret = await axios(url);
        response = {
            'statusCode': 200,
            'body': JSON.stringify({
                message: 'hello world',
                location: ret.data.trim()
            })
        }
    } catch (err) {
        console.log(err);
        return err;
    }

    return response
};

This is my source structure;

❯ tree .
.
├── dependencies
│   ├── node_modules
│   └── package.json
├── events
│   └── event.json
├── hello-world
│   └── app.js
└── template.yaml

4 directories, 4 files

And after I run sam build, this is my built folder structure (which adds nodejs folder for the layer);

 tree .aws-sam/build
.aws-sam/build
├── CommonDependenciesLayer
│   └── nodejs
│       ├── node_modules
│       │   ├── @ungap
│       │   ├── axios
│       │   │   ├── CHANGELOG.md
│       │   │   ├── LICENSE
│       │   │   ├── README.md
│       │   │   ├── SECURITY.md
│       │   │   ├── UPGRADE_GUIDE.md
│       │   │   ├── dist
│       │   │   │   ├── axios.js
│       │   │   │   ├── axios.map
│       │   │   │   ├── axios.min.js
│       │   │   │   └── axios.min.map
│       │   │   ├── index.d.ts
│       │   │   ├── index.js
│       │   │   ├── lib
│       │   │   │   ├── adapters
│       │   │   │   │   ├── README.md
│       │   │   │   │   ├── http.js
│       │   │   │   │   └── xhr.js
│       │   │   │   ├── axios.js
│       │   │   │   ├── cancel
│       │   │   │   │   ├── Cancel.js
│       │   │   │   │   ├── CancelToken.js
│       │   │   │   │   └── isCancel.js
│       │   │   │   ├── core
│       │   │   │   │   ├── Axios.js
│       │   │   │   │   ├── InterceptorManager.js
│       │   │   │   │   ├── README.md
│       │   │   │   │   ├── buildFullPath.js
│       │   │   │   │   ├── createError.js
│       │   │   │   │   ├── dispatchRequest.js
│       │   │   │   │   ├── enhanceError.js
│       │   │   │   │   ├── mergeConfig.js
│       │   │   │   │   ├── settle.js
│       │   │   │   │   └── transformData.js
│       │   │   │   ├── defaults.js
│       │   │   │   ├── helpers
│       │   │   │   │   ├── README.md
│       │   │   │   │   ├── bind.js
│       │   │   │   │   ├── buildURL.js
│       │   │   │   │   ├── combineURLs.js
│       │   │   │   │   ├── cookies.js
│       │   │   │   │   ├── deprecatedMethod.js
│       │   │   │   │   ├── isAbsoluteURL.js
│       │   │   │   │   ├── isAxiosError.js
│       │   │   │   │   ├── isURLSameOrigin.js
│       │   │   │   │   ├── normalizeHeaderName.js
│       │   │   │   │   ├── parseHeaders.js
│       │   │   │   │   ├── spread.js
│       │   │   │   │   └── validator.js
│       │   │   │   └── utils.js
│       │   │   └── package.json
│       │   └── follow-redirects
│       │       ├── LICENSE
│       │       ├── README.md
│       │       ├── debug.js
│       │       ├── http.js
│       │       ├── https.js
│       │       ├── index.js
│       │       └── package.json
│       └── package.json
├── HelloWorldFunction
│   └── app.js
└── template.yaml

13 directories, 54 files

And if I run sam local invoke it imports the library and executes successfully;

❯ sam local invoke
Invoking app.lambdaHandler (nodejs14.x)
CommonDependenciesLayer is a local Layer in the template
Building image........................
Skip pulling image and use local one: samcli/lambda:nodejs14.x-x86_64-e2462f05972210f55b560eea4.

Mounting /Volumes/workplace/other/gh-issues/cli-2222/sam-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container
START RequestId: 95850ee7-80ed-4097-9ff0-b12779b28978 Version: $LATEST
END RequestId: 95850ee7-80ed-4097-9ff0-b12779b28978
REPORT RequestId: 95850ee7-80ed-4097-9ff0-b12779b28978	Init Duration: 0.32 ms	Duration: 418.49 ms	Billed Duration: 419 ms	Memory Size: 128 MB	Max Memory Used: 128 MB
{"statusCode":200,"body":"{\"message\":\"hello world\",\"location\":\"x.x.x.x\"}"}%

I am going to resolve this issue for now, but please let us know if you are still experiencing this issue with an example for us to reproduce it.

Thanks!

mndeveci avatar Jan 10 '23 22:01 mndeveci

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

github-actions[bot] avatar Jan 10 '23 22:01 github-actions[bot]