Skip to content
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

Compression packs symlinks as copies #477

Open
garthk opened this issue Jun 13, 2018 · 3 comments
Open

Compression packs symlinks as copies #477

garthk opened this issue Jun 13, 2018 · 3 comments

Comments

@garthk
Copy link

garthk commented Jun 13, 2018

Description:

sam package compresses symlinks as an additional copy of the file to which they resolve. Given a traditional shared library layout with

libz.so → libz.so.1
libz.so.1 → libz.so.1.2.11
libz.so.1.2.11

sam package will pack the library three times, not once with two symlinks.

Steps to reproduce the issue:

make in a directory with .env, template.yml, and Makefile:

.env: replace the values with your own profile, region, and S3 bucket name:

AWS_PROFILE=default
AWS_REGION=ap-southeast-2
BUCKET=your-bucket-name-I-do-not-want-to-know

template.yml:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Reproducing a SAM CLI compression wart

Globals:
  Function:
    Runtime: nodejs8.10

Resources:
  DummyFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: Dummy
      CodeUri: ./build
      Handler: lambda.dummy

Makefile:

# Import AWS_PROFILE, AWS_REGION, BUCKET, and S3_PREFIX  from ./.env:
-include .env

# Set defaults, with none of which you'll likely be happy:
AWS_PROFILE ?= default
AWS_REGION ?= ap-southeast-2
BUCKET ?= your-bucket-name-here
S3_PREFIX ?= lambdas

# Targets
EXPECTED := expected.zip
OBSERVED := observed.zip

# Satisfy `aws` and `sam`:
export AWS_PROFILE
export AWS_REGION

# These targets don't produce files:
.PHONY: comparison clean

# This target is our default:
comparison: $(EXPECTED) $(OBSERVED)

# This cleans up:
clean:
	rm -rf build $(OBSERVED) $(EXPECTED)

# Construct the ZIP file we wish SAM had made:
$(EXPECTED): build
	( cd build ; zip -9y ../$(EXPECTED) * )
	unzip -l $(EXPECTED)

# Download and list the contents of the ZIP file `sam package` uploaded:
$(OBSERVED): packaged.yml
	aws s3 cp `grep CodeUri packaged.yml  | awk '{ print $$2 }'` $(OBSERVED)
	unzip -l $(OBSERVED)

# Zip the `build` directory, upload it to `BUCKET`, and prepare `packaged.yml`:
packaged.yml: build template.yml
	sam package \
		--debug \
		--template-file template.yml \
		--s3-bucket $(BUCKET) \
		--s3-prefix $(S3_PREFIX) \
		--output-template-file packaged.yml

# Prepare a `build` directory with a random 10MB shared library with
# traditional symlinks:
build: Makefile
	rm -rf build
	mkdir -p build
	echo 'module.exports.dummy = function() { return { pass: true }; };' > build/lambda.js
	dd if=/dev/random of=build/libz.so.1.2.11 bs=65536 count=160
	ln -s libz.so.1.2.11 build/libz.so.1
	ln -s libz.so.1 build/libz.so

Observed result:

Archive:  observed.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
       62  06-13-2018 14:02   lambda.js
 10485760  06-13-2018 14:02   libz.so.1
 10485760  06-13-2018 14:02   libz.so
 10485760  06-13-2018 14:02   libz.so.1.2.11
---------                     -------
 31457342                     4 files

Expected result:

Archive:  expected.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
       62  06-13-2018 14:02   lambda.js
        9  06-13-2018 14:02   libz.so
       14  06-13-2018 14:02   libz.so.1
 10485760  06-13-2018 14:02   libz.so.1.2.11
---------                     -------
 10485845                     4 files

Also, I expect compression at least as good as zip -9.

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

Output of sam --version: SAM CLI, version 0.3.0

Optional Debug logs: I gave --debug but couldn't find the output

@mhart
Copy link
Contributor

mhart commented Oct 25, 2019

This is also an issue with sam package creating layers that contain symlinks.

Given:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  DependenciesLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      ContentUri: dependencies/

If the dependencies directory has symlinks (which is very common for runtimes and binaries), then these won't be zipped correctly (ie, in the same way that zip -yr would) – this can lead to bloat and outright failure if the symlink is an absolute one (eg, it links to /opt/something)

You can manually create the zip yourself, but if you refer to it in the ContentUri (eg, ContentUri: dependencies.zip), then sam local invoke no longer appears to work (it doesn't unpack the zip). Should I file a separate bug for that?

@awsjeffg awsjeffg added the stage/pm-review Waiting for review by our Product Manager, please don't work on this yet label Aug 21, 2020
@awsjeffg awsjeffg added type/bug and removed stage/pm-review Waiting for review by our Product Manager, please don't work on this yet labels Sep 18, 2020
@jfuss jfuss added the stage/needs-investigation Requires a deeper investigation label Oct 13, 2020
@neo-headz
Copy link

I'd like to revive this issue as it seems there hasn't been any movement in a couple years. It will start having a larger impact as Nodejs devs start moving away from the Commonjs module loader and start using native ES modules.

The Lambda team recently announced support for native ESM which is awesome, however, importing modules defined in a shared layer does not work because Nodejs dropped support for the NODE_PATH env var, recommending using symlinks instead. There's also been discussion around using the loaders feature to solve this issue but it's still experimental.

Using a symlink works nicely if your workflow does not include SAM CLI as demonstrated here. When I add the symlink ln -s /opt/nodejs/node_modules node_modules into my function folder and run run sam deploy I get an error saying that node_modules doesn't exist.

It would be awesome to see this working in the SAM toolchain! Lambda, CDK, and Cloudformation package seem to handle the symlinks correctly.

@rubiconjosh
Copy link

Is there an update on this issue?

SAM CLI turning symlinks into copies is causing my Layer to be over the maximum uncompressed size.

My workaround is manually creating the .zip file, but this breaks the workflow and causes me to put a large binary in my source repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants