From fa29072a5ab119c65373394c6a2006cba86479bc Mon Sep 17 00:00:00 2001 From: Haresh Nasit <84355507+hnnasit@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:35:35 -0800 Subject: [PATCH] feat: Add nodejs22.x support (#149) * feat: Add nodejs22.x support * use nodejs22 public ecr image * Update package.json to use nodejs22 --- .github/workflows/build.yml | 1 + Makefile | 1 + build-image-src/Dockerfile-nodejs22x | 65 +++++++++ build-image-src/build_all_images.sh | 2 + pytest.ini | 1 + tests/apps/nodejs22.x/sam-test-app/.gitignore | 129 ++++++++++++++++++ .../nodejs22.x/sam-test-app/events/event.json | 62 +++++++++ .../sam-test-app/hello-world/.npmignore | 1 + .../sam-test-app/hello-world/app.mjs | 26 ++++ .../sam-test-app/hello-world/package.json | 19 +++ .../nodejs22.x/sam-test-app/template.yaml | 39 ++++++ tests/test_build_images.py | 33 +++++ 12 files changed, 379 insertions(+) create mode 100644 build-image-src/Dockerfile-nodejs22x create mode 100644 tests/apps/nodejs22.x/sam-test-app/.gitignore create mode 100644 tests/apps/nodejs22.x/sam-test-app/events/event.json create mode 100644 tests/apps/nodejs22.x/sam-test-app/hello-world/.npmignore create mode 100644 tests/apps/nodejs22.x/sam-test-app/hello-world/app.mjs create mode 100644 tests/apps/nodejs22.x/sam-test-app/hello-world/package.json create mode 100644 tests/apps/nodejs22.x/sam-test-app/template.yaml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 27c4733..e38eb6a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,6 +51,7 @@ jobs: - "nodejs16x" - "nodejs18x" - "nodejs20x" + - "nodejs22x" - "provided_al2" - "provided_al2023" - "python38" diff --git a/Makefile b/Makefile index d9e3c73..cfced6e 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ IS_java21 := java21 IS_nodejs16x := nodejs16.x IS_nodejs18x := nodejs18.x IS_nodejs20x := nodejs20.x +IS_nodejs22x := nodejs22.x IS_provided_al2 := provided.al2 IS_provided_al2023 := provided.al2023 IS_python38 := python3.8 diff --git a/build-image-src/Dockerfile-nodejs22x b/build-image-src/Dockerfile-nodejs22x new file mode 100644 index 0000000..cdb4fa3 --- /dev/null +++ b/build-image-src/Dockerfile-nodejs22x @@ -0,0 +1,65 @@ +ARG IMAGE_ARCH +FROM public.ecr.aws/lambda/nodejs:22-$IMAGE_ARCH + +ENV PATH=/var/lang/bin:$PATH \ + LD_LIBRARY_PATH=/var/lang/lib:$LD_LIBRARY_PATH \ + AWS_EXECUTION_ENV=AWS_Lambda_nodejs22.x \ + NODE_PATH=/opt/nodejs/node22/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules + +RUN dnf remove -y microdnf-dnf && \ + microdnf install -y dnf + +RUN dnf groupinstall -y development && \ + dnf install -y \ + tar \ + gzip \ + unzip \ + python3 \ + jq \ + grep \ + make \ + rsync \ + binutils \ + gcc-c++ \ + procps \ + gmp-devel \ + zlib-devel \ + libmpc-devel \ + python3-devel \ + && dnf clean all + +# Install AWS CLI +ARG AWS_CLI_ARCH +RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-$AWS_CLI_ARCH.zip" -o "awscliv2.zip" && unzip awscliv2.zip && ./aws/install && rm awscliv2.zip && rm -rf ./aws + +# Install SAM CLI from native installer +ARG SAM_CLI_VERSION +# need to redefine since ARG is not available after FROM tag: https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact +ARG IMAGE_ARCH +RUN curl -L "https://github.com/aws/aws-sam-cli/releases/download/v$SAM_CLI_VERSION/aws-sam-cli-linux-$IMAGE_ARCH.zip" -o "samcli.zip" && \ + unzip samcli.zip -d sam-installation && ./sam-installation/install && \ + rm samcli.zip && rm -rf sam-installation && sam --version + +# Prepare virtualenv for lambda builders +RUN python3 -m venv --without-pip /usr/local/opt/lambda-builders +RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py +RUN LD_LIBRARY_PATH= /usr/local/opt/lambda-builders/bin/python3 get-pip.py +# Install lambda builders in a dedicated Python virtualenv +# Nodejs22 uses a different version (3.1.3) of OpenSSL. This caused an error when Python (installed via dnf) tries to use the ssl module. +# Temporarily set LD_LIBRARY_PATH to empty for python and pip to pick up the right OpenSSL version +RUN AWS_LB_VERSION=$(curl -sSL https://raw.githubusercontent.com/aws/aws-sam-cli/v$SAM_CLI_VERSION/requirements/base.txt | grep aws_lambda_builders | cut -d= -f3) && \ + LD_LIBRARY_PATH= /usr/local/opt/lambda-builders/bin/pip3 --no-cache-dir install "aws-lambda-builders==$AWS_LB_VERSION" + +ENV PATH=$PATH:/usr/local/opt/lambda-builders/bin + +ENV LANG=en_US.UTF-8 + +# Wheel is required by SAM CLI to build libraries like cryptography. It needs to be installed in the system +# Python for it to be picked up during `sam build` +RUN LD_LIBRARY_PATH= pip3 install wheel + +COPY ATTRIBUTION.txt / + +# Compatible with initial base image +ENTRYPOINT [] +CMD ["/bin/bash"] \ No newline at end of file diff --git a/build-image-src/build_all_images.sh b/build-image-src/build_all_images.sh index acc59b6..1b258f7 100755 --- a/build-image-src/build_all_images.sh +++ b/build-image-src/build_all_images.sh @@ -29,6 +29,7 @@ docker build -f Dockerfile-java21 -t amazon/aws-sam-cli-build-image-java21:x86_6 docker build -f Dockerfile-nodejs16x -t amazon/aws-sam-cli-build-image-nodejs16.x:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg IMAGE_ARCH=x86_64 . & docker build -f Dockerfile-nodejs18x -t amazon/aws-sam-cli-build-image-nodejs18.x:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg IMAGE_ARCH=x86_64 . & docker build -f Dockerfile-nodejs20x -t amazon/aws-sam-cli-build-image-nodejs20.x:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg IMAGE_ARCH=x86_64 . & +docker build -f Dockerfile-nodejs22x -t amazon/aws-sam-cli-build-image-nodejs22.x:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg IMAGE_ARCH=x86_64 . & docker build -f Dockerfile-provided_al2 -t amazon/aws-sam-cli-build-image-provided.al2:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg GO_ARCH=amd64 --build-arg IMAGE_ARCH=x86_64 . & docker build -f Dockerfile-provided_al2023 -t amazon/aws-sam-cli-build-image-provided.al2023:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg IMAGE_ARCH=x86_64 . & docker build -f Dockerfile-python38 -t amazon/aws-sam-cli-build-image-python3.8:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg IMAGE_ARCH=x86_64 . & @@ -53,6 +54,7 @@ docker build -f Dockerfile-java21 -t amazon/aws-sam-cli-build-image-java21:arm64 docker build -f Dockerfile-nodejs16x -t amazon/aws-sam-cli-build-image-nodejs16.x:arm64 --platform linux/arm64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=aarch64 --build-arg IMAGE_ARCH=arm64 . & docker build -f Dockerfile-nodejs18x -t amazon/aws-sam-cli-build-image-nodejs18.x:arm64 --platform linux/arm64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=aarch64 --build-arg IMAGE_ARCH=arm64 . & docker build -f Dockerfile-nodejs20x -t amazon/aws-sam-cli-build-image-nodejs20.x:arm64 --platform linux/arm64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=aarch64 --build-arg IMAGE_ARCH=arm64 . & +docker build -f Dockerfile-nodejs22x -t amazon/aws-sam-cli-build-image-nodejs22.x:arm64 --platform linux/arm64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=aarch64 --build-arg IMAGE_ARCH=arm64 . & docker build -f Dockerfile-provided_al2 -t amazon/aws-sam-cli-build-image-provided.al2:arm64 --platform linux/arm64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=aarch64 --build-arg GO_ARCH=arm64 --build-arg IMAGE_ARCH=arm64 . & docker build -f Dockerfile-provided_al2023 -t amazon/aws-sam-cli-build-image-provided.al2023:arm64 --platform linux/arm64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=aarch64 --build-arg IMAGE_ARCH=arm64 . & docker build -f Dockerfile-python38 -t amazon/aws-sam-cli-build-image-python3.8:arm64 --platform linux/arm64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=aarch64 --build-arg IMAGE_ARCH=arm64 . & diff --git a/pytest.ini b/pytest.ini index a0c1f87..7036b19 100644 --- a/pytest.ini +++ b/pytest.ini @@ -12,6 +12,7 @@ markers = nodejs16x nodejs18x nodejs20x + nodejs22x provided_al2 provided_al2023 python38 diff --git a/tests/apps/nodejs22.x/sam-test-app/.gitignore b/tests/apps/nodejs22.x/sam-test-app/.gitignore new file mode 100644 index 0000000..01cabda --- /dev/null +++ b/tests/apps/nodejs22.x/sam-test-app/.gitignore @@ -0,0 +1,129 @@ + +# Created by https://www.gitignore.io/api/osx,node,linux,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/osx,node,linux,windows diff --git a/tests/apps/nodejs22.x/sam-test-app/events/event.json b/tests/apps/nodejs22.x/sam-test-app/events/event.json new file mode 100644 index 0000000..070ad8e --- /dev/null +++ b/tests/apps/nodejs22.x/sam-test-app/events/event.json @@ -0,0 +1,62 @@ +{ + "body": "{\"message\": \"hello world\"}", + "resource": "/{proxy+}", + "path": "/path/to/resource", + "httpMethod": "POST", + "isBase64Encoded": false, + "queryStringParameters": { + "foo": "bar" + }, + "pathParameters": { + "proxy": "/path/to/resource" + }, + "stageVariables": { + "baz": "qux" + }, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "09/Apr/2015:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "/prod/path/to/resource", + "resourcePath": "/{proxy+}", + "httpMethod": "POST", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } +} diff --git a/tests/apps/nodejs22.x/sam-test-app/hello-world/.npmignore b/tests/apps/nodejs22.x/sam-test-app/hello-world/.npmignore new file mode 100644 index 0000000..e7e1fb0 --- /dev/null +++ b/tests/apps/nodejs22.x/sam-test-app/hello-world/.npmignore @@ -0,0 +1 @@ +tests/* diff --git a/tests/apps/nodejs22.x/sam-test-app/hello-world/app.mjs b/tests/apps/nodejs22.x/sam-test-app/hello-world/app.mjs new file mode 100644 index 0000000..9c26e5c --- /dev/null +++ b/tests/apps/nodejs22.x/sam-test-app/hello-world/app.mjs @@ -0,0 +1,26 @@ +/** + * + * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format + * @param {Object} event - API Gateway Lambda Proxy Input Format + * + * Context doc: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html + * @param {Object} context + * + * Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html + * @returns {Object} object - API Gateway Lambda Proxy Output Format + * + */ + +export const lambdaHandler = async (event, context) => { + try { + return { + 'statusCode': 200, + 'body': JSON.stringify({ + message: 'hello world', + }) + } + } catch (err) { + console.log(err); + return err; + } +}; diff --git a/tests/apps/nodejs22.x/sam-test-app/hello-world/package.json b/tests/apps/nodejs22.x/sam-test-app/hello-world/package.json new file mode 100644 index 0000000..5318385 --- /dev/null +++ b/tests/apps/nodejs22.x/sam-test-app/hello-world/package.json @@ -0,0 +1,19 @@ +{ + "name": "hello_world", + "version": "1.0.0", + "description": "Hello world sample for NodeJS22", + "main": "app.mjs", + "repository": "https://github.com/awslabs/aws-sam-cli/tree/develop/samcli/local/init/templates/cookiecutter-aws-sam-hello-nodejs", + "author": "SAM CLI", + "license": "MIT", + "dependencies": { + "axios": "^0.21.1" + }, + "scripts": { + "test": "mocha tests/unit/" + }, + "devDependencies": { + "chai": "^4.3.8", + "mocha": "^10.2.0" + } +} diff --git a/tests/apps/nodejs22.x/sam-test-app/template.yaml b/tests/apps/nodejs22.x/sam-test-app/template.yaml new file mode 100644 index 0000000..ce8eebd --- /dev/null +++ b/tests/apps/nodejs22.x/sam-test-app/template.yaml @@ -0,0 +1,39 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + sam-test-app12 + + Sample SAM Template for sam-test-app12 + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 3 + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + CodeUri: hello-world/ + Handler: app.lambdaHandler + Runtime: nodejs22.x + Events: + HelloWorld: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + +Outputs: + # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function + # Find out more about other implicit resources you can reference within SAM + # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api + HelloWorldApi: + Description: "API Gateway endpoint URL for Prod stage for Hello World function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" + HelloWorldFunction: + Description: "Hello World Lambda Function ARN" + Value: !GetAtt HelloWorldFunction.Arn + HelloWorldFunctionIamRole: + Description: "Implicit IAM Role created for Hello World function" + Value: !GetAtt HelloWorldFunctionRole.Arn diff --git a/tests/test_build_images.py b/tests/test_build_images.py index bcd605d..094efd0 100644 --- a/tests/test_build_images.py +++ b/tests/test_build_images.py @@ -341,6 +341,39 @@ def test_packages(self): self.assertTrue(self.is_package_present("npm")) self.assertTrue(self.is_architecture("aarch64")) +@pytest.mark.nodejs22xx86_64 +class TestBINode22(AL2023BasedBuildImageBase): + __test__ = True + + @classmethod + def setUpClass(cls): + super().setUpClass("nodejs22.x", "Dockerfile-nodejs22x", "npm", tag="x86_64") + + def test_packages(self): + """ + Test packages specific to this build image + """ + self.assertTrue(self.check_package_output("node --version", "v22.")) + self.assertTrue(self.is_package_present("npm")) + self.assertTrue(self.is_architecture("x86_64")) + + +@pytest.mark.nodejs22xarm64 +class TestBINode22ForArm(AL2023BasedBuildImageBase): + __test__ = True + + @classmethod + def setUpClass(cls): + super().setUpClass("nodejs22.x", "Dockerfile-nodejs22x", "npm", tag="arm64") + + def test_packages(self): + """ + Test packages specific to this build image + """ + self.assertTrue(self.check_package_output("node --version", "v22.")) + self.assertTrue(self.is_package_present("npm")) + self.assertTrue(self.is_architecture("aarch64")) + @pytest.mark.python38x86_64 class TestBIPython38(BuildImageBase):