From 1410a570b2dda2b105e8c5c00912272a7bcf8eac Mon Sep 17 00:00:00 2001 From: Rodric Rabbah Date: Wed, 13 May 2020 17:22:55 -0400 Subject: [PATCH 01/29] Update dockerfile and gradle builds for nimbella enhancements. --- core/nodejs10Action/Dockerfile | 6 ++++++ core/nodejs10Action/build.gradle | 8 ++++++++ core/nodejs12Action/Dockerfile | 6 ++++++ core/nodejs12Action/build.gradle | 8 ++++++++ core/nodejs14Action/Dockerfile | 6 ++++++ core/nodejs14Action/build.gradle | 8 ++++++++ core/nodejsActionBase/Dockerfile | 6 ++++++ core/nodejsActionBase/lambda.js | 0 core/nodejsActionBase/nim.js | 0 core/typescript37Action/Dockerfile | 4 ++++ core/typescript37Action/build.gradle | 7 +++++++ 11 files changed, 59 insertions(+) create mode 100644 core/nodejsActionBase/lambda.js create mode 100644 core/nodejsActionBase/nim.js diff --git a/core/nodejs10Action/Dockerfile b/core/nodejs10Action/Dockerfile index 36ca2472..f5adabab 100644 --- a/core/nodejs10Action/Dockerfile +++ b/core/nodejs10Action/Dockerfile @@ -38,6 +38,12 @@ COPY package.json / RUN cd / && npm install --no-package-lock --production \ && npm cache clean --force +# move nim sdk to node modules directory so that it can be found by node module loader +RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js + +ARG __LAMBDA_COMPAT +ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT + EXPOSE 8080 # The flag --experimental-worker enables worker threads, diff --git a/core/nodejs10Action/build.gradle b/core/nodejs10Action/build.gradle index b52bdaff..57412c93 100644 --- a/core/nodejs10Action/build.gradle +++ b/core/nodejs10Action/build.gradle @@ -49,6 +49,12 @@ task copyProxy(type: Copy) { task copyRunner(type: Copy) { from '../nodejsActionBase/runner.js' into '.' + + from '../nodejsActionBase/lambda.js' + into '.' + + from '../nodejsActionBase/nim.js' + into '.' } task copyService(type: Copy) { @@ -79,6 +85,8 @@ task copyBuildTemplate(type: Copy) { task cleanup(type: Delete) { delete 'package.json' delete 'app.js' + delete 'lambda.js' + delete 'nim.js' delete 'runner.js' delete 'src' delete 'platform' diff --git a/core/nodejs12Action/Dockerfile b/core/nodejs12Action/Dockerfile index 0558f92d..c7235d61 100644 --- a/core/nodejs12Action/Dockerfile +++ b/core/nodejs12Action/Dockerfile @@ -38,6 +38,12 @@ COPY package.json / RUN cd / && npm install --no-package-lock --production \ && npm cache clean --force +# move nim sdk to node modules directory so that it can be found by node module loader +RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js + +ARG __LAMBDA_COMPAT +ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT + EXPOSE 8080 CMD node --expose-gc app.js diff --git a/core/nodejs12Action/build.gradle b/core/nodejs12Action/build.gradle index ae773f6d..9dbf23e5 100644 --- a/core/nodejs12Action/build.gradle +++ b/core/nodejs12Action/build.gradle @@ -49,6 +49,12 @@ task copyProxy(type: Copy) { task copyRunner(type: Copy) { from '../nodejsActionBase/runner.js' into '.' + + from '../nodejsActionBase/lambda.js' + into '.' + + from '../nodejsActionBase/nim.js' + into '.' } task copyService(type: Copy) { @@ -79,6 +85,8 @@ task copyBuildTemplate(type: Copy) { task cleanup(type: Delete) { delete 'package.json' delete 'app.js' + delete 'lambda.js' + delete 'nim.js' delete 'runner.js' delete 'src' delete 'platform' diff --git a/core/nodejs14Action/Dockerfile b/core/nodejs14Action/Dockerfile index 80fd805e..b65d8247 100644 --- a/core/nodejs14Action/Dockerfile +++ b/core/nodejs14Action/Dockerfile @@ -38,6 +38,12 @@ COPY package.json / RUN cd / && npm install --no-package-lock --production \ && npm cache clean --force +# move nim sdk to node modules directory so that it can be found by node module loader +RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js + +ARG __LAMBDA_COMPAT +ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT + EXPOSE 8080 CMD node --expose-gc app.js diff --git a/core/nodejs14Action/build.gradle b/core/nodejs14Action/build.gradle index 85e07966..bab01564 100644 --- a/core/nodejs14Action/build.gradle +++ b/core/nodejs14Action/build.gradle @@ -49,6 +49,12 @@ task copyProxy(type: Copy) { task copyRunner(type: Copy) { from '../nodejsActionBase/runner.js' into '.' + + from '../nodejsActionBase/lambda.js' + into '.' + + from '../nodejsActionBase/nim.js' + into '.' } task copyService(type: Copy) { @@ -79,6 +85,8 @@ task copyBuildTemplate(type: Copy) { task cleanup(type: Delete) { delete 'package.json' delete 'app.js' + delete 'lambda.js' + delete 'nim.js' delete 'runner.js' delete 'src' delete 'platform' diff --git a/core/nodejsActionBase/Dockerfile b/core/nodejsActionBase/Dockerfile index d11e890a..cfc48bf9 100644 --- a/core/nodejsActionBase/Dockerfile +++ b/core/nodejsActionBase/Dockerfile @@ -36,6 +36,12 @@ COPY package.json / RUN cd / && npm install --no-package-lock --production \ && npm cache clean --force +# move nim sdk to node modules directory so that it can be found by node module loader +RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js + +ARG __LAMBDA_COMPAT +ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT + EXPOSE 8080 WORKDIR /nodejsAction diff --git a/core/nodejsActionBase/lambda.js b/core/nodejsActionBase/lambda.js new file mode 100644 index 00000000..e69de29b diff --git a/core/nodejsActionBase/nim.js b/core/nodejsActionBase/nim.js new file mode 100644 index 00000000..e69de29b diff --git a/core/typescript37Action/Dockerfile b/core/typescript37Action/Dockerfile index 29cc334d..f856807a 100644 --- a/core/typescript37Action/Dockerfile +++ b/core/typescript37Action/Dockerfile @@ -64,6 +64,7 @@ RUN mv /bin/proxy_${GO_PROXY_BUILD_FROM} /bin/proxy WORKDIR /app COPY bin/compile /bin/compile COPY lib/launcher.ts /lib/launcher.ts +COPY nim.js / COPY package.json / # Customize runtime with additional packages. @@ -75,6 +76,9 @@ RUN cd / && npm install -g \ && npm install --no-package-lock --production \ && npm cache clean --force +# move nim sdk to node modules directory so that it can be found by node module loader +RUN mkdir /node_modules/nim && mv /nim.js /node_modules/nim/index.js + EXPOSE 8080 ENTRYPOINT ["/bin/proxy"] diff --git a/core/typescript37Action/build.gradle b/core/typescript37Action/build.gradle index 1a17b564..0595b4fd 100644 --- a/core/typescript37Action/build.gradle +++ b/core/typescript37Action/build.gradle @@ -19,12 +19,19 @@ ext.dockerImageName = 'action-typescript-v3.7' apply from: '../../gradle/docker.gradle' distDocker.dependsOn 'copyPackageJson' +distDocker.dependsOn 'copyRunner' task copyPackageJson(type: Copy) { from '../nodejsActionBase/package.json' into '.' } +task copyRunner(type: Copy) { + from '../nodejsActionBase/nim.js' + into '.' +} + task cleanup(type: Delete) { delete 'package.json' + delete 'nim.js' } From 493bf8a385b8867feb431beb97d6ce127544872e Mon Sep 17 00:00:00 2001 From: Rodric Rabbah Date: Wed, 13 May 2020 17:35:51 -0400 Subject: [PATCH 02/29] Add lambda compatibility support. --- core/nodejsActionBase/app.js | 1 + core/nodejsActionBase/lambda.js | 18 ++++++++++++++++++ core/nodejsActionBase/nim.js | 18 ++++++++++++++++++ core/nodejsActionBase/src/service.js | 9 ++++++++- 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/core/nodejsActionBase/app.js b/core/nodejsActionBase/app.js index c50647d1..c0e58904 100644 --- a/core/nodejsActionBase/app.js +++ b/core/nodejsActionBase/app.js @@ -20,6 +20,7 @@ var config = { 'port': 8080, 'apiHost': process.env.__OW_API_HOST, 'allowConcurrent': process.env.__OW_ALLOW_CONCURRENT, + 'lambdaCompat': process.env.__LAMBDA_COMPAT, 'requestBodyLimit': "48mb" }; diff --git a/core/nodejsActionBase/lambda.js b/core/nodejsActionBase/lambda.js index e69de29b..51ec6721 100644 --- a/core/nodejsActionBase/lambda.js +++ b/core/nodejsActionBase/lambda.js @@ -0,0 +1,18 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// this is a place holder file diff --git a/core/nodejsActionBase/nim.js b/core/nodejsActionBase/nim.js index e69de29b..51ec6721 100644 --- a/core/nodejsActionBase/nim.js +++ b/core/nodejsActionBase/nim.js @@ -0,0 +1,18 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// this is a place holder file diff --git a/core/nodejsActionBase/src/service.js b/core/nodejsActionBase/src/service.js index e7812102..7f8dc942 100644 --- a/core/nodejsActionBase/src/service.js +++ b/core/nodejsActionBase/src/service.js @@ -16,6 +16,12 @@ */ const { initializeActionHandler, NodeActionRunner } = require('../runner'); +const NodeActionLambdaRunner = (() => { + try { + let lambda = require('../lambda'); + return lambda; + } catch (e) {} +})(); function NodeActionService(config) { @@ -27,6 +33,7 @@ function NodeActionService(config) { }; const ignoreRunStatus = config.allowConcurrent === undefined ? false : config.allowConcurrent.toLowerCase() === 'true'; + const lambdaCompat = config.lambdaCompat === undefined ? false : config.lambdaCompat.toLowerCase() === 'true' && NodeActionLambdaRunner !== undefined; let status = Status.ready; let server = undefined; @@ -173,7 +180,7 @@ function NodeActionService(config) { return initializeActionHandler(message) .then(handler => { - userCodeRunner = new NodeActionRunner(handler); + userCodeRunner = lambdaCompat === false ? new NodeActionRunner(handler) : new NodeActionLambdaRunner(handler); }) // emit error to activation log then flush the logs as this is the end of the activation .catch(error => { From 2d041966087c18949cdb227bf716da6bbbf9cee6 Mon Sep 17 00:00:00 2001 From: Rodric Rabbah Date: Wed, 13 May 2020 18:25:02 -0400 Subject: [PATCH 03/29] Add cloudjs runtime. --- core/cloudjs10Action/.dockerignore | 13 +++++ core/cloudjs10Action/Dockerfile | 52 +++++++++++++++++ core/cloudjs10Action/build.gradle | 94 ++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 core/cloudjs10Action/.dockerignore create mode 100644 core/cloudjs10Action/Dockerfile create mode 100644 core/cloudjs10Action/build.gradle diff --git a/core/cloudjs10Action/.dockerignore b/core/cloudjs10Action/.dockerignore new file mode 100644 index 00000000..a1d03cb9 --- /dev/null +++ b/core/cloudjs10Action/.dockerignore @@ -0,0 +1,13 @@ +*.*~ +*.yaml +*.tmpl +*.gradle +.dockerignore +.project +.settings +build.xml +Dockerfile +logs +node_modules +package-lock.json +test.js diff --git a/core/cloudjs10Action/Dockerfile b/core/cloudjs10Action/Dockerfile new file mode 100644 index 00000000..a8c50d47 --- /dev/null +++ b/core/cloudjs10Action/Dockerfile @@ -0,0 +1,52 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +FROM node:10.15.3-stretch + +# Initial update and some basics. +# +RUN apt-get update && apt-get install -y \ + imagemagick \ + graphicsmagick \ + unzip \ + && rm -rf /var/lib/apt/lists/* + +# Add sources and copy the package.json to root container, +# so npm packages from user functions take precendence. +# +WORKDIR /nodejsAction +ADD . /nodejsAction/ +COPY package.json / + +# Customize runtime with additional packages. +# Install package globally so user packages can override. +# +RUN cd / && npm install --no-package-lock --production \ + && npm cache clean --force + +# move nim sdk to node modules directory so that it can be found by node module loader +RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js + +RUN curl -sSL https://sdk.cloud.google.com | bash +ENV PATH="${PATH}:/root/google-cloud-sdk/bin" +RUN gcloud components install beta \ + && gcloud components install kubectl \ + && gcloud components update + +EXPOSE 8080 + +CMD node --expose-gc app.js diff --git a/core/cloudjs10Action/build.gradle b/core/cloudjs10Action/build.gradle new file mode 100644 index 00000000..cf64c56c --- /dev/null +++ b/core/cloudjs10Action/build.gradle @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'eclipse' +eclipse { + project { + natures 'org.eclipse.wst.jsdt.core.jsNature' + buildCommand 'org.eclipse.wst.jsdt.core.javascriptValidator' + } +} + +ext.dockerImageName = 'action-cloudjs-v10' +apply from: '../../gradle/docker.gradle' + +distDocker.dependsOn 'copyPackageJson' +distDocker.dependsOn 'copyProxy' +distDocker.dependsOn 'copyRunner' +distDocker.dependsOn 'copyService' +distDocker.dependsOn 'copyPlatform' +distDocker.dependsOn 'copyOpenWhisk' +distDocker.dependsOn 'copyKnative' +distDocker.dependsOn 'copyBuildTemplate' +distDocker.finalizedBy('cleanup') + +task copyPackageJson(type: Copy) { + from '../nodejsActionBase/package.json' + into '.' +} + +task copyProxy(type: Copy) { + from '../nodejsActionBase/app.js' + into '.' +} + +task copyRunner(type: Copy) { + from '../nodejsActionBase/runner.js' + into '.' + + from '../nodejsActionBase/lambda.js' + into '.' + + from '../nodejsActionBase/nim.js' + into '.' +} + +task copyService(type: Copy) { + from '../nodejsActionBase/src/service.js' + into './src' +} + +task copyPlatform(type: Copy) { + from '../nodejsActionBase/platform/platform.js' + into './platform' +} + +task copyOpenWhisk(type: Copy) { + from '../nodejsActionBase/platform/openwhisk.js' + into './platform' +} + +task copyKnative(type: Copy) { + from '../nodejsActionBase/platform/knative.js' + into './platform' +} + +task copyBuildTemplate(type: Copy) { + from '../nodejsActionBase/buildtemplate.yaml' + into '.' +} + +task cleanup(type: Delete) { + delete 'package.json' + delete 'app.js' + delete 'lambda.js' + delete 'nim.js' + delete 'runner.js' + delete 'src' + delete 'platform' + delete 'buildtemplate.yaml' +} From b64fe6925ca90b08df16c77b2828a8373176d371 Mon Sep 17 00:00:00 2001 From: Rodric Rabbah Date: Wed, 13 May 2020 18:30:24 -0400 Subject: [PATCH 04/29] Add tesseract runtime. --- core/tessjs10Action/.dockerignore | 13 +++++ core/tessjs10Action/Dockerfile | 58 +++++++++++++++++++ core/tessjs10Action/build.gradle | 94 +++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 core/tessjs10Action/.dockerignore create mode 100644 core/tessjs10Action/Dockerfile create mode 100644 core/tessjs10Action/build.gradle diff --git a/core/tessjs10Action/.dockerignore b/core/tessjs10Action/.dockerignore new file mode 100644 index 00000000..a1d03cb9 --- /dev/null +++ b/core/tessjs10Action/.dockerignore @@ -0,0 +1,13 @@ +*.*~ +*.yaml +*.tmpl +*.gradle +.dockerignore +.project +.settings +build.xml +Dockerfile +logs +node_modules +package-lock.json +test.js diff --git a/core/tessjs10Action/Dockerfile b/core/tessjs10Action/Dockerfile new file mode 100644 index 00000000..319fcb0b --- /dev/null +++ b/core/tessjs10Action/Dockerfile @@ -0,0 +1,58 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +FROM node:10.15.3-stretch + +# Initial update and some basics. +# +RUN apt-get update && apt-get install -y \ + imagemagick \ + graphicsmagick \ + unzip \ + wget \ + && rm -rf /var/lib/apt/lists/* + +# Add sources and copy the package.json to root container, +# so npm packages from user functions take precendence. +# +WORKDIR /nodejsAction +ADD . /nodejsAction/ +COPY package.json / + +# Download models +RUN wget -q https://raw.githubusercontent.com/tesseract-ocr/tessdata/master/eng.traineddata +RUN wget -q https://raw.githubusercontent.com/tesseract-ocr/tessdata/master/spa.traineddata +RUN wget -q https://raw.githubusercontent.com/tesseract-ocr/tessdata/master/chi_tra.traineddata + +# Customize runtime with additional packages. +# Install package globally so user packages can override. +# +RUN cd / && npm install --no-package-lock --production \ + && npm install --no-package-lock --production tesseract.js@1.0.19 \ + && npm cache clean --force + +# move nim sdk to node modules directory so that it can be found by node module loader +RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js + +ARG __LAMBDA_COMPAT +ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT + +EXPOSE 8080 + +# The flag --experimental-worker enables worker threads, +# see https://nodejs.org/docs/latest-v10.x/api/worker_threads.html +CMD node --experimental-worker --expose-gc app.js diff --git a/core/tessjs10Action/build.gradle b/core/tessjs10Action/build.gradle new file mode 100644 index 00000000..53126c75 --- /dev/null +++ b/core/tessjs10Action/build.gradle @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'eclipse' +eclipse { + project { + natures 'org.eclipse.wst.jsdt.core.jsNature' + buildCommand 'org.eclipse.wst.jsdt.core.javascriptValidator' + } +} + +ext.dockerImageName = 'action-tessjs-v10' +apply from: '../../gradle/docker.gradle' + +distDocker.dependsOn 'copyPackageJson' +distDocker.dependsOn 'copyProxy' +distDocker.dependsOn 'copyRunner' +distDocker.dependsOn 'copyService' +distDocker.dependsOn 'copyPlatform' +distDocker.dependsOn 'copyOpenWhisk' +distDocker.dependsOn 'copyKnative' +distDocker.dependsOn 'copyBuildTemplate' +distDocker.finalizedBy('cleanup') + +task copyPackageJson(type: Copy) { + from '../nodejsActionBase/package.json' + into '.' +} + +task copyProxy(type: Copy) { + from '../nodejsActionBase/app.js' + into '.' +} + +task copyRunner(type: Copy) { + from '../nodejsActionBase/runner.js' + into '.' + + from '../nodejsActionBase/lambda.js' + into '.' + + from '../nodejsActionBase/nim.js' + into '.' +} + +task copyService(type: Copy) { + from '../nodejsActionBase/src/service.js' + into './src' +} + +task copyPlatform(type: Copy) { + from '../nodejsActionBase/platform/platform.js' + into './platform' +} + +task copyOpenWhisk(type: Copy) { + from '../nodejsActionBase/platform/openwhisk.js' + into './platform' +} + +task copyKnative(type: Copy) { + from '../nodejsActionBase/platform/knative.js' + into './platform' +} + +task copyBuildTemplate(type: Copy) { + from '../nodejsActionBase/buildtemplate.yaml' + into '.' +} + +task cleanup(type: Delete) { + delete 'package.json' + delete 'app.js' + delete 'lambda.js' + delete 'nim.js' + delete 'runner.js' + delete 'src' + delete 'platform' + delete 'buildtemplate.yaml' +} From fd26c6f83f76d83ebbe2bc389210ee045e6a2f2d Mon Sep 17 00:00:00 2001 From: Rodric Rabbah Date: Wed, 13 May 2020 18:49:13 -0400 Subject: [PATCH 05/29] Update publish targets. --- .travis.yml | 22 +++++----------------- README.md | 2 +- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 494870d0..4c306084 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,13 +22,6 @@ language: java services: - docker -notifications: - email: false - webhooks: - urls: - # travis2slack webhook to enable DMs on openwhisk-team.slack.com to PR authors with TravisCI results - secure: "C+xu3CoAqyHm8N8zVwjOGhZOxYmwjZRkBMZUAbiNz6vVZq6j/TU8Mu44Z5zEWsufSdrAtu+Mg4Kfr00x8hlYYBxH6YXs7vKhToCERY1JLnlSjquvzzbOkaiG+fpYyiATNH6uz1BJdm1FcSr8n2mRV1nmAXmE/Ie28Q+nVIFt8CXA/mBWl9Z/l6Rwf7REWgWL4mGr2Wjb3vgth0IEO7rZtDKxQlas0s8naJA6nA6dIPxBFuuBrLmNIRAF7qOLBLC6508UWqt+9k/QYbujM7qhnmSJEPGHXG/5lZBWbn2UPIS6EKTlYW5o44cGmP8N0MAKDJezmDjE4r8HwTiKzaM8axQPLw+H7wumhIXbPO2lsHGgzxZAh7M771cXf8pRxoaqWm/bxweAPWA+6bKSrHJGYtM9FTHghNVeuwLTR18NJj4mIzb9BS90rodLfLXrbUPY5lC/4I5YRrCqlhyHr7aibWXM27ehf5/ujkQkBSyd6LeiONl04jFcCNPHlYxIf2XJnHX/6CiE/eJ2R7xqwtGBkTXCb63hnOqDv49nDrj0PfPi2Y0B4x/zoXz6P7ZyogDM6dOOUeL2u/XBryJgQxnoH2S+7Gh+qSdAigCsD2onsF6ghHCdeQRVX/f7CHsyXVxqxHdfyXNXrJJ1uz0tVKZkNSSOwU/1JJbiA+wzGYTnu3E=" - before_install: - "./tools/travis/setup.sh" install: true @@ -36,18 +29,13 @@ script: - "./tools/travis/build.sh && ./tools/travis/test.sh" deploy: - provider: script - script: "./tools/travis/publish.sh openwhisk ${TRAVIS_TAG%@*} ${TRAVIS_TAG##*@}" + script: "./tools/travis/publish.sh nimbella nodejs10Action ${TRAVIS_TAG} && ./tools/travis/publish.sh nimbella nodejs12Action ${TRAVIS_TAG} && ./tools/travis/publish.sh nimbella nodejs14Action ${TRAVIS_TAG} && ./tools/travis/publish.sh nimbella typescript37Action ${TRAVIS_TAG}" on: tags: true all_branches: true - repo: apache/openwhisk-runtime-nodejs + repo: nimbella-corp/openwhisk-runtime-nodejs - provider: script - script: "./tools/travis/publish.sh openwhisk nodejs10Action nightly && ./tools/travis/publish.sh openwhisk nodejs12Action nightly && ./tools/travis/publish.sh openwhisk nodejs14Action nightly && ./tools/travis/publish.sh openwhisk typescript37Action nightly" + script: "./tools/travis/publish.sh nimbella nodejs10Action nightly && ./tools/travis/publish.sh nimbella nodejs12Action nightly && ./tools/travis/publish.sh nimbella nodejs14Action nightly && ./tools/travis/publish.sh nimbella typescript37Action nightly" on: - branch: master - repo: apache/openwhisk-runtime-nodejs - -env: - global: - - secure: Y1ldwIQ6bc3/3Pc0E+qQ6K2M830B9BObYDlsNilPwF/kak3YSfF7SuXuRbJGjTdhH2KOotZD2CwONgP2yvOSPBToC/HpnXYfAGtgblrxQORvgdik88CFWa3Lli1pwlpdzKQNWhBvglzq+IIS98wqzmwqGr8zKA+Iau2ByHdb1j3M9rrIY9V6oU9Gwim1apcRyfI/as3+QfPtt8BUAl2U7+PprxwJigyF/mcZnBJbd7IjrilE2gldZLxKlBiffoKVBinrEg3IQGJPt6k8riw264pBQEpcA0ZBsPUvMaISSxLb+d1ymp3WsiTJUjv+URR/HcdDa7P9jY+ouc8PQz4Yt+Ii38lM2tQU480APfVTyfj6drkjL/+54mYuxm8TzkBWcM2j6/FYT+8HvK/pF35wDJ3El+jGq7BARXg8HVxFsZgynJnhqhWDQb3xX9fK+N4K8+ct+HlsOSa5mP5i5Yo6WRTrWrFpyxVnv9crKePCiYqA2Y8ta8Wnh0sM06nLRtDbfbDjvXPQbaZqSnL4B2Cto08YoT/W/lu8QgJ3EEFlUdDOke4kv9yoXtuE0h7+8dwOvBNMVrBis3G2EYObgR4WmWjk4loYhqT9h3jrH0/5bGLzSKc++qYW0rOZ/RB21cRSe1ILQvSzWkImUoPI8b0i5baGSDq3EjTXYr3pIXSYpQk= - - secure: DOg+FgllLbyv7nEK3JJZfO/cvXy5K0L6QI/S9EJ/ivm4XBDCw1ayhrSQXvp1tMTPbWBEIv2gomPsHghJ+hVvX3dgwYdoNz9WZaNBB6lOO9U8OQW0LBsO5Eai6grzqOP35OuKtthuyR3dGJHAZo/XjhZM/jL0z6q1kNDzdS7ASwRwHJG0rHPGVlGeolH4nAity4KNJvyAspS1FYaIj9FEC/M7UT6nJVACbr9iMt/83teF/Oo2uoFI6Pa4K3nE2NViVFibToNOM3CV8kArDPDoNJviXxQ07ZM6fNijwehZ80waiPSaxFY8PLSntQNxGyB3DbomSTCcdVvtuHHQVmZgpVdvOJE8wk3R09+nq9U9FuUWLiRYSRbF1eF48YFnssPW1jEeVSenFRADcQ37e4B21ssLvXRHpQHpPVrYBZ8ffDamS7pKtEqocX/3Syc6irxHGCpxEdhvQ0Of5AWHhzB714VCijJJQiH9J4hEKXhMeAZ5SSt4eUavEHJKMhUcJ/aaku5w1+KtiYeOso1fTRbTYkEYb1A0bSNdXlGrYRRT+N683W7+ENiQIT+hTp617L/m5WQLIHfKe3gy5qt46kHFiUL3R3YlBI5OKjnLkDnUiA+0d4SFtJC/TBuPmH1fG4isAuvggTjzCb3kUG3ysin8AW0AKaXW0eqjKa/nsHWDKmc= + branch: dev + repo: nimbella-corp/openwhisk-runtime-nodejs diff --git a/README.md b/README.md index 1ecaef9c..9cbe8bfb 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ # Apache OpenWhisk runtimes for Node.js [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0) -[![Build Status](https://travis-ci.com/apache/openwhisk-runtime-nodejs.svg?branch=master)](https://travis-ci.com/apache/openwhisk-runtime-nodejs) +[![Build Status](https://travis-ci.com/nimbella-corp/openwhisk-runtime-nodejs.svg?branch=master)](https://travis-ci.com/nimbella-corp/openwhisk-runtime-nodejs) This repository contains sources files needed to build the Node.js runtimes for Apache OpenWhisk. The build system will produce a series of docker images for each runtime version. These images are used in the platform to execute Node.js actions. From 67564bf06038a16880fa1fc078b37ead48c21452 Mon Sep 17 00:00:00 2001 From: Rodric Rabbah Date: Mon, 1 Mar 2021 10:36:07 -0500 Subject: [PATCH 06/29] Update from source build. --- core/typescript37Action/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/typescript37Action/Dockerfile b/core/typescript37Action/Dockerfile index f856807a..2b9dac27 100644 --- a/core/typescript37Action/Dockerfile +++ b/core/typescript37Action/Dockerfile @@ -17,8 +17,8 @@ # build go proxy from source FROM golang:1.15 AS builder_source -ARG GO_PROXY_GITHUB_USER=apache -ARG GO_PROXY_GITHUB_BRANCH=master +ARG GO_PROXY_GITHUB_USER=nimbella-corp +ARG GO_PROXY_GITHUB_BRANCH=dev RUN git clone --branch ${GO_PROXY_GITHUB_BRANCH} \ https://github.com/${GO_PROXY_GITHUB_USER}/openwhisk-runtime-go /src ;\ cd /src ; env GO111MODULE=on CGO_ENABLED=0 go build main/proxy.go && \ @@ -36,7 +36,7 @@ RUN curl -sL \ FROM node:12.1.0-stretch # select the builder to use -ARG GO_PROXY_BUILD_FROM=release +ARG GO_PROXY_BUILD_FROM=source ENV TYPESCRIPT_VERSION=3.7.4 ENV OW_COMPILER=/bin/compile From 730e40e039c5518710c0331efe7190a9c80578e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Tue, 15 Feb 2022 12:27:41 +0100 Subject: [PATCH 07/29] Run the app from a fully qualified path (#1) This makes running the runtime non-sensitive to workingdir changes so that that can be changed through docker run commands to instruct the runtime to write elsewhere. --- core/nodejs14Action/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/nodejs14Action/Dockerfile b/core/nodejs14Action/Dockerfile index b65d8247..ccfb2e76 100644 --- a/core/nodejs14Action/Dockerfile +++ b/core/nodejs14Action/Dockerfile @@ -46,4 +46,4 @@ ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT EXPOSE 8080 -CMD node --expose-gc app.js +CMD node --expose-gc /nodejsAction/app.js From 8f4a65fcce37a5fb63e2cb3fef631791bc362a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Tue, 15 Feb 2022 13:27:13 +0100 Subject: [PATCH 08/29] Add all the references (#2) --- core/cloudjs10Action/Dockerfile | 2 +- core/nodejs12Action/Dockerfile | 2 +- core/nodejsActionBase/Dockerfile | 2 +- core/tessjs10Action/Dockerfile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/cloudjs10Action/Dockerfile b/core/cloudjs10Action/Dockerfile index a8c50d47..33595740 100644 --- a/core/cloudjs10Action/Dockerfile +++ b/core/cloudjs10Action/Dockerfile @@ -49,4 +49,4 @@ RUN gcloud components install beta \ EXPOSE 8080 -CMD node --expose-gc app.js +CMD node --expose-gc /nodejsAction/app.js diff --git a/core/nodejs12Action/Dockerfile b/core/nodejs12Action/Dockerfile index c7235d61..511dd002 100644 --- a/core/nodejs12Action/Dockerfile +++ b/core/nodejs12Action/Dockerfile @@ -46,4 +46,4 @@ ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT EXPOSE 8080 -CMD node --expose-gc app.js +CMD node --expose-gc /nodejsAction/app.js diff --git a/core/nodejsActionBase/Dockerfile b/core/nodejsActionBase/Dockerfile index cfc48bf9..ad0d6f5c 100644 --- a/core/nodejsActionBase/Dockerfile +++ b/core/nodejsActionBase/Dockerfile @@ -45,4 +45,4 @@ ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT EXPOSE 8080 WORKDIR /nodejsAction -CMD node --expose-gc app.js +CMD node --expose-gc /nodejsAction/app.js diff --git a/core/tessjs10Action/Dockerfile b/core/tessjs10Action/Dockerfile index 319fcb0b..7e1f5156 100644 --- a/core/tessjs10Action/Dockerfile +++ b/core/tessjs10Action/Dockerfile @@ -55,4 +55,4 @@ EXPOSE 8080 # The flag --experimental-worker enables worker threads, # see https://nodejs.org/docs/latest-v10.x/api/worker_threads.html -CMD node --experimental-worker --expose-gc app.js +CMD node --experimental-worker --expose-gc /nodejsAction/app.js From acaaa897f36951c7882b4e91213a863f4ed94116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Wed, 23 Mar 2022 08:39:31 +0100 Subject: [PATCH 09/29] SERVERLESS-943 Make the Node.js 14 runtime action-loop based (#3) All of our other runtimes (except .Net and deno for now) are action-loop based. This allows us to make assumptions about all runtimes in the same way and consolidates further implementation efforts towards the go-proxy. --- .gitignore | 1 + core/nodejs14Action/Dockerfile | 39 +- core/nodejs14Action/build.gradle | 44 +- core/nodejsActionBase/app.js | 96 ---- core/nodejsActionBase/bin/compile | 99 ++++ core/nodejsActionBase/launcher.js | 79 +++ core/nodejsActionBase/platform/knative.js | 514 ------------------ core/nodejsActionBase/platform/openwhisk.js | 29 - core/nodejsActionBase/platform/platform.js | 144 ----- core/nodejsActionBase/src/service.js | 225 -------- .../NodeJsActionContainerTests.scala | 10 +- 11 files changed, 223 insertions(+), 1057 deletions(-) delete mode 100644 core/nodejsActionBase/app.js create mode 100755 core/nodejsActionBase/bin/compile create mode 100644 core/nodejsActionBase/launcher.js delete mode 100644 core/nodejsActionBase/platform/knative.js delete mode 100644 core/nodejsActionBase/platform/openwhisk.js delete mode 100644 core/nodejsActionBase/platform/platform.js delete mode 100644 core/nodejsActionBase/src/service.js diff --git a/.gitignore b/.gitignore index 0f904f2d..e0825869 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ results !/ansible/environments/mac # actionloop action compiler script +!core/nodejsActionBase/bin/compile !core/typescript37Action/bin/compile # Eclipse diff --git a/core/nodejs14Action/Dockerfile b/core/nodejs14Action/Dockerfile index ccfb2e76..de904121 100644 --- a/core/nodejs14Action/Dockerfile +++ b/core/nodejs14Action/Dockerfile @@ -15,8 +15,29 @@ # limitations under the License. # +# build go proxy from source +FROM golang:1.15 AS builder_source +ARG GO_PROXY_GITHUB_USER=nimbella-corp +ARG GO_PROXY_GITHUB_BRANCH=dev +RUN git clone --branch ${GO_PROXY_GITHUB_BRANCH} \ + https://github.com/${GO_PROXY_GITHUB_USER}/openwhisk-runtime-go /src ;\ + cd /src ; env GO111MODULE=on CGO_ENABLED=0 go build main/proxy.go && \ + mv proxy /bin/proxy + +# or build it from a release +FROM golang:1.15 AS builder_release +ARG GO_PROXY_RELEASE_VERSION=1.15@1.17.0 +RUN curl -sL \ + https://github.com/apache/openwhisk-runtime-go/archive/{$GO_PROXY_RELEASE_VERSION}.tar.gz\ + | tar xzf -\ + && cd openwhisk-runtime-go-*/main\ + && GO111MODULE=on go build -o /bin/proxy + FROM node:14.15.4-stretch +# select the builder to use +ARG GO_PROXY_BUILD_FROM=source + # Initial update and some basics. # RUN apt-get update && apt-get install -y \ @@ -41,9 +62,19 @@ RUN cd / && npm install --no-package-lock --production \ # move nim sdk to node modules directory so that it can be found by node module loader RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js -ARG __LAMBDA_COMPAT -ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT +ARG __OW_LAMBDA_COMPAT +ENV __OW_LAMBDA_COMPAT=$__OW_LAMBDA_COMPAT + +COPY --from=builder_source /bin/proxy /bin/proxy_source +COPY --from=builder_release /bin/proxy /bin/proxy_release +RUN mv /bin/proxy_${GO_PROXY_BUILD_FROM} /bin/proxy + +ADD bin/compile /bin/compile +ENV OW_COMPILER=/bin/compile -EXPOSE 8080 +# log initialization errors +ENV OW_LOG_INIT_ERROR=1 +# the launcher must wait for an ack +ENV OW_WAIT_FOR_ACK=1 -CMD node --expose-gc /nodejsAction/app.js +ENTRYPOINT [ "/bin/proxy" ] diff --git a/core/nodejs14Action/build.gradle b/core/nodejs14Action/build.gradle index bab01564..8aabac77 100644 --- a/core/nodejs14Action/build.gradle +++ b/core/nodejs14Action/build.gradle @@ -27,13 +27,8 @@ ext.dockerImageName = 'action-nodejs-v14' apply from: '../../gradle/docker.gradle' distDocker.dependsOn 'copyPackageJson' -distDocker.dependsOn 'copyProxy' distDocker.dependsOn 'copyRunner' -distDocker.dependsOn 'copyService' -distDocker.dependsOn 'copyPlatform' -distDocker.dependsOn 'copyOpenWhisk' -distDocker.dependsOn 'copyKnative' -distDocker.dependsOn 'copyBuildTemplate' +distDocker.dependsOn 'copyCompile' distDocker.finalizedBy('cleanup') task copyPackageJson(type: Copy) { @@ -41,11 +36,6 @@ task copyPackageJson(type: Copy) { into '.' } -task copyProxy(type: Copy) { - from '../nodejsActionBase/app.js' - into '.' -} - task copyRunner(type: Copy) { from '../nodejsActionBase/runner.js' into '.' @@ -55,40 +45,22 @@ task copyRunner(type: Copy) { from '../nodejsActionBase/nim.js' into '.' -} - -task copyService(type: Copy) { - from '../nodejsActionBase/src/service.js' - into './src' -} -task copyPlatform(type: Copy) { - from '../nodejsActionBase/platform/platform.js' - into './platform' -} - -task copyOpenWhisk(type: Copy) { - from '../nodejsActionBase/platform/openwhisk.js' - into './platform' -} - -task copyKnative(type: Copy) { - from '../nodejsActionBase/platform/knative.js' - into './platform' + from '../nodejsActionBase/launcher.js' + into '.' } -task copyBuildTemplate(type: Copy) { - from '../nodejsActionBase/buildtemplate.yaml' - into '.' +task copyCompile(type: Copy) { + from '../nodejsActionBase/bin/compile' + into './bin' } task cleanup(type: Delete) { delete 'package.json' - delete 'app.js' + delete 'launcher.js' delete 'lambda.js' delete 'nim.js' delete 'runner.js' delete 'src' - delete 'platform' - delete 'buildtemplate.yaml' + delete 'bin' } diff --git a/core/nodejsActionBase/app.js b/core/nodejsActionBase/app.js deleted file mode 100644 index c0e58904..00000000 --- a/core/nodejsActionBase/app.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// __OW_ALLOW_CONCURRENT: see docs/concurrency.md -var config = { - 'port': 8080, - 'apiHost': process.env.__OW_API_HOST, - 'allowConcurrent': process.env.__OW_ALLOW_CONCURRENT, - 'lambdaCompat': process.env.__LAMBDA_COMPAT, - 'requestBodyLimit': "48mb" -}; - -var bodyParser = require('body-parser'); -var express = require('express'); - -/** - * instantiate app as an instance of Express - * i.e. app starts the server - */ -var app = express(); - -/** - * instantiate an object which handles REST calls from the Invoker - */ -var service = require('./src/service').getService(config); - -/** - * setup a middleware layer to restrict the request body size - * this middleware is called every time a request is sent to the server - */ -app.use(bodyParser.json({ limit: config.requestBodyLimit })); - -// identify the target Serverless platform -const platformFactory = require('./platform/platform.js'); -const factory = new platformFactory(app, config, service); -var targetPlatform = process.env.__OW_RUNTIME_PLATFORM; - -// default to "openwhisk" platform initialization if not defined -// TODO export isvalid() from platform, if undefined this is OK to default, but if not valid value then error out -if (typeof targetPlatform === "undefined") { - targetPlatform = platformFactory.PLATFORM_OPENWHISK; - // console.log("__OW_RUNTIME_PLATFORM is undefined; defaulting to 'openwhisk' ..."); -} - -if (!platformFactory.isSupportedPlatform(targetPlatform)) { - console.error("__OW_RUNTIME_PLATFORM ("+targetPlatform+") is not supported by the runtime."); - process.exit(9); -} - -/** - * Register different endpoint handlers depending on target PLATFORM and its expected behavior. - * In addition, register request pre-processors and/or response post-processors as needed - * to move data where the platform and function author expects it to be. - */ - -const platformImpl = factory.createPlatformImpl(targetPlatform); - -if (typeof platformImpl !== "undefined") { - - platformImpl.registerHandlers(app, platformImpl); - - // short-circuit any requests to invalid routes (endpoints) that we have no handlers for. - app.use(function (req, res, next) { - res.status(500).json({error: "Bad request."}); - }); - - /** - * Register a default error handler. This effectively only gets called when invalid JSON is received - * (JSON Parser) and we do not wish the default handler to error with a 400 and send back HTML in the - * body of the response. - */ - app.use(function (err, req, res, next) { - console.log(err.stackTrace); - res.status(500).json({error: "Bad request."}); - }); - - service.start(app); - -} else { - console.error("Failed to initialize __OW_RUNTIME_PLATFORM ("+targetPlatform+")."); - process.exit(10); -} diff --git a/core/nodejsActionBase/bin/compile b/core/nodejsActionBase/bin/compile new file mode 100755 index 00000000..4cfe0825 --- /dev/null +++ b/core/nodejsActionBase/bin/compile @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import print_function +import os +import sys +import codecs + +def sources(launcher, source_dir, main): + # We're dealing with a zipped action if there's more than one file after unzipping + # or if we have just one but that isn't exec. + num_files = len([name for name in os.listdir(source_dir) if os.path.isfile("%s/%s" % (source_dir, name))]) + if num_files == 1 and os.path.isfile("%s/exec" % source_dir): + main_file = "main" + main_func = main + + # If we only upload a single file, it'll be called 'exec' which we need the launcher + # script to be. + src = "%s/exec" % source_dir + dst = "%s/main.js" % source_dir + body = "" + with codecs.open(src, 'r', 'utf-8') as s: + body = s.read() + with codecs.open(dst, 'w', 'utf-8') as d: + func = '''module.exports.%(main)s = (function(){ + %(code)s + try { + return %(main)s + } catch (e) { + if (e.name === 'ReferenceError') { + return module.exports.%(main)s || exports.%(main)s + } else throw e + } +})()''' % {"code": body, "main": main} + d.write(func) + else: + # main can be either + # file.func + # func + # + # If only 1 part is defined, Node.js will infer the file to either be index.js or + # part of package.json. + parts = main.split(".", 1) + if len(parts) == 1: + if not os.path.isfile("%s/index.js" % source_dir) and not os.path.isfile("%s/package.json" % source_dir): + print("Zipped actions must contain either package.json or index.js at the root.") + sys.exit(1) + + main_file = "" + main_func = parts[0] + else: + main_file = parts[0] + main_func = parts[1] + + # Write the launcher file to the current source dir + launcher_file = "%s/exec__.js" % source_dir + with codecs.open(launcher_file, 'w', 'utf-8') as d: + with codecs.open(launcher, 'r', 'utf-8') as s: + body = s.read() + body = body.replace('require("./##MAIN_FILE##").##MAIN_FUNC##', 'require("./%s").%s' % (main_file, main_func)) + d.write(body) + +def build(source_dir, target_file): + with codecs.open(target_file, 'w', 'utf-8') as d: + d.write("""#!/bin/bash +cd %s +exec node exec__.js +""" % source_dir) + os.chmod(target_file, 0o755) + +def main(argv): + if len(argv) < 4: + print("usage: ") + sys.exit(1) + + main = argv[1] + source_dir = os.path.abspath(argv[2]) + target_file = os.path.abspath("%s/exec" % argv[3]) + launcher = "/nodejsAction/launcher.js" + sources(launcher, source_dir, main) + build(source_dir, target_file) + +if __name__ == '__main__': + main(sys.argv) diff --git a/core/nodejsActionBase/launcher.js b/core/nodejsActionBase/launcher.js new file mode 100644 index 00000000..e9b8e44b --- /dev/null +++ b/core/nodejsActionBase/launcher.js @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +try { + const readline = require('readline'); + const fs = require("fs") + + const { NodeActionRunner } = require('/nodejsAction/runner'); + const NodeActionLambdaRunner = (() => { + try { + let lambda = require('/nodejsAction/lambda'); + return lambda; + } catch (e) {} + })(); + + const lambdaCompat = process.env.__OW_LAMBDA_COMPAT === undefined ? false : process.env.__OW_LAMBDA_COMPAT.toLowerCase() === 'true' && NodeActionLambdaRunner !== undefined; + const handler = eval('require("./##MAIN_FILE##").##MAIN_FUNC##') // Will be replaced in the compile script with the correct main. + const runner = lambdaCompat === false ? new NodeActionRunner(handler) : new NodeActionLambdaRunner(handler); + + async function actionLoop() { + const out = fs.createWriteStream(null, + { fd: 3, encoding: "utf8" }) + process.stdin.setEncoding('utf8'); + const rl = readline.createInterface({ + input: process.stdin + }); + out.write(JSON.stringify({ "ok": true }) + "\n"); + for await (const line of rl) { + try { + let args = JSON.parse(line) + let value = args.value || {} + for (let key in args) { + if (key !== "value") { + let envar = "__OW_" + key.toUpperCase() + process.env[envar] = args[key] + } + } + let result = await runner.run(value).then(result => { + if (typeof result !== 'object') { + console.error(`Result must be of type object but has type "${typeof result}":`, result); + } + writeMarkers(); + return result; + }); + + out.write(JSON.stringify(result) + "\n"); + } catch (err) { + console.log(err); + let message = err.message || err.toString() + let error = { "error": message } + writeMarkers(); + out.write(JSON.stringify(error) + "\n"); + } + } + } + actionLoop() +} catch (e) { + console.log(e) + process.exit(1) +} + +function writeMarkers() { + console.log('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX'); + console.error('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX'); +} diff --git a/core/nodejsActionBase/platform/knative.js b/core/nodejsActionBase/platform/knative.js deleted file mode 100644 index d0dbdb0b..00000000 --- a/core/nodejsActionBase/platform/knative.js +++ /dev/null @@ -1,514 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -const OW_ENV_PREFIX = "__OW_"; -const CONTENT_TYPE = "Content-Type"; - -/** - * Determine if runtime is a "stem" cell, i.e., can be initialized with request init. data - * @param env - * @returns {boolean} - */ -function isStemCell(env) { - let actionCode = env.__OW_ACTION_CODE; - // It is a stem cell if valid code is "built into" the runtime's process environment. - return (typeof actionCode === 'undefined' || actionCode.length === 0); -} - -/** - * Determine if the request (body) contains valid activation data. - * @param req - * @returns {boolean} - */ -function hasActivationData(req) { - // it is a valid activation if the body contains an activation and value keys with data. - if (typeof req.body !== "undefined" && - typeof req.body.activation !== "undefined" && - typeof req.body.value !== "undefined") { - return true; - } - return false; -} - -/** - * Determine if the request (body) contains valid init data. - * @param req - * @returns {boolean} - */ -function hasInitData(req) { - // it is a valid init. if the body contains an init key with data. - if (typeof req.body !== "undefined" && - typeof req.body.init !== "undefined") { - return true; - } - return false; -} - - -/** - * Remove all INIT data from the value data that will be passed to the user function. - * @param body - */ -function removeInitData(body) { - - if (typeof body !== "undefined" && - typeof body.value !== "undefined") { - delete body.value.code; - delete body.value.main; - delete body.value.binary; - delete body.value.raw; - } -} - - -/** - * Create request init data from the process environment - */ -function createInitDataFromEnvironment(env) { - try { - var initdata = {}; - initdata.main = (typeof env.__OW_ACTION_MAIN === 'undefined') ? "main" : env.__OW_ACTION_MAIN; - // TODO: Throw error if CODE is NOT defined! - initdata.code = (typeof env.__OW_ACTION_CODE === 'undefined') ? "" : env.__OW_ACTION_CODE; - initdata.binary = (typeof env.__OW_ACTION_BINARY === 'undefined') ? false : env.__OW_ACTION_BINARY.toLowerCase() === "true"; - // TODO: default to empty? - initdata.actionName = (typeof env.__OW_ACTION_NAME === 'undefined') ? "" : env.__OW_ACTION_NAME; - initdata.raw = (typeof env.__OW_ACTION_RAW === 'undefined') ? false : env.__OW_ACTION_RAW.toLowerCase() === "true"; - - return initdata; - - } catch(e){ - console.error(e); - throw("Unable to process Initialization data: " + e.message); - } -} - - -/** - * Pre-process the init data from the request - */ -function preProcessInitData(initdata, valuedata, activationdata) { - try { - // Look for init data within the request (i.e., "stem cell" runtime, where code is injected by request) - if (typeof(initdata) !== "undefined") { - - if (initdata.main && typeof initdata.main === 'string') { - valuedata.main = initdata.main; - } - if (initdata.code && typeof initdata.code === 'string') { - valuedata.code = initdata.code; - } - if (initdata.binary) { - if (typeof initdata.binary === 'boolean') { - valuedata.binary = initdata.binary; - } else { - throw ("Invalid Init. data; expected boolean for key 'binary'."); - } - } - if (initdata.raw) { - if (typeof initdata.raw === 'boolean') { - valuedata.raw = initdata.raw; - } else { - throw ("Invalid Init. data; expected boolean for key 'raw'."); - } - } - - // Action name is a special case, as we have a key collision on "name" between init. data and request - // param. data (as they both appear within "body.value") so we must save it to its final location - // as the default Action name as part of the activation data - if (initdata.name && typeof initdata.name === 'string') { - if (typeof (activationdata) !== "undefined") { - if (typeof (activationdata.action_name) === "undefined" || - (typeof (activationdata.action_name) === "string" && - activationdata.action_name.length === 0)) { - activationdata.action_name = initdata.name; - } - } - } - } - - } catch(e){ - console.error(e); - throw("Unable to process Initialization data: " + e.message); - } -} - -/** - * Pre-process HTTP request information and make it available as parameter data to the action function - * by moving it to where the route handlers expect it to be (i.e., in the JSON value data map). - * - * See: https://github.com/apache/openwhisk/blob/master/docs/webactions.md#http-context - * - * HTTP Context - * ============ - * All web actions, when invoked, receives additional HTTP request details as parameters to the action - * input argument. These include: - * - * __ow_method (type: string): the HTTP method of the request. - * __ow_headers (type: map string to string): the request headers. - * __ow_path (type: string): the unmatched path of the request (matching stops after consuming the action extension). - * __ow_user (type: string): the namespace identifying the OpenWhisk authenticated subject. - * __ow_body (type: string): the request body entity, as a base64 encoded string when content is - * binary or JSON object/array, or plain string otherwise. - * __ow_query (type: string): the query parameters from the request as an unparsed string. - * - * TODO: - * A request may not override any of the named __ow_ parameters above; doing so will result in a - * failed request with status equal to 400 Bad Request. - */ -function preProcessHTTPContext(req, valueData) { - try { - if (valueData.raw) { - // __ow_body is a base64 encoded string when content is binary or JSON object/array, - // or plain string otherwise. - if (typeof req.body.value === "string" && req.body.value !== undefined) { - valueData.__ow_body = req.body.value; - } else { - // make value data available as __ow_body - const tmpBody = Object.assign({}, req.body.value); - // delete main, binary, raw, and code from the body before sending it as an action argument - removeInitData(tmpBody); - delete tmpBody.main; - delete tmpBody.code; - delete tmpBody.binary; - delete tmpBody.raw; - var bodyStr = JSON.stringify(tmpBody); - // note: we produce an empty map if there are no query parms/ - valueData.__ow_body = Buffer.from(bodyStr).toString("base64");; - } - valueData.__ow_query = req.query; - } - - var namespace = ""; - if (process.env[OW_ENV_PREFIX + "NAMESPACE"] !== undefined) { - namespace = process.env[OW_ENV_PREFIX + "NAMESPACE"]; - } - valueData.__ow_user = namespace; - valueData.__ow_method = req.method; - valueData.__ow_headers = req.headers; - valueData.__ow_path = ""; - } catch (e) { - console.error(e); - throw ("Unable to process HTTP Context: " + e.message) - } -} - -/** - * Pre-process the incoming http request data, moving it to where the - * route handlers expect it to be for an openwhisk runtime. - */ -function preProcessActivationData(env, activationdata) { - try { - // Note: we move the values here so that the "run()" handler does not have - // to move them again. - Object.keys(activationdata).forEach( - function (k) { - if (typeof activationdata[k] === 'string') { - var envVariable = OW_ENV_PREFIX + k.toUpperCase(); - process.env[envVariable] = activationdata[k]; - } - } - ); - } catch(e){ - console.error(e); - throw("Unable to process Activation data: " + e.message); - } -} - -/** - * Pre-process the incoming http request data, moving it to where the - * route handlers expect it to be for an openwhisk runtime. - */ -function preProcessRequest(req){ - try { - let env = process.env || {}; - - // Get or create valid references to the various data we might encounter - // in a request such as Init., Activation and function parameter data. - let body = req.body || {}; - let valueData = body.value || {}; - let initData = body.init || {}; - let activationData = body.activation || {}; - - // process initialization (i.e., "init") data - if (hasInitData(req)) { - preProcessInitData(initData, valueData, activationData); - } - - if(hasActivationData(req)) { - // process HTTP request header and body to make it available to function as parameter data - preProcessHTTPContext(req, valueData); - - // process per-activation (i.e, "run") data - preProcessActivationData(env, activationData); - } - - // Fix up pointers in case we had to allocate new maps - req.body = body; - req.body.value = valueData; - req.body.init = initData; - req.body.activation = activationData; - - } catch(e){ - console.error(e); - // TODO: test this error is handled properly and results in an HTTP error response - throw("Unable to process request data: " + e.message); - } -} - -function postProcessResponse(req, result, res) { - - var content_types = { - json: 'application/json', - html: 'text/html', - png: 'image/png', - svg: 'image/svg+xml', - }; - - // After getting the result back from an action, update the HTTP headers, - // status code, and body based on its result if it includes one or more of the - // following as top level JSON properties: headers, statusCode, body - let statusCode = result.code; - let headers = {}; - let body = result.response; - let contentTypeInHeader = false; - - // statusCode: default is 200 OK if body is not empty otherwise 204 No Content - if (result.response.statusCode !== undefined) { - statusCode = result.response.statusCode; - delete body['statusCode']; - } - - // the default content-type for an HTTP response is application/json - // this default are overwritten with the action specified headers - if (result.response.headers !== undefined) { - headers = result.response.headers; - delete body['headers']; - } - - // addressing content-type v/s Content-Type - // marking 'Content-Type' as standard inside header - if (headers.hasOwnProperty(CONTENT_TYPE.toLowerCase())) { - headers[CONTENT_TYPE] = headers[CONTENT_TYPE.toLowerCase()]; - delete headers[CONTENT_TYPE.toLowerCase()]; - } - - // If a content-type header is not declared in the action result’s headers, - // the body is interpreted as application/json for non-string values, - // and text/html otherwise. - if (!headers.hasOwnProperty(CONTENT_TYPE)) { - if (result.response.body !== undefined && typeof result.response.body == "string") { - headers[CONTENT_TYPE] = content_types.html; - } else { - headers[CONTENT_TYPE] = content_types.json; - } - } else { - contentTypeInHeader = true; - } - - - // body: a string which is either a plain text, JSON object, or a base64 encoded string for binary data (default is "") - // body is considered empty if it is null, "", or undefined - if (result.response.body !== undefined) { - body = result.response.body; - delete body['main']; - delete body['code']; - delete body['binary']; - } - - // When the content-type is defined, check if the response is binary data or - // plain text and decode the plain text using a base64 decoder whenever needed. - // Should the body fail to decoded correctly, return an error to the caller. - if (contentTypeInHeader && headers[CONTENT_TYPE].lastIndexOf("image", 0) === 0) { - if (typeof body === "string") { - body = Buffer.from(body, 'base64') - headers["Content-Transfer-Encoding"] = "binary"; - } - // TODO: throw an error if body can not be decoded - } - - - // statusCode: set it to 204 No Content if body is empty - if (statusCode === 200 && body === "") { - statusCode = 204; - } - - if (!headers.hasOwnProperty('Access-Control-Allow-Origin')) { - headers['Access-Control-Allow-Origin'] = '*'; - } - if (!headers.hasOwnProperty('Access-Control-Allow-Methods')) { - headers['Access-Control-Allow-Methods'] = 'OPTIONS, GET, DELETE, POST, PUT, HEAD, PATCH'; - } - // the header Access-Control-Request-Headers is echoed back as the header Access-Control-Allow-Headers if it is present in the HTTP request. - // Otherwise, a default value is generated. - if (!headers.hasOwnProperty['Access-Control-Allow-Headers']) { - headers['Access-Control-Allow-Headers'] = 'Authorization, Origin, X - Requested - With, Content - Type, Accept, User - Agent'; - if (typeof req.headers['Access-Control-Request-Headers'] !== "undefined") { - headers['Access-Control-Allow-Headers'] = req.headers['Access-Control-Request-Headers']; - } - } - - res.header(headers).status(statusCode).send(body); -} - -function PlatformKnativeImpl(platformFactory) { - - var http_method = { - get: 'GET', - post: 'POST', - put: 'PUT', - delete: 'DELETE', - options: 'OPTIONS', - }; - - const DEFAULT_METHOD = [ 'POST' ]; - - // Provide access to common runtime services - var service = platformFactory.service; - - // TODO: Should we use app.WrapEndpoint()? - this.run = function(req, res) { - - try { - - // Do not process requests with init. data if this is not a "stem" cell - if (hasInitData(req) && !isStemCell(process.env)) - throw ("Cannot initialize a runtime with a dedicated function."); - - // If this is a dedicated, uninitialized runtime, then copy INIT data from env. into the request - if( !isStemCell(process.env) && !service.initialized()){ - let body = req.body || {}; - body.init = createInitDataFromEnvironment(process.env); - } - - // Different pre-processing logic based upon request data needed due Promise behavior - if(hasInitData(req) && hasActivationData(req)){ - // Request has both Init and Run (activation) data - preProcessRequest(req); - // Invoke the OW "init" entrypoint - service.initCode(req).then(function () { - // delete any INIT data (e.g., code, raw, etc.) from the 'value' data before calling run(). - removeInitData(req.body); - // Invoke the OW "run" entrypoint - service.runCode(req).then(function (result) { - postProcessResponse(req, result, res) - }); - }).catch(function (error) { - console.error(error); - if (typeof error.code === "number" && typeof error.response !== "undefined") { - res.status(error.code).json(error.response); - } else { - console.error("[wrapEndpoint]", "invalid errored promise", JSON.stringify(error)); - res.status(500).json({ error: "Internal error during function execution." }); - } - }); - } else if(hasInitData(req)){ - // Request has ONLY Init data - preProcessRequest(req); - // Invoke the OW "init" entrypoint - service.initCode(req).then(function (result) { - res.status(result.code).send(result.response); - }).catch(function (error) { - console.error(error); - if (typeof error.code === "number" && typeof error.response !== "undefined") { - res.status(error.code).json(error.response); - } else { - console.error("[wrapEndpoint]", "invalid errored promise", JSON.stringify(error)); - res.status(500).json({ error: "Internal error during function execution." }); - } - }); - } else if(hasActivationData(req)){ - // Request has ONLY Run (activation) data - preProcessRequest(req); - // Invoke the OW "run" entrypoint - service.runCode(req).then(function (result) { - postProcessResponse(req, result, res) - }).catch(function (error) { - console.error(error); - if (typeof error.code === "number" && typeof error.response !== "undefined") { - res.status(error.code).json(error.response); - } else { - console.error("[wrapEndpoint]", "invalid errored promise", JSON.stringify(error)); - res.status(500).json({ error: "Internal error during function execution." }); - } - }); - } else { - preProcessRequest(req); - // Invoke the OW "run" entrypoint - service.runCode(req).then(function (result) { - postProcessResponse(req, result, res) - }).catch(function (error) { - console.error(error); - if (typeof error.code === "number" && typeof error.response !== "undefined") { - res.status(error.code).json(error.response); - } else { - console.error("[wrapEndpoint]", "invalid errored promise", JSON.stringify(error)); - res.status(500).json({ error: "Internal error during function execution." }); - } - }); - } - } catch (e) { - res.status(500).json({error: "internal error during request processing."}) - } - }; - - // TODO: the 'httpMethods' var should not alternatively store string and string[] types - this.registerHandlers = function(app, platform) { - var httpMethods = process.env.__OW_HTTP_METHODS; - // default to "[post]" HTTP method if not defined - if (typeof httpMethods === "undefined") { - console.error("__OW_HTTP_METHODS is undefined; defaulting to '[post]' ..."); - httpMethods = DEFAULT_METHOD; - } else { - if (httpMethods.startsWith('[') && httpMethods.endsWith(']')) { - httpMethods = httpMethods.substr(1, httpMethods.length); - httpMethods = httpMethods.substr(0, httpMethods.length -1); - httpMethods = httpMethods.split(','); - } - } - // default to "[post]" HTTP method if specified methods are not valid - if (!Array.isArray(httpMethods) || !Array.length) { - console.error("__OW_HTTP_METHODS is undefined; defaulting to '[post]' ..."); - httpMethods = DEFAULT_METHOD; - } - - httpMethods.forEach(function (method) { - switch (method.toUpperCase()) { - case http_method.get: - app.get('/', platform.run); - break; - case http_method.post: - app.post('/', platform.run); - break; - case http_method.put: - app.put('/', platform.run); - break; - case http_method.delete: - app.delete('/', platform.run); - break; - case http_method.options: - app.options('/', platform.run); - break; - default: - console.error("Environment variable '__OW_HTTP_METHODS' has an unrecognized value (" + method + ")."); - } - }); - }; -} - -module.exports = PlatformKnativeImpl; diff --git a/core/nodejsActionBase/platform/openwhisk.js b/core/nodejsActionBase/platform/openwhisk.js deleted file mode 100644 index eefed16a..00000000 --- a/core/nodejsActionBase/platform/openwhisk.js +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -function PlatformOpenWhiskImpl(platformFactory) { - // Provide access to common runtime services - var service = platformFactory.service; - - this.registerHandlers = function(app, platform) { - app.post('/init', platformFactory.wrapEndpoint(service.initCode)); - app.post('/run', platformFactory.wrapEndpoint(service.runCode)); - }; -} - -module.exports = PlatformOpenWhiskImpl; diff --git a/core/nodejsActionBase/platform/platform.js b/core/nodejsActionBase/platform/platform.js deleted file mode 100644 index 1196ccce..00000000 --- a/core/nodejsActionBase/platform/platform.js +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Runtime platform factory - * - * This module is a NodeJS compatible version of a factory that will - * produce an implementation module provides OpenWhisk Language - * Runtime functionality and is able to register endpoints/handlers - * allowing to host OpenWhisk Actions and process OpenWhisk Activations. - */ - - -// Export supported platform impls. -const PLATFORM_OPENWHISK = 'openwhisk'; -const PLATFORM_KNATIVE = 'knative'; - -const SUPPORTED_PLATFORMS = [ - PLATFORM_OPENWHISK, - PLATFORM_KNATIVE -]; - -module.exports = class PlatformFactory { - - /** - * Object constructor - * @param app NodeJS express application instance - * @param cfg Runtime configuration - * @@param svc Runtime services (default handlers) - */ - constructor (app, cfg, svc) { - this._app = app; - this._service = svc; - this._config = cfg; - } - - /** - * @returns {string[]} List of supported platforms by their string ID - */ - static get SUPPORTED_PLATFORMS() { - return SUPPORTED_PLATFORMS; - } - - static get PLATFORM_OPENWHISK() { - return PLATFORM_OPENWHISK; - } - - static get PLATFORM_KNATIVE() { - return PLATFORM_KNATIVE; - } - - get app(){ - return this._app; - } - - get service(){ - return this._service; - } - - get config(){ - return this._config; - } - - /** - * validate if a platform ID is a known, supported value - * @param id Platform Id - */ - static isSupportedPlatform(id) { - if (SUPPORTED_PLATFORMS.indexOf(id) > -1) { - return true; - } - return false; - } - - /** - * Instantiate a platform implementation - * @param id Platform ID - * @returns {PlatformImpl} Platform instance (interface), as best can be done with NodeJS - */ - createPlatformImpl(id) { - // Load the appropriate implementation module and return reference to it - switch (id.toLowerCase()) { - case PLATFORM_KNATIVE: - const knPlatformImpl = require('./knative.js'); - this._platformImpl = new knPlatformImpl(this); - break; - case PLATFORM_OPENWHISK: - const owPlatformImpl = require('./openwhisk.js'); - this._platformImpl = new owPlatformImpl(this); - break; - default: - console.error("Platform ID is not a known value (" + id + ")."); - } - return this._platformImpl; - } - - /** - * Wraps an endpoint written to return a Promise into an express endpoint, - * producing the appropriate HTTP response and closing it for all controllable - * failure modes. - * - * The expected signature for the promise value (both completed and failed) - * is { code: int, response: object }. - * - * @param ep a request=>promise function - * @returns an express endpoint handler - */ - wrapEndpoint(ep) { - return function (req, res) { - try { - ep(req).then(function (result) { - res.status(result.code).json(result.response); - }).catch(function (error) { - if (typeof error.code === "number" && typeof error.response !== "undefined") { - res.status(error.code).json(error.response); - } else { - console.error("[wrapEndpoint]", "invalid errored promise", JSON.stringify(error)); - res.status(500).json({ error: "Internal error." }); - } - }); - } catch (e) { - // This should not happen, as the contract for the endpoints is to - // never (externally) throw, and wrap failures in the promise instead, - // but, as they say, better safe than sorry. - console.error("[wrapEndpoint]", "exception caught", e.message); - res.status(500).json({ error: "Internal error (exception)." }); - } - } - } -}; diff --git a/core/nodejsActionBase/src/service.js b/core/nodejsActionBase/src/service.js deleted file mode 100644 index 7f8dc942..00000000 --- a/core/nodejsActionBase/src/service.js +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const { initializeActionHandler, NodeActionRunner } = require('../runner'); -const NodeActionLambdaRunner = (() => { - try { - let lambda = require('../lambda'); - return lambda; - } catch (e) {} -})(); - -function NodeActionService(config) { - - const Status = { - ready: 'ready', - starting: 'starting', - running: 'running', - stopped: 'stopped', - }; - - const ignoreRunStatus = config.allowConcurrent === undefined ? false : config.allowConcurrent.toLowerCase() === 'true'; - const lambdaCompat = config.lambdaCompat === undefined ? false : config.lambdaCompat.toLowerCase() === 'true' && NodeActionLambdaRunner !== undefined; - - let status = Status.ready; - let server = undefined; - let userCodeRunner = undefined; - - function setStatus(newStatus) { - if (status !== Status.stopped) { - status = newStatus; - } - } - - /** - * An ad-hoc format for the endpoints returning a Promise representing, - * eventually, an HTTP response. - * - * The promised values (whether successful or not) have the form: - * { code: int, response: object } - * - */ - function responseMessage(code, response) { - return { code: code, response: response }; - } - - function errorMessage(code, errorMsg) { - return responseMessage(code, { error: errorMsg }); - } - - /** - * Indicates if we have been initialized which is determined by if we have - * created a NodeActionRunner. - * @returns {boolean} - */ - this.initialized = function isInitialized(){ - return (typeof userCodeRunner !== 'undefined'); - }; - - /** - * Starts the server. - * - * @param app express app - */ - this.start = function start(app) { - server = app.listen(config.port, function() { - var host = server.address().address; - var port = server.address().port; - }); - - // This is required as http server will auto disconnect in 2 minutes, this to not auto disconnect at all - server.timeout = 0; - }; - - /** Returns a promise of a response to the /init invocation. - * - * req.body = { main: String, code: String, binary: Boolean } - */ - this.initCode = function initCode(req) { - if (status === Status.ready && userCodeRunner === undefined) { - setStatus(Status.starting); - - let body = req.body || {}; - let message = body.value || {}; - - if (message.main && message.code && typeof message.main === 'string' && typeof message.code === 'string') { - return doInit(message).then(_ => { - setStatus(Status.ready); - return responseMessage(200, { OK: true }); - }).catch(error => { - setStatus(Status.stopped); - let errStr = `Initialization has failed due to: ${error.stack ? String(error.stack) : error}`; - return Promise.reject(errorMessage(502, errStr)); - }); - } else { - setStatus(Status.ready); - let msg = 'Missing main/no code to execute.'; - return Promise.reject(errorMessage(403, msg)); - } - } else if (userCodeRunner !== undefined) { - let msg = 'Cannot initialize the action more than once.'; - console.error('Internal system error:', msg); - return Promise.reject(errorMessage(403, msg)); - } else { - let msg = `System not ready, status is ${status}.`; - console.error('Internal system error:', msg); - return Promise.reject(errorMessage(403, msg)); - } - }; - - /** - * Returns a promise of a response to the /exec invocation. - * Note that the promise is failed if and only if there was an unhandled error - * (the user code threw an exception, or our proxy had an internal error). - * Actions returning { error: ... } are modeled as a Promise successful resolution. - * - * req.body = { value: Object, meta { activationId : int } } - */ - this.runCode = function runCode(req) { - if (status === Status.ready && userCodeRunner !== undefined) { - if (!ignoreRunStatus) { - setStatus(Status.running); - } - - // these are defensive checks against the expected interface invariants - let msg = req && req.body || {}; - if (msg.value === null || msg.value === undefined) { - msg.value = {}; - } else if (typeof msg.value !== 'object') { - let errStr = `Internal system error: the argument must be a dictionary but has type '${typeof msg.value}'.`; - console.error('Internal system error:', errStr); - return Promise.reject(errorMessage(403, errStr)); - } - - return doRun(msg).then(result => { - if (!ignoreRunStatus) { - setStatus(Status.ready); - } - if (typeof result !== 'object') { - return errorMessage(502, 'The action did not return a dictionary.'); - } else { - return responseMessage(200, result); - } - }).catch(error => { - let msg = `An error has occurred: ${error}`; - setStatus(Status.stopped); - return Promise.reject(errorMessage(502, msg)); - }); - } else { - let msg = userCodeRunner ? `System not ready, status is ${status}.` : 'System not initialized.'; - console.error('Internal system error:', msg); - return Promise.reject(errorMessage(403, msg)); - } - }; - - function doInit(message) { - if (message.env && typeof message.env == 'object') { - Object.keys(message.env).forEach(k => { - let val = message.env[k]; - if (typeof val !== 'object' || val == null) { - process.env[k] = val ? val.toString() : ""; - } else { - process.env[k] = JSON.stringify(val); - } - }); - } - - return initializeActionHandler(message) - .then(handler => { - userCodeRunner = lambdaCompat === false ? new NodeActionRunner(handler) : new NodeActionLambdaRunner(handler); - }) - // emit error to activation log then flush the logs as this is the end of the activation - .catch(error => { - console.error('Error during initialization:', error); - writeMarkers(); - return Promise.reject(error); - }); - } - - function doRun(msg) { - // Move per-activation keys to process env. vars with __OW_ (reserved) prefix - Object.keys(msg).forEach(k => { - if (typeof msg[k] === 'string' && k !== 'value') { - let envVariable = '__OW_' + k.toUpperCase(); - process.env[envVariable] = msg[k]; - } - }); - - return userCodeRunner - .run(msg.value) - .then(result => { - if (typeof result !== 'object') { - console.error(`Result must be of type object but has type "${typeof result}":`, result); - } - writeMarkers(); - return result; - }).catch(error => { - console.error(error); - writeMarkers(); - return Promise.reject(error); - }); - } - - function writeMarkers() { - console.log('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX'); - console.error('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX'); - } -} - -NodeActionService.getService = config => new NodeActionService(config); - -module.exports = NodeActionService; diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala index bb781808..507e47f5 100644 --- a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala +++ b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala @@ -177,10 +177,6 @@ abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with Ws initCode should be(200) val (runCode, runRes) = c.run(runPayload(JsObject())) - // actionloop proxy does not return a different error code when there is an error, - // because it communicates only through json - if (!isTypeScript) - runCode should not be (200) runRes shouldBe defined runRes.get.fields.get("error") shouldBe defined @@ -407,10 +403,7 @@ abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with Ws val (runCode, out) = c.run(runPayload(JsObject())) - if (isTypeScript) - out.get.fields should contain key ("error") - else - runCode should not be (200) + out.get.fields should contain key ("error") } @@ -754,7 +747,6 @@ abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with Ws checkStreams(out, err, { case (o, e) => - (o + e).toLowerCase should include regex ("error|exited") (o + e).toLowerCase should include("zipped actions must contain either package.json or index.js at the root.") }) } From b6be08db52a4accf27217e70cfa47fda30c86b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Fri, 13 May 2022 15:02:32 +0200 Subject: [PATCH 10/29] SERVERLESS-1377 Make the Node.js 14 runtime prelaunchable (#4) * SERVERLESS-1377 Make the Node.js 14 runtime prelaunchable This instructs the go-proxy to launch the new prelauncher.js script on its startup, amortizing the cost of doing so into the container bringup vs. the action initialization. The script deals with initializing the action itself making it blazingly quick especially for very simple actions that are just some lines of Javascript. * Remove redundant error --- core/nodejs14Action/Dockerfile | 2 + core/nodejsActionBase/prelauncher.js | 107 +++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100755 core/nodejsActionBase/prelauncher.js diff --git a/core/nodejs14Action/Dockerfile b/core/nodejs14Action/Dockerfile index de904121..e7674e8a 100644 --- a/core/nodejs14Action/Dockerfile +++ b/core/nodejs14Action/Dockerfile @@ -77,4 +77,6 @@ ENV OW_LOG_INIT_ERROR=1 # the launcher must wait for an ack ENV OW_WAIT_FOR_ACK=1 +ENV OW_INIT_IN_ACTIONLOOP=/nodejsAction/prelauncher.js + ENTRYPOINT [ "/bin/proxy" ] diff --git a/core/nodejsActionBase/prelauncher.js b/core/nodejsActionBase/prelauncher.js new file mode 100755 index 00000000..39705a0f --- /dev/null +++ b/core/nodejsActionBase/prelauncher.js @@ -0,0 +1,107 @@ +#!/usr/local/bin/node + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +try { + const readline = require('readline'); + const fs = require("fs") + + const { NodeActionRunner, initializeActionHandler } = require('/nodejsAction/runner'); + const NodeActionLambdaRunner = (() => { + try { + let lambda = require('/nodejsAction/lambda'); + return lambda; + } catch (e) {} + })(); + + const lambdaCompat = process.env.__OW_LAMBDA_COMPAT === undefined ? false : process.env.__OW_LAMBDA_COMPAT.toLowerCase() === 'true' && NodeActionLambdaRunner !== undefined; + + function doInit(message) { + if (message.env && typeof message.env == 'object') { + Object.keys(message.env).forEach(k => { + let val = message.env[k]; + if (typeof val !== 'object' || val == null) { + process.env[k] = val ? val.toString() : ""; + } else { + process.env[k] = JSON.stringify(val); + } + }); + } + + return initializeActionHandler(message) + .then(handler => { + return lambdaCompat === false ? new NodeActionRunner(handler) : new NodeActionLambdaRunner(handler); + }); + } + + async function actionLoop() { + let initialized = false + let runner = null + + const out = fs.createWriteStream(null,{fd: 3, encoding: "utf8"}) + process.stdin.setEncoding('utf8'); + const rl = readline.createInterface({input: process.stdin}); + out.write(JSON.stringify({ "ok": true }) + "\n"); + + for await (const line of rl) { + try { + let args = JSON.parse(line) + let value = args.value || {} + + if (!initialized) { + // The first value sent through is the actual init. + runner = await doInit(value) + initialized = true + out.write(JSON.stringify({ "ok": true }) + "\n"); + continue; + } + + for (let key in args) { + if (key !== "value") { + let envar = "__OW_" + key.toUpperCase() + process.env[envar] = args[key] + } + } + let result = await runner.run(value).then(result => { + if (typeof result !== 'object') { + console.error(`Result must be of type object but has type "${typeof result}":`, result); + } + writeMarkers(); + return result; + }); + + out.write(JSON.stringify(result) + "\n"); + } catch (err) { + console.log(err); + let message = err.message || err.toString() + let error = { "error": message } + writeMarkers(); + out.write(JSON.stringify(error) + "\n"); + } + } + } + actionLoop() +} catch (e) { + console.log(e) + process.exit(1) +} + +function writeMarkers() { + console.log('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX'); + console.error('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX'); +} From 79a0c09424136d20bf897618a230ddb941fd3299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Wed, 25 May 2022 08:53:11 +0200 Subject: [PATCH 11/29] Update Node.js and Golang versions to more recent ones (#5) 1. The Golang version we're building the proxy with is ancient. 1.18 is the most recent and known to work. 2. The Node.js patch version is unnecessarily pinned. We can update to 14.19.3. --- core/nodejs14Action/Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/nodejs14Action/Dockerfile b/core/nodejs14Action/Dockerfile index e7674e8a..cf8fdffe 100644 --- a/core/nodejs14Action/Dockerfile +++ b/core/nodejs14Action/Dockerfile @@ -16,7 +16,8 @@ # # build go proxy from source -FROM golang:1.15 AS builder_source +ARG GO_PROXY_BASE_IMAGE=golang:1.18 +FROM $GO_PROXY_BASE_IMAGE AS builder_source ARG GO_PROXY_GITHUB_USER=nimbella-corp ARG GO_PROXY_GITHUB_BRANCH=dev RUN git clone --branch ${GO_PROXY_GITHUB_BRANCH} \ @@ -25,7 +26,7 @@ RUN git clone --branch ${GO_PROXY_GITHUB_BRANCH} \ mv proxy /bin/proxy # or build it from a release -FROM golang:1.15 AS builder_release +FROM $GO_PROXY_BASE_IMAGE AS builder_release ARG GO_PROXY_RELEASE_VERSION=1.15@1.17.0 RUN curl -sL \ https://github.com/apache/openwhisk-runtime-go/archive/{$GO_PROXY_RELEASE_VERSION}.tar.gz\ @@ -33,7 +34,7 @@ RUN curl -sL \ && cd openwhisk-runtime-go-*/main\ && GO111MODULE=on go build -o /bin/proxy -FROM node:14.15.4-stretch +FROM node:14-stretch # select the builder to use ARG GO_PROXY_BUILD_FROM=source From 49b433d8197238a8f7e9fd454e8c860cffa29f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Fri, 17 Jun 2022 14:11:05 +0200 Subject: [PATCH 12/29] Add a Node.js 18 runtime (#7) * Add a Node.js 18 runtime This adds Node.js 18 as a runtime and is a straight copy of the Node.js 14 runtime, with the pending size improvements already applied to it. * Drop nim.js --- core/nodejs18Action/.dockerignore | 13 ++++ core/nodejs18Action/Dockerfile | 71 +++++++++++++++++++ core/nodejs18Action/build.gradle | 66 +++++++++++++++++ .../NodeJs18ActionContainerTests.scala | 27 +++++++ 4 files changed, 177 insertions(+) create mode 100644 core/nodejs18Action/.dockerignore create mode 100644 core/nodejs18Action/Dockerfile create mode 100644 core/nodejs18Action/build.gradle create mode 100644 tests/src/test/scala/runtime/actionContainers/NodeJs18ActionContainerTests.scala diff --git a/core/nodejs18Action/.dockerignore b/core/nodejs18Action/.dockerignore new file mode 100644 index 00000000..a1d03cb9 --- /dev/null +++ b/core/nodejs18Action/.dockerignore @@ -0,0 +1,13 @@ +*.*~ +*.yaml +*.tmpl +*.gradle +.dockerignore +.project +.settings +build.xml +Dockerfile +logs +node_modules +package-lock.json +test.js diff --git a/core/nodejs18Action/Dockerfile b/core/nodejs18Action/Dockerfile new file mode 100644 index 00000000..1d2d7f1e --- /dev/null +++ b/core/nodejs18Action/Dockerfile @@ -0,0 +1,71 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# build go proxy from source +ARG GO_PROXY_BASE_IMAGE=golang:1.18 +FROM $GO_PROXY_BASE_IMAGE AS builder + +ARG GO_PROXY_GITHUB_USER=nimbella-corp +ARG GO_PROXY_GITHUB_BRANCH=dev +RUN git clone --branch ${GO_PROXY_GITHUB_BRANCH} https://github.com/${GO_PROXY_GITHUB_USER}/openwhisk-runtime-go /src \ + && cd /src \ + && env GO111MODULE=on CGO_ENABLED=0 go build -o /bin/proxy main/proxy.go + +FROM node:18-bullseye-slim + +# Initial update and some basics. +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + # For npm to work properly. + git \ + ssh \ + ca-certificates \ + # For the proxy. + unzip \ + # Dependencies for the users. + graphicsmagick \ + imagemagick \ + && update-ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Add sources and copy the package.json to root container, +# so npm packages from user functions take precendence. +WORKDIR /nodejsAction +COPY . /nodejsAction/ +COPY package.json / + +# Customize runtime with additional packages. +# Install package globally so user packages can override. +RUN cd / \ + && npm install --no-package-lock --omit=dev \ + && npm cache clean --force + +ARG __OW_LAMBDA_COMPAT +ENV __OW_LAMBDA_COMPAT=$__OW_LAMBDA_COMPAT + +COPY bin/compile /bin/compile +ENV OW_COMPILER=/bin/compile + +# log initialization errors +ENV OW_LOG_INIT_ERROR=1 +# the launcher must wait for an ack +ENV OW_WAIT_FOR_ACK=1 + +ENV OW_INIT_IN_ACTIONLOOP=/nodejsAction/prelauncher.js + +COPY --from=builder /bin/proxy /bin/proxy +ENTRYPOINT [ "/bin/proxy" ] \ No newline at end of file diff --git a/core/nodejs18Action/build.gradle b/core/nodejs18Action/build.gradle new file mode 100644 index 00000000..04b067a0 --- /dev/null +++ b/core/nodejs18Action/build.gradle @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'eclipse' +eclipse { + project { + natures 'org.eclipse.wst.jsdt.core.jsNature' + buildCommand 'org.eclipse.wst.jsdt.core.javascriptValidator' + } +} + +ext.dockerImageName = 'action-nodejs-v18' +apply from: '../../gradle/docker.gradle' + +distDocker.dependsOn 'copyPackageJson' +distDocker.dependsOn 'copyRunner' +distDocker.dependsOn 'copyCompile' +distDocker.finalizedBy('cleanup') + +task copyPackageJson(type: Copy) { + from '../nodejsActionBase/package.json' + into '.' +} + +task copyRunner(type: Copy) { + from '../nodejsActionBase/runner.js' + into '.' + + from '../nodejsActionBase/lambda.js' + into '.' + + from '../nodejsActionBase/nim.js' + into '.' + + from '../nodejsActionBase/launcher.js' + into '.' +} + +task copyCompile(type: Copy) { + from '../nodejsActionBase/bin/compile' + into './bin' +} + +task cleanup(type: Delete) { + delete 'package.json' + delete 'launcher.js' + delete 'lambda.js' + delete 'nim.js' + delete 'runner.js' + delete 'src' + delete 'bin' +} diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJs18ActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJs18ActionContainerTests.scala new file mode 100644 index 00000000..8271b60c --- /dev/null +++ b/tests/src/test/scala/runtime/actionContainers/NodeJs18ActionContainerTests.scala @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package runtime.actionContainers + +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class NodeJs18ActionContainerTests extends NodeJsActionContainerTests { + override lazy val nodejsContainerImageName = "action-nodejs-v18" + override lazy val nodejsTestDockerImageName = "nodejs18docker" +} From 4c84588312b0521021cd607bf5f788a5fccc9633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Thu, 11 Aug 2022 20:28:28 +0200 Subject: [PATCH 13/29] SERVERLESS-1563 Support ES modules as functions (#8) * SERVERLESS-1563 Support ES modules as functions This changes the runner to be able to import ES modules and CommonJS modules in a backwards compatible way so that both ES modules and CommonJS modules are supported as functions. * Flip ES module detection logic around --- core/nodejsActionBase/bin/compile | 4 +- core/nodejsActionBase/runner.js | 72 +++++++--- .../NodeJsActionContainerTests.scala | 126 +++++++++++++++++- 3 files changed, 179 insertions(+), 23 deletions(-) diff --git a/core/nodejsActionBase/bin/compile b/core/nodejsActionBase/bin/compile index 4cfe0825..206eafb4 100755 --- a/core/nodejsActionBase/bin/compile +++ b/core/nodejsActionBase/bin/compile @@ -57,8 +57,8 @@ def sources(launcher, source_dir, main): # part of package.json. parts = main.split(".", 1) if len(parts) == 1: - if not os.path.isfile("%s/index.js" % source_dir) and not os.path.isfile("%s/package.json" % source_dir): - print("Zipped actions must contain either package.json or index.js at the root.") + if not os.path.isfile("%s/index.js" % source_dir) and not os.path.isfile("%s/index.mjs" % source_dir) and not os.path.isfile("%s/package.json" % source_dir): + print("Zipped actions must contain either package.json or index.[m]js at the root.") sys.exit(1) main_file = "" diff --git a/core/nodejsActionBase/runner.js b/core/nodejsActionBase/runner.js index 43f758b7..596e90df 100644 --- a/core/nodejsActionBase/runner.js +++ b/core/nodejsActionBase/runner.js @@ -42,31 +42,63 @@ function initializeActionHandler(message) { // Set the executable directory to the project dir. process.chdir(moduleDir); - if (index === undefined && !fs.existsSync('package.json') && !fs.existsSync('index.js')) { - return Promise.reject('Zipped actions must contain either package.json or index.js at the root.'); + const packageJsonExists = fs.existsSync('package.json') + const indexJSExists = fs.existsSync('index.js') + const indexMJSExists = fs.existsSync('index.mjs') + if (index === undefined && !packageJsonExists && !indexJSExists && !indexMJSExists) { + return Promise.reject('Zipped actions must contain either package.json or index.[m]js at the root.'); + } + + let mainFile + if (index !== undefined) { + // Backwards compat: We allow for main definitions like: `file.a.b.c` + // where we'd import the function a.b.c from `file.[m]js`. + if (fs.existsSync(index + '.js')) { + mainFile = index + '.js' + } else if (fs.existsSync(index + '.mjs')) { + mainFile = index + '.mjs' + } + } + if (!mainFile && packageJsonExists) { + // Infer the main file from package.json by default. + let package = JSON.parse(fs.readFileSync('package.json')); + mainFile = package.main + } + if (!mainFile && indexMJSExists) { + mainFile = 'index.mjs' + } + if (!mainFile) { + mainFile = 'index.js' } // The module to require. - let whatToRequire = index !== undefined ? path.join(moduleDir, index) : moduleDir; - let handler = eval('require("' + whatToRequire + '").' + main); - return assertMainIsFunction(handler, message.main); + let handler = eval('import("' + path.join(moduleDir, mainFile) + '").then(evaled => evaled.' + main + ')'); + return handler.then(func => assertMainIsFunction(func, message.main)) }) .catch(error => Promise.reject(error)); - } else try { - let handler = eval( - `(function(){ - ${message.code} - try { - return ${message.main} - } catch (e) { - if (e.name === 'ReferenceError') { - return module.exports.${message.main} || exports.${message.main} - } else throw e - } - })()`); - return assertMainIsFunction(handler, message.main); - } catch (e) { - return Promise.reject(e); + } else { + return new Promise((resolve) => { + // Throws on error and rejects the promise as a consequence. + let handler = eval( + `(function(){ + ${message.code} + try { + return ${message.main} + } catch (e) { + if (e.name === 'ReferenceError') { + return module.exports.${message.main} || exports.${message.main} + } else throw e + } + })()`) + resolve(handler) + }) + .then(func => assertMainIsFunction(func, message.main)) + .catch(_ => { + // Write file as ES modules need to be loaded from files. + fs.writeFileSync('index.mjs', message.code) + return eval('import("' + process.cwd() + '/index.mjs").then(evaled => evaled.' + message.main + ')'); + }) + .then(func => assertMainIsFunction(func, message.main)) } } diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala index 507e47f5..27c2ab10 100644 --- a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala +++ b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala @@ -747,7 +747,7 @@ abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with Ws checkStreams(out, err, { case (o, e) => - (o + e).toLowerCase should include("zipped actions must contain either package.json or index.js at the root.") + (o + e).toLowerCase should include("zipped actions must contain either package.json or index.[m]js at the root.") }) } @@ -925,4 +925,128 @@ abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with Ws runRes.get.fields("error").toString.toLowerCase should include("error: app error") } } + + it should "have openwhisk package available through an ES module import" in { + val (out, err) = withNodeJsContainer { c => + val code = + """ + | import ow from 'openwhisk'; + | export function main(args) { + | return { "result": true }; + | } + """.stripMargin + + val (initCode, _) = c.init(initPayload(code)) + initCode should be(200) + + val (runCode, out) = c.run(runPayload(JsObject())) + runCode should be(200) + } + } + + it should "support zip-encoded ES module actions without a package.json file" in { + val srcs = Seq( + Seq("index.mjs") -> + """ + | export function main(args) { + | var name = typeof args["name"] === "string" ? args["name"] : "stranger"; + | + | return { + | greeting: "Hello " + name + ", from an ES module action without a package.json." + | }; + | } + | + """.stripMargin) + + val code = ZipBuilder.mkBase64Zip(srcs) + + val (out, err) = withNodeJsContainer { c => + c.init(initPayload(code))._1 should be(200) + + val (runCode, runRes) = c.run(runPayload(JsObject())) + + runCode should be(200) + runRes.get.fields.get("greeting") shouldBe Some( + JsString("Hello stranger, from an ES module action without a package.json.")) + } + } + + it should "support zip-encoded ES module with main from file other than index.mjs" in { + val srcs = Seq( + Seq("other.mjs") -> + """ + | export function niam(args) { + | var name = typeof args["name"] === "string" ? args["name"] : "stranger"; + | + | return { + | greeting: "Hello " + name + ", from other.niam." + | }; + | } + """.stripMargin) + + val code = ZipBuilder.mkBase64Zip(srcs) + + val (out, err) = withNodeJsContainer { c => + c.init(initPayload(code, "other.niam"))._1 should be(200) + + val (runCode, runRes) = c.run(runPayload(JsObject())) + runCode should be(200) + runRes.get.fields.get("greeting") shouldBe Some(JsString("Hello stranger, from other.niam.")) + } + + checkStreams(out, err, { + case (o, e) => + o shouldBe empty + e shouldBe empty + }) + } + + it should "support zip-encoded ES module with multiple js files, enabled through package.json" in { + val srcs = Seq( + Seq("package.json") -> + """ + | { + | "name": "wskaction", + | "version": "1.0.0", + | "description": "An OpenWhisk action as an npm package.", + | "main": "foo.js", + | "type": "module", + | "author": "info@openwhisk.org", + | "license": "Apache-2.0" + | } + """.stripMargin, + Seq("foo.js") -> + """ + | import {hello} from './bar.js'; + | export function main(args) { + | var name = typeof args["name"] === "string" ? args["name"] : "stranger"; + | + | return { + | greeting: hello(name) + | }; + | } + """.stripMargin, + Seq("bar.js") -> + """ + | export function hello(name) { + | return "Hello " + name + ", from module." + | } + """.stripMargin) + + val code = ZipBuilder.mkBase64Zip(srcs) + + val (out, err) = withNodeJsContainer { c => + c.init(initPayload(code))._1 should be(200) + + val (runCode, runRes) = c.run(runPayload(JsObject())) + runCode should be(200) + runRes.get.fields.get("greeting") shouldBe Some(JsString("Hello stranger, from module.")) + } + + checkStreams(out, err, { + case (o, e) => + o shouldBe empty + e shouldBe empty + }) + } } From 8975cda6d354599c51b74e554fe2a5a167fae431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Mon, 19 Sep 2022 11:08:19 +0200 Subject: [PATCH 14/29] Add python to Node.js 18 image (#9) The compile script needs python to work correctly. It's necessary for log shipping based use-cases. --- core/nodejs18Action/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/core/nodejs18Action/Dockerfile b/core/nodejs18Action/Dockerfile index 1d2d7f1e..6cae3fdc 100644 --- a/core/nodejs18Action/Dockerfile +++ b/core/nodejs18Action/Dockerfile @@ -36,6 +36,7 @@ RUN apt-get update \ ca-certificates \ # For the proxy. unzip \ + python \ # Dependencies for the users. graphicsmagick \ imagemagick \ From 9b3f4d66aa32d97f6a1a8e51e01474d870c91658 Mon Sep 17 00:00:00 2001 From: Joshua Auerbach Date: Sun, 30 Oct 2022 08:43:02 -0400 Subject: [PATCH 15/29] Include functions deployer in runtime image (#10) --- core/nodejs14Action/Dockerfile | 7 +++++++ core/nodejs18Action/Dockerfile | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/core/nodejs14Action/Dockerfile b/core/nodejs14Action/Dockerfile index cf8fdffe..0276dad2 100644 --- a/core/nodejs14Action/Dockerfile +++ b/core/nodejs14Action/Dockerfile @@ -63,6 +63,13 @@ RUN cd / && npm install --no-package-lock --production \ # move nim sdk to node modules directory so that it can be found by node module loader RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js +# install the functions-deployer (co-exist with nim temporarily) +ARG DEPLOYER_DOWNLOAD +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +RUN curl -L ${DEPLOYER_DOWNLOAD} | tar xzf - \ + && rm -fr /usr/local/lib/dosls && mv dosls /usr/local/lib \ + && rm -f /usr/local/bin/dosls && ln -s /usr/local/lib/dosls/bootstrap /usr/local/bin/dosls + ARG __OW_LAMBDA_COMPAT ENV __OW_LAMBDA_COMPAT=$__OW_LAMBDA_COMPAT diff --git a/core/nodejs18Action/Dockerfile b/core/nodejs18Action/Dockerfile index 6cae3fdc..f85ad78b 100644 --- a/core/nodejs18Action/Dockerfile +++ b/core/nodejs18Action/Dockerfile @@ -37,6 +37,8 @@ RUN apt-get update \ # For the proxy. unzip \ python \ + # For function-deployer install + curl \ # Dependencies for the users. graphicsmagick \ imagemagick \ @@ -55,6 +57,13 @@ RUN cd / \ && npm install --no-package-lock --omit=dev \ && npm cache clean --force +# install the functions-deployer (co-exist with nim temporarily) +ARG DEPLOYER_DOWNLOAD +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +RUN curl -L ${DEPLOYER_DOWNLOAD} | tar xzf - \ + && rm -fr /usr/local/lib/dosls && mv dosls /usr/local/lib \ + && rm -f /usr/local/bin/dosls && ln -s /usr/local/lib/dosls/bootstrap /usr/local/bin/dosls + ARG __OW_LAMBDA_COMPAT ENV __OW_LAMBDA_COMPAT=$__OW_LAMBDA_COMPAT From fb059f5ebb9b23a8978f4cfef2277cc0a99aa76b Mon Sep 17 00:00:00 2001 From: Matt Welke Date: Tue, 1 Nov 2022 12:41:28 -0400 Subject: [PATCH 16/29] Faster docker builds when sources change (#11) * Change Node 18 Dockerfile to install packages before copying in source files. * Re-arrange npm install step in Dockerfiles for faster subsequent builds. --- core/nodejs14Action/Dockerfile | 14 ++++++++------ core/nodejs18Action/Dockerfile | 7 +++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/core/nodejs14Action/Dockerfile b/core/nodejs14Action/Dockerfile index 0276dad2..77a0096b 100644 --- a/core/nodejs14Action/Dockerfile +++ b/core/nodejs14Action/Dockerfile @@ -47,18 +47,20 @@ RUN apt-get update && apt-get install -y \ unzip \ && rm -rf /var/lib/apt/lists/* -# Add sources and copy the package.json to root container, +# Copy the package.json to root container, # so npm packages from user functions take precendence. -# WORKDIR /nodejsAction -ADD . /nodejsAction/ COPY package.json / # Customize runtime with additional packages. # Install package globally so user packages can override. -# -RUN cd / && npm install --no-package-lock --production \ - && npm cache clean --force +RUN cd / \ + && npm install --no-package-lock --omit=dev \ + && npm cache clean --force + +# Copy sources in after copying in package.json and running npm install to +# enable faster builds after only sources change. +COPY . /nodejsAction/ # move nim sdk to node modules directory so that it can be found by node module loader RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js diff --git a/core/nodejs18Action/Dockerfile b/core/nodejs18Action/Dockerfile index f85ad78b..3f110efd 100644 --- a/core/nodejs18Action/Dockerfile +++ b/core/nodejs18Action/Dockerfile @@ -45,10 +45,9 @@ RUN apt-get update \ && update-ca-certificates \ && rm -rf /var/lib/apt/lists/* -# Add sources and copy the package.json to root container, +# Copy the package.json to root container, # so npm packages from user functions take precendence. WORKDIR /nodejsAction -COPY . /nodejsAction/ COPY package.json / # Customize runtime with additional packages. @@ -57,6 +56,10 @@ RUN cd / \ && npm install --no-package-lock --omit=dev \ && npm cache clean --force +# Copy sources in after copying in package.json and running npm install to +# enable faster builds after only sources change. +COPY . /nodejsAction/ + # install the functions-deployer (co-exist with nim temporarily) ARG DEPLOYER_DOWNLOAD SHELL ["/bin/bash", "-o", "pipefail", "-c"] From 0eb74b96e36b53281805ca4b1f413a0918df94c2 Mon Sep 17 00:00:00 2001 From: Joshua Auerbach Date: Thu, 10 Nov 2022 05:50:04 -0500 Subject: [PATCH 17/29] Clean up references to nim (#12) Comment changes and remove ancient support for nim.js. Removing nim completely from this runtime requires changing the dependency declaration in the main build for the runtime (TBD). --- core/nodejs14Action/Dockerfile | 5 +---- core/nodejs18Action/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/core/nodejs14Action/Dockerfile b/core/nodejs14Action/Dockerfile index 77a0096b..e56a715a 100644 --- a/core/nodejs14Action/Dockerfile +++ b/core/nodejs14Action/Dockerfile @@ -62,10 +62,7 @@ RUN cd / \ # enable faster builds after only sources change. COPY . /nodejsAction/ -# move nim sdk to node modules directory so that it can be found by node module loader -RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js - -# install the functions-deployer (co-exist with nim temporarily) +# install the functions-deployer ARG DEPLOYER_DOWNLOAD SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN curl -L ${DEPLOYER_DOWNLOAD} | tar xzf - \ diff --git a/core/nodejs18Action/Dockerfile b/core/nodejs18Action/Dockerfile index 3f110efd..3f0c0428 100644 --- a/core/nodejs18Action/Dockerfile +++ b/core/nodejs18Action/Dockerfile @@ -60,7 +60,7 @@ RUN cd / \ # enable faster builds after only sources change. COPY . /nodejsAction/ -# install the functions-deployer (co-exist with nim temporarily) +# install the functions-deployer ARG DEPLOYER_DOWNLOAD SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN curl -L ${DEPLOYER_DOWNLOAD} | tar xzf - \ From 0180d7a0c4a20520ba1b476da3eaf70ffb9ed9a9 Mon Sep 17 00:00:00 2001 From: Matt Welke Date: Mon, 28 Nov 2022 14:38:03 -0500 Subject: [PATCH 18/29] Remove unused Node.js runtimes. Can restore from Git history later if needed. (#15) --- core/cloudjs10Action/.dockerignore | 13 -- core/cloudjs10Action/Dockerfile | 52 ------ core/cloudjs10Action/build.gradle | 94 ---------- core/nodejs10Action/.dockerignore | 13 -- core/nodejs10Action/CHANGELOG.md | 53 ------ core/nodejs10Action/Dockerfile | 51 ------ core/nodejs10Action/build.gradle | 94 ---------- core/nodejs10Action/knative/Dockerfile | 38 ---- core/nodejs12Action/.dockerignore | 13 -- core/nodejs12Action/CHANGELOG.md | 54 ------ core/nodejs12Action/Dockerfile | 49 ------ core/nodejs12Action/build.gradle | 94 ---------- core/tessjs10Action/.dockerignore | 13 -- core/tessjs10Action/Dockerfile | 58 ------- core/tessjs10Action/build.gradle | 94 ---------- core/typescript37Action/.dockerignore | 13 -- core/typescript37Action/Dockerfile | 84 --------- core/typescript37Action/Makefile | 32 ---- core/typescript37Action/bin/compile | 162 ------------------ core/typescript37Action/build.gradle | 37 ---- core/typescript37Action/lib/launcher.ts | 100 ----------- .../NodeJs10ActionContainerTests.scala | 27 --- .../NodeJs10ConcurrentTests.scala | 27 --- .../NodeJs12ActionContainerTests.scala | 27 --- .../NodeJs12ConcurrentTests.scala | 27 --- .../Typescript37BasicTests.scala | 93 ---------- .../Typescript37CommonTests.scala | 29 ---- 27 files changed, 1441 deletions(-) delete mode 100644 core/cloudjs10Action/.dockerignore delete mode 100644 core/cloudjs10Action/Dockerfile delete mode 100644 core/cloudjs10Action/build.gradle delete mode 100644 core/nodejs10Action/.dockerignore delete mode 100644 core/nodejs10Action/CHANGELOG.md delete mode 100644 core/nodejs10Action/Dockerfile delete mode 100644 core/nodejs10Action/build.gradle delete mode 100644 core/nodejs10Action/knative/Dockerfile delete mode 100644 core/nodejs12Action/.dockerignore delete mode 100644 core/nodejs12Action/CHANGELOG.md delete mode 100644 core/nodejs12Action/Dockerfile delete mode 100644 core/nodejs12Action/build.gradle delete mode 100644 core/tessjs10Action/.dockerignore delete mode 100644 core/tessjs10Action/Dockerfile delete mode 100644 core/tessjs10Action/build.gradle delete mode 100644 core/typescript37Action/.dockerignore delete mode 100644 core/typescript37Action/Dockerfile delete mode 100644 core/typescript37Action/Makefile delete mode 100755 core/typescript37Action/bin/compile delete mode 100644 core/typescript37Action/build.gradle delete mode 100644 core/typescript37Action/lib/launcher.ts delete mode 100644 tests/src/test/scala/runtime/actionContainers/NodeJs10ActionContainerTests.scala delete mode 100644 tests/src/test/scala/runtime/actionContainers/NodeJs10ConcurrentTests.scala delete mode 100644 tests/src/test/scala/runtime/actionContainers/NodeJs12ActionContainerTests.scala delete mode 100644 tests/src/test/scala/runtime/actionContainers/NodeJs12ConcurrentTests.scala delete mode 100644 tests/src/test/scala/runtime/actionContainers/Typescript37BasicTests.scala delete mode 100644 tests/src/test/scala/runtime/actionContainers/Typescript37CommonTests.scala diff --git a/core/cloudjs10Action/.dockerignore b/core/cloudjs10Action/.dockerignore deleted file mode 100644 index a1d03cb9..00000000 --- a/core/cloudjs10Action/.dockerignore +++ /dev/null @@ -1,13 +0,0 @@ -*.*~ -*.yaml -*.tmpl -*.gradle -.dockerignore -.project -.settings -build.xml -Dockerfile -logs -node_modules -package-lock.json -test.js diff --git a/core/cloudjs10Action/Dockerfile b/core/cloudjs10Action/Dockerfile deleted file mode 100644 index 33595740..00000000 --- a/core/cloudjs10Action/Dockerfile +++ /dev/null @@ -1,52 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -FROM node:10.15.3-stretch - -# Initial update and some basics. -# -RUN apt-get update && apt-get install -y \ - imagemagick \ - graphicsmagick \ - unzip \ - && rm -rf /var/lib/apt/lists/* - -# Add sources and copy the package.json to root container, -# so npm packages from user functions take precendence. -# -WORKDIR /nodejsAction -ADD . /nodejsAction/ -COPY package.json / - -# Customize runtime with additional packages. -# Install package globally so user packages can override. -# -RUN cd / && npm install --no-package-lock --production \ - && npm cache clean --force - -# move nim sdk to node modules directory so that it can be found by node module loader -RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js - -RUN curl -sSL https://sdk.cloud.google.com | bash -ENV PATH="${PATH}:/root/google-cloud-sdk/bin" -RUN gcloud components install beta \ - && gcloud components install kubectl \ - && gcloud components update - -EXPOSE 8080 - -CMD node --expose-gc /nodejsAction/app.js diff --git a/core/cloudjs10Action/build.gradle b/core/cloudjs10Action/build.gradle deleted file mode 100644 index cf64c56c..00000000 --- a/core/cloudjs10Action/build.gradle +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'eclipse' -eclipse { - project { - natures 'org.eclipse.wst.jsdt.core.jsNature' - buildCommand 'org.eclipse.wst.jsdt.core.javascriptValidator' - } -} - -ext.dockerImageName = 'action-cloudjs-v10' -apply from: '../../gradle/docker.gradle' - -distDocker.dependsOn 'copyPackageJson' -distDocker.dependsOn 'copyProxy' -distDocker.dependsOn 'copyRunner' -distDocker.dependsOn 'copyService' -distDocker.dependsOn 'copyPlatform' -distDocker.dependsOn 'copyOpenWhisk' -distDocker.dependsOn 'copyKnative' -distDocker.dependsOn 'copyBuildTemplate' -distDocker.finalizedBy('cleanup') - -task copyPackageJson(type: Copy) { - from '../nodejsActionBase/package.json' - into '.' -} - -task copyProxy(type: Copy) { - from '../nodejsActionBase/app.js' - into '.' -} - -task copyRunner(type: Copy) { - from '../nodejsActionBase/runner.js' - into '.' - - from '../nodejsActionBase/lambda.js' - into '.' - - from '../nodejsActionBase/nim.js' - into '.' -} - -task copyService(type: Copy) { - from '../nodejsActionBase/src/service.js' - into './src' -} - -task copyPlatform(type: Copy) { - from '../nodejsActionBase/platform/platform.js' - into './platform' -} - -task copyOpenWhisk(type: Copy) { - from '../nodejsActionBase/platform/openwhisk.js' - into './platform' -} - -task copyKnative(type: Copy) { - from '../nodejsActionBase/platform/knative.js' - into './platform' -} - -task copyBuildTemplate(type: Copy) { - from '../nodejsActionBase/buildtemplate.yaml' - into '.' -} - -task cleanup(type: Delete) { - delete 'package.json' - delete 'app.js' - delete 'lambda.js' - delete 'nim.js' - delete 'runner.js' - delete 'src' - delete 'platform' - delete 'buildtemplate.yaml' -} diff --git a/core/nodejs10Action/.dockerignore b/core/nodejs10Action/.dockerignore deleted file mode 100644 index a1d03cb9..00000000 --- a/core/nodejs10Action/.dockerignore +++ /dev/null @@ -1,13 +0,0 @@ -*.*~ -*.yaml -*.tmpl -*.gradle -.dockerignore -.project -.settings -build.xml -Dockerfile -logs -node_modules -package-lock.json -test.js diff --git a/core/nodejs10Action/CHANGELOG.md b/core/nodejs10Action/CHANGELOG.md deleted file mode 100644 index ec5cf657..00000000 --- a/core/nodejs10Action/CHANGELOG.md +++ /dev/null @@ -1,53 +0,0 @@ - - -# NodeJS 10 OpenWhisk Runtime Container - -# Next Release -Node.js version = [10.23.2](https://nodejs.org/en/blog/release/v10.23.2/) - -## Apache 1.17 - - Update Node.js and OpenWhisk versions. - -Node.js version = [10.23.0](https://nodejs.org/en/blog/release/v10.23.0/) -OpenWhisk version = [OpenWhisk v3.21.3](https://www.npmjs.com/package/openwhisk) - -## Apache 1.16 -Changes: - - Update Node.js and OpenWhisk versions. - -Node.js version = [10.21.0](https://nodejs.org/en/blog/release/v10.21.0/) -OpenWhisk version = [OpenWhisk v3.21.2](https://www.npmjs.com/package/openwhisk) - -## Apache 1.15 -Changes: - - Update Node.js - - Update OpenWhisk npm package - - Support for __OW_ACTION_VERSION (openwhisk/4761) - -Node.js version = [10.19.0](https://nodejs.org/en/blog/release/v10.19.0/) -OpenWhisk version = [OpenWhisk v3.21.1](https://www.npmjs.com/package/openwhisk) - -## Apache 1.13 -Changes: -- Initial version with NodejS10 LTS -- Node.js version = [10.16.3](https://nodejs.org/en/blog/release/v10.16.3/) -- [OpenWhisk v3.18.0](https://www.npmjs.com/package/openwhisk) - JavaScript client library for the OpenWhisk platform. Provides a wrapper around the OpenWhisk APIs. - -Node.js version = [10.15.3](https://nodejs.org/en/blog/release/v10.15.3/) diff --git a/core/nodejs10Action/Dockerfile b/core/nodejs10Action/Dockerfile deleted file mode 100644 index f5adabab..00000000 --- a/core/nodejs10Action/Dockerfile +++ /dev/null @@ -1,51 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -FROM node:10.23.2-stretch - -# Initial update and some basics. -# -RUN apt-get update && apt-get install -y \ - imagemagick \ - graphicsmagick \ - unzip \ - && rm -rf /var/lib/apt/lists/* - -# Add sources and copy the package.json to root container, -# so npm packages from user functions take precendence. -# -WORKDIR /nodejsAction -ADD . /nodejsAction/ -COPY package.json / - -# Customize runtime with additional packages. -# Install package globally so user packages can override. -# -RUN cd / && npm install --no-package-lock --production \ - && npm cache clean --force - -# move nim sdk to node modules directory so that it can be found by node module loader -RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js - -ARG __LAMBDA_COMPAT -ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT - -EXPOSE 8080 - -# The flag --experimental-worker enables worker threads, -# see https://nodejs.org/docs/latest-v10.x/api/worker_threads.html -CMD node --experimental-worker --expose-gc app.js diff --git a/core/nodejs10Action/build.gradle b/core/nodejs10Action/build.gradle deleted file mode 100644 index 57412c93..00000000 --- a/core/nodejs10Action/build.gradle +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'eclipse' -eclipse { - project { - natures 'org.eclipse.wst.jsdt.core.jsNature' - buildCommand 'org.eclipse.wst.jsdt.core.javascriptValidator' - } -} - -ext.dockerImageName = 'action-nodejs-v10' -apply from: '../../gradle/docker.gradle' - -distDocker.dependsOn 'copyPackageJson' -distDocker.dependsOn 'copyProxy' -distDocker.dependsOn 'copyRunner' -distDocker.dependsOn 'copyService' -distDocker.dependsOn 'copyPlatform' -distDocker.dependsOn 'copyOpenWhisk' -distDocker.dependsOn 'copyKnative' -distDocker.dependsOn 'copyBuildTemplate' -distDocker.finalizedBy('cleanup') - -task copyPackageJson(type: Copy) { - from '../nodejsActionBase/package.json' - into '.' -} - -task copyProxy(type: Copy) { - from '../nodejsActionBase/app.js' - into '.' -} - -task copyRunner(type: Copy) { - from '../nodejsActionBase/runner.js' - into '.' - - from '../nodejsActionBase/lambda.js' - into '.' - - from '../nodejsActionBase/nim.js' - into '.' -} - -task copyService(type: Copy) { - from '../nodejsActionBase/src/service.js' - into './src' -} - -task copyPlatform(type: Copy) { - from '../nodejsActionBase/platform/platform.js' - into './platform' -} - -task copyOpenWhisk(type: Copy) { - from '../nodejsActionBase/platform/openwhisk.js' - into './platform' -} - -task copyKnative(type: Copy) { - from '../nodejsActionBase/platform/knative.js' - into './platform' -} - -task copyBuildTemplate(type: Copy) { - from '../nodejsActionBase/buildtemplate.yaml' - into '.' -} - -task cleanup(type: Delete) { - delete 'package.json' - delete 'app.js' - delete 'lambda.js' - delete 'nim.js' - delete 'runner.js' - delete 'src' - delete 'platform' - delete 'buildtemplate.yaml' -} diff --git a/core/nodejs10Action/knative/Dockerfile b/core/nodejs10Action/knative/Dockerfile deleted file mode 100644 index 2453c2bb..00000000 --- a/core/nodejs10Action/knative/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -FROM node:10.20.1-stretch -RUN apt-get update && apt-get install -y \ - imagemagick \ - graphicsmagick \ - unzip \ - && rm -rf /var/lib/apt/lists/* -WORKDIR /nodejsAction -# COPY source code "*.js" from nodejsActionBase to current working dir -RUN mkdir /src /platform -COPY ./core/nodejsActionBase/*.js ./ -COPY ./core/nodejsActionBase/src/*.js ./src/ -COPY ./core/nodejsActionBase/platform/*.js ./platform/ -COPY . . -# COPY the package.json to root container, so we can install npm packages a level up from user's packages, -# so user's packages take precedence -COPY ./core/nodejsActionBase/package.json / -RUN cd / && npm install --no-package-lock \ - && npm cache clean --force -EXPOSE 8080 -# The flag --experimental-worker enables worker threads, see https://nodejs.org/docs/latest-v10.x/api/worker_threads.html -CMD node --experimental-worker --expose-gc app.js diff --git a/core/nodejs12Action/.dockerignore b/core/nodejs12Action/.dockerignore deleted file mode 100644 index a1d03cb9..00000000 --- a/core/nodejs12Action/.dockerignore +++ /dev/null @@ -1,13 +0,0 @@ -*.*~ -*.yaml -*.tmpl -*.gradle -.dockerignore -.project -.settings -build.xml -Dockerfile -logs -node_modules -package-lock.json -test.js diff --git a/core/nodejs12Action/CHANGELOG.md b/core/nodejs12Action/CHANGELOG.md deleted file mode 100644 index 58d60200..00000000 --- a/core/nodejs12Action/CHANGELOG.md +++ /dev/null @@ -1,54 +0,0 @@ - - -# NodeJS 12 OpenWhisk Runtime Container - -# Next Release -Node.js version = [12.20.1](https://nodejs.org/en/blog/release/v12.20.1/) - -## Apache 1.17 - - Update Node.js and OpenWhisk versions. - -Node.js version = [12.19.1](https://nodejs.org/en/blog/release/v12.19.1/) -OpenWhisk version = [OpenWhisk v3.21.3](https://www.npmjs.com/package/openwhisk) - -## Apache 1.16 -Changes: - - Update Node.js and OpenWhisk versions. - - Update OpenWhisk npm package - -Node.js version = [12.18.2](https://nodejs.org/en/blog/release/v12.18.2/) -OpenWhisk version = [OpenWhisk v3.21.2](https://www.npmjs.com/package/openwhisk) - -## Apache 1.15 -Changes: - - Update Node.js - - Update OpenWhisk npm package - - Support for __OW_ACTION_VERSION (openwhisk/4761) - -Node.js version = [12.15.0](https://nodejs.org/en/blog/release/v12.15.0/) -OpenWhisk version = [OpenWhisk v3.21.1](https://www.npmjs.com/package/openwhisk) - -## Apache 1.14 -Changes: -- Adding Nodejs version 12 -- Node.js version = [12.8.1](https://nodejs.org/en/blog/release/v12.8.1/) -- [OpenWhisk v3.18.0](https://www.npmjs.com/package/openwhisk) - JavaScript client library for the OpenWhisk platform. Provides a wrapper around the OpenWhisk APIs. - -Node.js version = [12.1.0](https://nodejs.org/en/blog/release/v12.1.0/) diff --git a/core/nodejs12Action/Dockerfile b/core/nodejs12Action/Dockerfile deleted file mode 100644 index 511dd002..00000000 --- a/core/nodejs12Action/Dockerfile +++ /dev/null @@ -1,49 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -FROM node:12.20.1-stretch - -# Initial update and some basics. -# -RUN apt-get update && apt-get install -y \ - imagemagick \ - graphicsmagick \ - unzip \ - && rm -rf /var/lib/apt/lists/* - -# Add sources and copy the package.json to root container, -# so npm packages from user functions take precendence. -# -WORKDIR /nodejsAction -ADD . /nodejsAction/ -COPY package.json / - -# Customize runtime with additional packages. -# Install package globally so user packages can override. -# -RUN cd / && npm install --no-package-lock --production \ - && npm cache clean --force - -# move nim sdk to node modules directory so that it can be found by node module loader -RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js - -ARG __LAMBDA_COMPAT -ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT - -EXPOSE 8080 - -CMD node --expose-gc /nodejsAction/app.js diff --git a/core/nodejs12Action/build.gradle b/core/nodejs12Action/build.gradle deleted file mode 100644 index 9dbf23e5..00000000 --- a/core/nodejs12Action/build.gradle +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'eclipse' -eclipse { - project { - natures 'org.eclipse.wst.jsdt.core.jsNature' - buildCommand 'org.eclipse.wst.jsdt.core.javascriptValidator' - } -} - -ext.dockerImageName = 'action-nodejs-v12' -apply from: '../../gradle/docker.gradle' - -distDocker.dependsOn 'copyPackageJson' -distDocker.dependsOn 'copyProxy' -distDocker.dependsOn 'copyRunner' -distDocker.dependsOn 'copyService' -distDocker.dependsOn 'copyPlatform' -distDocker.dependsOn 'copyOpenWhisk' -distDocker.dependsOn 'copyKnative' -distDocker.dependsOn 'copyBuildTemplate' -distDocker.finalizedBy('cleanup') - -task copyPackageJson(type: Copy) { - from '../nodejsActionBase/package.json' - into '.' -} - -task copyProxy(type: Copy) { - from '../nodejsActionBase/app.js' - into '.' -} - -task copyRunner(type: Copy) { - from '../nodejsActionBase/runner.js' - into '.' - - from '../nodejsActionBase/lambda.js' - into '.' - - from '../nodejsActionBase/nim.js' - into '.' -} - -task copyService(type: Copy) { - from '../nodejsActionBase/src/service.js' - into './src' -} - -task copyPlatform(type: Copy) { - from '../nodejsActionBase/platform/platform.js' - into './platform' -} - -task copyOpenWhisk(type: Copy) { - from '../nodejsActionBase/platform/openwhisk.js' - into './platform' -} - -task copyKnative(type: Copy) { - from '../nodejsActionBase/platform/knative.js' - into './platform' -} - -task copyBuildTemplate(type: Copy) { - from '../nodejsActionBase/buildtemplate.yaml' - into '.' -} - -task cleanup(type: Delete) { - delete 'package.json' - delete 'app.js' - delete 'lambda.js' - delete 'nim.js' - delete 'runner.js' - delete 'src' - delete 'platform' - delete 'buildtemplate.yaml' -} diff --git a/core/tessjs10Action/.dockerignore b/core/tessjs10Action/.dockerignore deleted file mode 100644 index a1d03cb9..00000000 --- a/core/tessjs10Action/.dockerignore +++ /dev/null @@ -1,13 +0,0 @@ -*.*~ -*.yaml -*.tmpl -*.gradle -.dockerignore -.project -.settings -build.xml -Dockerfile -logs -node_modules -package-lock.json -test.js diff --git a/core/tessjs10Action/Dockerfile b/core/tessjs10Action/Dockerfile deleted file mode 100644 index 7e1f5156..00000000 --- a/core/tessjs10Action/Dockerfile +++ /dev/null @@ -1,58 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -FROM node:10.15.3-stretch - -# Initial update and some basics. -# -RUN apt-get update && apt-get install -y \ - imagemagick \ - graphicsmagick \ - unzip \ - wget \ - && rm -rf /var/lib/apt/lists/* - -# Add sources and copy the package.json to root container, -# so npm packages from user functions take precendence. -# -WORKDIR /nodejsAction -ADD . /nodejsAction/ -COPY package.json / - -# Download models -RUN wget -q https://raw.githubusercontent.com/tesseract-ocr/tessdata/master/eng.traineddata -RUN wget -q https://raw.githubusercontent.com/tesseract-ocr/tessdata/master/spa.traineddata -RUN wget -q https://raw.githubusercontent.com/tesseract-ocr/tessdata/master/chi_tra.traineddata - -# Customize runtime with additional packages. -# Install package globally so user packages can override. -# -RUN cd / && npm install --no-package-lock --production \ - && npm install --no-package-lock --production tesseract.js@1.0.19 \ - && npm cache clean --force - -# move nim sdk to node modules directory so that it can be found by node module loader -RUN mkdir /node_modules/nim && mv /nodejsAction/nim.js /node_modules/nim/index.js - -ARG __LAMBDA_COMPAT -ENV __LAMBDA_COMPAT=$__LAMBDA_COMPAT - -EXPOSE 8080 - -# The flag --experimental-worker enables worker threads, -# see https://nodejs.org/docs/latest-v10.x/api/worker_threads.html -CMD node --experimental-worker --expose-gc /nodejsAction/app.js diff --git a/core/tessjs10Action/build.gradle b/core/tessjs10Action/build.gradle deleted file mode 100644 index 53126c75..00000000 --- a/core/tessjs10Action/build.gradle +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'eclipse' -eclipse { - project { - natures 'org.eclipse.wst.jsdt.core.jsNature' - buildCommand 'org.eclipse.wst.jsdt.core.javascriptValidator' - } -} - -ext.dockerImageName = 'action-tessjs-v10' -apply from: '../../gradle/docker.gradle' - -distDocker.dependsOn 'copyPackageJson' -distDocker.dependsOn 'copyProxy' -distDocker.dependsOn 'copyRunner' -distDocker.dependsOn 'copyService' -distDocker.dependsOn 'copyPlatform' -distDocker.dependsOn 'copyOpenWhisk' -distDocker.dependsOn 'copyKnative' -distDocker.dependsOn 'copyBuildTemplate' -distDocker.finalizedBy('cleanup') - -task copyPackageJson(type: Copy) { - from '../nodejsActionBase/package.json' - into '.' -} - -task copyProxy(type: Copy) { - from '../nodejsActionBase/app.js' - into '.' -} - -task copyRunner(type: Copy) { - from '../nodejsActionBase/runner.js' - into '.' - - from '../nodejsActionBase/lambda.js' - into '.' - - from '../nodejsActionBase/nim.js' - into '.' -} - -task copyService(type: Copy) { - from '../nodejsActionBase/src/service.js' - into './src' -} - -task copyPlatform(type: Copy) { - from '../nodejsActionBase/platform/platform.js' - into './platform' -} - -task copyOpenWhisk(type: Copy) { - from '../nodejsActionBase/platform/openwhisk.js' - into './platform' -} - -task copyKnative(type: Copy) { - from '../nodejsActionBase/platform/knative.js' - into './platform' -} - -task copyBuildTemplate(type: Copy) { - from '../nodejsActionBase/buildtemplate.yaml' - into '.' -} - -task cleanup(type: Delete) { - delete 'package.json' - delete 'app.js' - delete 'lambda.js' - delete 'nim.js' - delete 'runner.js' - delete 'src' - delete 'platform' - delete 'buildtemplate.yaml' -} diff --git a/core/typescript37Action/.dockerignore b/core/typescript37Action/.dockerignore deleted file mode 100644 index a1d03cb9..00000000 --- a/core/typescript37Action/.dockerignore +++ /dev/null @@ -1,13 +0,0 @@ -*.*~ -*.yaml -*.tmpl -*.gradle -.dockerignore -.project -.settings -build.xml -Dockerfile -logs -node_modules -package-lock.json -test.js diff --git a/core/typescript37Action/Dockerfile b/core/typescript37Action/Dockerfile deleted file mode 100644 index 2b9dac27..00000000 --- a/core/typescript37Action/Dockerfile +++ /dev/null @@ -1,84 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# build go proxy from source -FROM golang:1.15 AS builder_source -ARG GO_PROXY_GITHUB_USER=nimbella-corp -ARG GO_PROXY_GITHUB_BRANCH=dev -RUN git clone --branch ${GO_PROXY_GITHUB_BRANCH} \ - https://github.com/${GO_PROXY_GITHUB_USER}/openwhisk-runtime-go /src ;\ - cd /src ; env GO111MODULE=on CGO_ENABLED=0 go build main/proxy.go && \ - mv proxy /bin/proxy - -# or build it from a release -FROM golang:1.15 AS builder_release -ARG GO_PROXY_RELEASE_VERSION=1.15@1.17.0 -RUN curl -sL \ - https://github.com/apache/openwhisk-runtime-go/archive/{$GO_PROXY_RELEASE_VERSION}.tar.gz\ - | tar xzf -\ - && cd openwhisk-runtime-go-*/main\ - && GO111MODULE=on go build -o /bin/proxy - -FROM node:12.1.0-stretch - -# select the builder to use -ARG GO_PROXY_BUILD_FROM=source - -ENV TYPESCRIPT_VERSION=3.7.4 -ENV OW_COMPILER=/bin/compile -ENV OW_LOG_INIT_ERROR=1 -ENV OW_WAIT_FOR_ACK=1 -ENV OW_EXECUTION_ENV=openwhisk/typescript3.7 - -# Initial update and some basics. -# -RUN apt-get update && apt-get install -y \ - imagemagick \ - graphicsmagick \ - unzip \ - && rm -rf /var/lib/apt/lists/* &&\ - mkdir -p /app/action - -WORKDIR /proxy -COPY --from=builder_source /bin/proxy /bin/proxy_source -COPY --from=builder_release /bin/proxy /bin/proxy_release -RUN mv /bin/proxy_${GO_PROXY_BUILD_FROM} /bin/proxy - -# Add sources and copy the package.json to root container, -# so npm packages from user functions take precendence. -# -WORKDIR /app -COPY bin/compile /bin/compile -COPY lib/launcher.ts /lib/launcher.ts -COPY nim.js / -COPY package.json / - -# Customize runtime with additional packages. -# -RUN cd / && npm install -g \ - yarn \ - typescript@${TYPESCRIPT_VERSION} \ - && npm install --no-package-lock --production @types/node@13.13.5 \ - && npm install --no-package-lock --production \ - && npm cache clean --force - -# move nim sdk to node modules directory so that it can be found by node module loader -RUN mkdir /node_modules/nim && mv /nim.js /node_modules/nim/index.js - -EXPOSE 8080 - -ENTRYPOINT ["/bin/proxy"] diff --git a/core/typescript37Action/Makefile b/core/typescript37Action/Makefile deleted file mode 100644 index 373f831a..00000000 --- a/core/typescript37Action/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -PREFIX=whisk -IMG=action-typescript-v3.7 - -start: - docker run -p 8080:8080 -ti -v $(PWD):/mnt $(IMG) - -debug: - docker run -p 8080:8080 -p 8081:8081 -ti --entrypoint=/bin/bash \ - -v $(PWD):/mnt -e OW_COMPILER=/mnt/bin/compile $(IMG) - -build: - docker build . -t $(IMG) - docker tag $(IMG) whisk/$(IMG) - docker images | grep $(IMG) - -.PHONY: start debug build diff --git a/core/typescript37Action/bin/compile b/core/typescript37Action/bin/compile deleted file mode 100755 index 2635459c..00000000 --- a/core/typescript37Action/bin/compile +++ /dev/null @@ -1,162 +0,0 @@ -#!/usr/bin/env node -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const path = require("path") -const fs = require("fs") -const execFileSync = require('child_process').execFileSync; - -// write a file creating intermediate directories -function write_file(file, body, executable) { - fs.mkdirSync(path.dirname(file), { recursive: true }) - fs.writeFileSync(file, body) - if (executable) { - fs.chmodSync(file, 0755) - } -} - -// copy a file eventually replacing a substring -function copy_replace(src, dst, match, replacement) { - let body = fs.readFileSync(src, "utf-8") - if (match) { - body = body.replace(match, replacement) - } - write_file(dst, body) -} - -function deext(filename) { - const pos = filename.lastIndexOf(".") - filename = pos > -1 ? filename.substring(0, pos) : filename - return filename -} - -// resolve dependencies from package.json - return the main file -function dependencies(src_dir) { - const pkg_config = src_dir + "/package.json" - const node_modules = src_dir + "/node_modules" - if (fs.existsSync(pkg_config)) { - if (!fs.existsSync(node_modules)) { - execFileSync("yarn", [], { - "cwd": src_dir - }) - } - const config = JSON.parse(fs.readFileSync(pkg_config, "utf-8")) - if ("main" in config) { - return deext(config["main"]) - } - } - return "index" -} - -// assemble sources -function sources(launcher, main_file, main_func, src_dir) { - // init config - const src_config = src_dir + "/tsconfig.json" - const config = {} - if (fs.existsSync(src_config)) { - config = JSON.parse(fs.readFileSync(src_config, "utf-8")) - } - - if (!("files" in config)) { - config["files"] = [] - } - - if (!("compilerOptions" in config)) { - config["compilerOptions"] = {} - } - - config["compilerOptions"]["inlineSourceMap"] = true - - if ("sourceMap" in config["compilerOptions"]) { - delete config["compilerOptions"]["sourceMap"] - } - - if (!("outDir" in config["compilerOptions"])) { - config["compilerOptions"]["outDir"] = "." - } - - // copy main src file if any (and use it as main) - const src_file = src_dir + "/exec" - const tgt_file = src_dir + "/" + main_file + ".ts" - if (fs.existsSync(src_file) && !fs.existsSync(tgt_file)) { - const re = RegExp('(? ") - process.exit(1) - } - const launcher = path.dirname(path.dirname(process.argv[1])) + "/lib/launcher.ts" - const src_dir = path.resolve(process.argv[3]) - const bin_dir = path.resolve(process.argv[4]) - let main_func = process.argv[2] - let main_file = dependencies(src_dir) - const pieces = main_func.split(".") - if (pieces.length > 1) { - main_file = pieces.shift() - main_func = pieces.join(".") - } - sources(launcher, main_file, main_func, src_dir) - build(src_dir, bin_dir) -} - -if (require.main === module) { - compile() -} diff --git a/core/typescript37Action/build.gradle b/core/typescript37Action/build.gradle deleted file mode 100644 index 0595b4fd..00000000 --- a/core/typescript37Action/build.gradle +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -ext.dockerImageName = 'action-typescript-v3.7' -apply from: '../../gradle/docker.gradle' - -distDocker.dependsOn 'copyPackageJson' -distDocker.dependsOn 'copyRunner' - -task copyPackageJson(type: Copy) { - from '../nodejsActionBase/package.json' - into '.' -} - -task copyRunner(type: Copy) { - from '../nodejsActionBase/nim.js' - into '.' -} - -task cleanup(type: Delete) { - delete 'package.json' - delete 'nim.js' -} diff --git a/core/typescript37Action/lib/launcher.ts b/core/typescript37Action/lib/launcher.ts deleted file mode 100644 index 95b428d9..00000000 --- a/core/typescript37Action/lib/launcher.ts +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -try { - const main = require("./main__").main - const readline = require('readline'); - const fs = require("fs") - const os = require("os") - - function vscodeDebug() { - let ifaces = os.networkInterfaces() - for (let iface of Object.keys(ifaces)) { - for (let ip of ifaces[iface]) { - if (!ip.internal) { - return { - "type": "node", - "request": "attach", - "name": process.env["__OW_ACTION_NAME"], - "address": ip.address, - "port": 8081, - "localRoot": "${workspaceFolder}", - "remoteRoot": __dirname - } - } - } - } - return { "error": "cannot find external interface" } - } - - async function actionLoop() { - const out = fs.createWriteStream(null, - { fd: 3, encoding: "utf8" }) - process.stdin.setEncoding('utf8'); - const rl = readline.createInterface({ - input: process.stdin - }); - const debugging = "__OW_DEBUG_PORT" in process.env - out.write(JSON.stringify({ "ok": true }) + "\n"); - for await (const line of rl) { - try { - let args = JSON.parse(line) - let value = args.value || {} - for (let key in args) { - if (key !== "value") { - let envar = "__OW_" + key.toUpperCase() - process.env[envar] = args[key] - } - } - let result = {} - if (debugging && "debugWith" in value) { - if (value["debugWith"] === "vscode") - result = vscodeDebug() - else - result = { "error": "requested unknown debugger" } - } else { - result = main(value) - if (typeof result === 'undefined') { - result = {} - } - if (Promise.resolve(result) == result) - try { - result = await result - } catch (error) { - if (typeof error === 'undefined') { - error = {} - } - result = { "error": error } - } - } - out.write(JSON.stringify(result) + "\n"); - } catch (err) { - console.log(err); - let message = err.message || err.toString() - let error = { "error": message } - out.write(JSON.stringify(error) + "\n"); - } - } - } - actionLoop() -} catch (e) { - if (e.code == "MODULE_NOT_FOUND") { - console.log("zipped actions must contain either package.json or index.js at the root.") - } - console.log(e) - process.exit(1) -} diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJs10ActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJs10ActionContainerTests.scala deleted file mode 100644 index a7bcc447..00000000 --- a/tests/src/test/scala/runtime/actionContainers/NodeJs10ActionContainerTests.scala +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package runtime.actionContainers - -import org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner - -@RunWith(classOf[JUnitRunner]) -class NodeJs10ActionContainerTests extends NodeJsActionContainerTests { - override lazy val nodejsContainerImageName = "action-nodejs-v10" - override lazy val nodejsTestDockerImageName = "nodejs10docker" -} diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJs10ConcurrentTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJs10ConcurrentTests.scala deleted file mode 100644 index ffb3108c..00000000 --- a/tests/src/test/scala/runtime/actionContainers/NodeJs10ConcurrentTests.scala +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package runtime.actionContainers - -import org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner - -@RunWith(classOf[JUnitRunner]) -class NodeJs10ConcurrentTests extends NodeJsConcurrentTests { - override lazy val nodejsContainerImageName = "action-nodejs-v10" - override lazy val nodejsTestDockerImageName = "nodejs10docker" -} diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJs12ActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJs12ActionContainerTests.scala deleted file mode 100644 index efba5698..00000000 --- a/tests/src/test/scala/runtime/actionContainers/NodeJs12ActionContainerTests.scala +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package runtime.actionContainers - -import org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner - -@RunWith(classOf[JUnitRunner]) -class NodeJs12ActionContainerTests extends NodeJsActionContainerTests { - override lazy val nodejsContainerImageName = "action-nodejs-v12" - override lazy val nodejsTestDockerImageName = "nodejs12docker" -} diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJs12ConcurrentTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJs12ConcurrentTests.scala deleted file mode 100644 index e3414c40..00000000 --- a/tests/src/test/scala/runtime/actionContainers/NodeJs12ConcurrentTests.scala +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package runtime.actionContainers - -import org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner - -@RunWith(classOf[JUnitRunner]) -class NodeJs12ConcurrentTests extends NodeJsConcurrentTests { - override lazy val nodejsContainerImageName = "action-nodejs-v12" - override lazy val nodejsTestDockerImageName = "nodejs12docker" -} diff --git a/tests/src/test/scala/runtime/actionContainers/Typescript37BasicTests.scala b/tests/src/test/scala/runtime/actionContainers/Typescript37BasicTests.scala deleted file mode 100644 index 4006cdec..00000000 --- a/tests/src/test/scala/runtime/actionContainers/Typescript37BasicTests.scala +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package runtime.actionContainers - -import actionContainers.ActionContainer.withContainer -import actionContainers.{ActionContainer, BasicActionRunnerTests} -import common.WskActorSystem -import org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner - -@RunWith(classOf[JUnitRunner]) -class Typescript37BasicTests extends BasicActionRunnerTests with WskActorSystem { - - val image = "action-typescript-v3.7" - - override def withActionContainer(env: Map[String, String] = Map.empty)(code: ActionContainer => Unit) = { - withContainer(image, env)(code) - } - - def withActionLoopContainer(code: ActionContainer => Unit) = - withContainer(image)(code) - - behavior of image - - override val testNoSourceOrExec = TestConfig("") - - override val testNotReturningJson = - TestConfig(""" - |export function main(args) { - | return "not a json object" - |} - """.stripMargin) - - override val testEcho = TestConfig("""|export function main(args) { - | console.log("hello stdout") - | console.error("hello stderr") - | return args - |} - """.stripMargin) - - override val testUnicode = TestConfig("""|export function main(args) { - | let delimiter = args['delimiter'] - | let msg = delimiter+" ☃ "+delimiter - | console.log(msg) - | return { "winter": msg } - |} - """.stripMargin) - - override val testEnv = TestConfig("""|export function main(args) { - | let env = process.env - | return { - | "api_host": env["__OW_API_HOST"], - | "api_key": env["__OW_API_KEY"], - | "namespace": env["__OW_NAMESPACE"], - | "activation_id": env["__OW_ACTIVATION_ID"], - | "action_name": env["__OW_ACTION_NAME"], - | "deadline": env["__OW_DEADLINE"], - | "action_version": env["__OW_ACTION_VERSION"] - | } - |} - """.stripMargin) - - override val testInitCannotBeCalledMoreThanOnce = TestConfig(s"""|export function main(args) { - | return args - |} - """.stripMargin) - - override val testEntryPointOtherThanMain = TestConfig( - s"""|export function niam(args) { - | return args - |} - """.stripMargin, - main = "niam") - - override val testLargeInput = TestConfig(s"""|export function main(args) { - | return args - |} - """.stripMargin) -} diff --git a/tests/src/test/scala/runtime/actionContainers/Typescript37CommonTests.scala b/tests/src/test/scala/runtime/actionContainers/Typescript37CommonTests.scala deleted file mode 100644 index e39e2463..00000000 --- a/tests/src/test/scala/runtime/actionContainers/Typescript37CommonTests.scala +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package runtime.actionContainers - -import org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner - -@RunWith(classOf[JUnitRunner]) -class Typescript37CommonTests extends NodeJsNonConcurrentTests { - - override lazy val nodejsContainerImageName = "action-typescript-v3.7" - override lazy val nodejsTestDockerImageName = "typescript37docker" - override val isTypeScript = true -} From 94f2ebba2169d991502cf89d69f4d01ba9ababcb Mon Sep 17 00:00:00 2001 From: Matt Welke Date: Mon, 5 Dec 2022 11:54:17 -0500 Subject: [PATCH 19/29] SERVERLESS-2326 | Merge OpenWhisk and Lambda variants of Node.js runtimes together Add Lambda function support to main runtime variant via sig auto-detect. (#16) Re-uses our "Lambda runner" JS code that we're already using in the Lambda variant of the Node.js runtime to support Lambda function signatures in the regular runtime too. This makes the non-Lambda variant work with both OpenWhisk and Lambda function signatures. It's backwards compatible because the Lambda runner JS code still uses the env var, so customers using the Lambda variant of the Node.js runtime explicitly will have their functions continue to work. Also simplifies some error handling in the launcher.js and prelauncher.js files. It now assumes it will be able to successfully import the Lambda runner code. --- core/nodejsActionBase/launcher.js | 6 ++- core/nodejsActionBase/package.json | 9 +++- core/nodejsActionBase/prelauncher.js | 11 +++-- core/nodejsActionBase/runner.js | 13 +++++- .../test/useLambdaRunner.spec.js | 41 +++++++++++++++++++ core/nodejsActionBase/useLambdaRunner.js | 29 +++++++++++++ .../NodeJsActionContainerTests.scala | 34 +++++++++++++++ 7 files changed, 135 insertions(+), 8 deletions(-) create mode 100644 core/nodejsActionBase/test/useLambdaRunner.spec.js create mode 100644 core/nodejsActionBase/useLambdaRunner.js diff --git a/core/nodejsActionBase/launcher.js b/core/nodejsActionBase/launcher.js index e9b8e44b..0de45300 100644 --- a/core/nodejsActionBase/launcher.js +++ b/core/nodejsActionBase/launcher.js @@ -15,6 +15,8 @@ * limitations under the License. */ +const useLambdaRunner = require('/nodejsAction/useLambdaRunner'); + try { const readline = require('readline'); const fs = require("fs") @@ -27,9 +29,9 @@ try { } catch (e) {} })(); - const lambdaCompat = process.env.__OW_LAMBDA_COMPAT === undefined ? false : process.env.__OW_LAMBDA_COMPAT.toLowerCase() === 'true' && NodeActionLambdaRunner !== undefined; const handler = eval('require("./##MAIN_FILE##").##MAIN_FUNC##') // Will be replaced in the compile script with the correct main. - const runner = lambdaCompat === false ? new NodeActionRunner(handler) : new NodeActionLambdaRunner(handler); + + const runner = useLambdaRunner(handler) ? new NodeActionLambdaRunner(handler) : new NodeActionRunner(handler); async function actionLoop() { const out = fs.createWriteStream(null, diff --git a/core/nodejsActionBase/package.json b/core/nodejsActionBase/package.json index 67cbe7b7..32799234 100644 --- a/core/nodejsActionBase/package.json +++ b/core/nodejsActionBase/package.json @@ -7,22 +7,27 @@ "url": "git@github.com:apache/openwhisk-runtime-nodejs.git" }, "license": "Apache-2.0", + "scripts": { + "test": "mocha" + }, "devDependencies": { "btoa": "1.1.2", + "chai": "^4.3.7", "eslint": "^5.16.0", "eslint-config-standard": "^12.0.0", "eslint-plugin-import": "^2.17.2", "eslint-plugin-node": "^8.0.1", "eslint-plugin-promise": "^4.1.1", "eslint-plugin-standard": "^4.0.0", + "mocha": "^10.1.0", "request": "2.79.0" }, "dependencies": { - "openwhisk": "3.21.3", "body-parser": "1.18.3", "express": "4.16.4", - "serialize-error": "3.0.0", + "openwhisk": "3.21.3", "redis": "2.8.0", + "serialize-error": "3.0.0", "uuid": "3.3.0" } } diff --git a/core/nodejsActionBase/prelauncher.js b/core/nodejsActionBase/prelauncher.js index 39705a0f..61f2a354 100755 --- a/core/nodejsActionBase/prelauncher.js +++ b/core/nodejsActionBase/prelauncher.js @@ -17,6 +17,8 @@ * limitations under the License. */ +const useLambdaRunner = require('/nodejsAction/useLambdaRunner'); + try { const readline = require('readline'); const fs = require("fs") @@ -29,8 +31,11 @@ try { } catch (e) {} })(); - const lambdaCompat = process.env.__OW_LAMBDA_COMPAT === undefined ? false : process.env.__OW_LAMBDA_COMPAT.toLowerCase() === 'true' && NodeActionLambdaRunner !== undefined; - + /** + * Initializes the user's function. Expected to be called with first line from ActionLoop input. + * @param {{ env: Object }} message + * @returns {NodeActionRunner | NodeActionLambdaRunner} The runner to use with the function. + */ function doInit(message) { if (message.env && typeof message.env == 'object') { Object.keys(message.env).forEach(k => { @@ -45,7 +50,7 @@ try { return initializeActionHandler(message) .then(handler => { - return lambdaCompat === false ? new NodeActionRunner(handler) : new NodeActionLambdaRunner(handler); + return useLambdaRunner(handler) ? new NodeActionLambdaRunner(handler) : new NodeActionRunner(handler); }); } diff --git a/core/nodejsActionBase/runner.js b/core/nodejsActionBase/runner.js index 596e90df..6de7f4eb 100644 --- a/core/nodejsActionBase/runner.js +++ b/core/nodejsActionBase/runner.js @@ -23,7 +23,11 @@ const fs = require('fs'); const path = require('path'); -/** Initializes the handler for the user function. */ +/** + * Initializes the handler for the user function. + * @param {Object} message + * @returns {Promise} + */ function initializeActionHandler(message) { if (message.binary) { // The code is a base64-encoded zip file. @@ -79,6 +83,13 @@ function initializeActionHandler(message) { } else { return new Promise((resolve) => { // Throws on error and rejects the promise as a consequence. + // In the eval below, ${message.code} will template in the user's code. ${message.main} will template in the + // name of the main function. So the code ends up being evaluated, which has the effect of declaring a + // function, and then that function is returned. If an error is thrown + // while trying to return the function using the current scope, and the error is ReferenceError, we assume + // that the user provided code by exporting a module instead of putting a function at the top level of their + // file, and we return what they exported instead. + // Either way, the result of eval will be the user's main function, as a function (not as a string etc.). let handler = eval( `(function(){ ${message.code} diff --git a/core/nodejsActionBase/test/useLambdaRunner.spec.js b/core/nodejsActionBase/test/useLambdaRunner.spec.js new file mode 100644 index 00000000..9c49e57c --- /dev/null +++ b/core/nodejsActionBase/test/useLambdaRunner.spec.js @@ -0,0 +1,41 @@ +const expect = require('chai').expect; + +const useLambdaRunner = require('../useLambdaRunner'); + +const envVarName = '__OW_LAMBDA_COMPAT'; + +describe('useLambdaRunner()', function () { + beforeEach(function () { + delete process.env[envVarName]; + }); + + it(`returns true when env var ${envVarName} is set to "true"`, function () { + process.env[envVarName] = 'true'; + + expect(useLambdaRunner(undefined)).to.equal(true); + }); + + it(`returns false when env var ${envVarName} is not set and it is given a function with no parameters`, function () { + const fn = function() {}; + + expect(useLambdaRunner(fn)).to.equal(false); + }); + + it(`returns false when env var ${envVarName} is not set and it is given a function with one parameter`, function () { + const fn = function(a) {}; + + expect(useLambdaRunner(fn)).to.equal(false); + }); + + it(`returns true when env var ${envVarName} is not set and it is given a function with two parameters`, function () { + const fn = function(a, b) {}; + + expect(useLambdaRunner(fn)).to.equal(true); + }); + + it(`returns true when env var ${envVarName} and it is given a function with three parameters`, function () { + const fn = function(a, b, c) {}; + + expect(useLambdaRunner(fn)).to.equal(true); + }); +}); diff --git a/core/nodejsActionBase/useLambdaRunner.js b/core/nodejsActionBase/useLambdaRunner.js new file mode 100644 index 00000000..89d9974b --- /dev/null +++ b/core/nodejsActionBase/useLambdaRunner.js @@ -0,0 +1,29 @@ +const envVarName = '__OW_LAMBDA_COMPAT'; + +/** + * Decides, based on environment variables and, if needed, the function signature, where to use the Lambda runner + * instead of the OpenWhisk runner. + * @param {Function} fn The function. + * @returns {boolean} Whether the Lambda runner should be used to run the function. + */ +function useLambdaRunner(fn) { + // Backwards compat: Deem function to be Lambda if env var is provided. This can be removed when we remove the + // Lambda only variant of the Node.js runtime. At that point, we would only use the Lambda runner if we detect that + // the function signature is Lambda-like. + if (process.env[envVarName] !== undefined && process.env[envVarName].toLowerCase() === 'true') { + return true; + } + + if (fn.length <= 1) { + // Includes no parameter case because we want to treat deployments after GA but before official Lambda support + // that have no parameters as OpenWhisk (not Lambda). + return false; + } + + // Includes >2 parameter cases because we want to maintain compatibility with deployments after GA that have + // more than two parameters. We have to choose OW or Lambda for them, so we choose Lambda (not for any + // particular reason though). + return true; +} + +module.exports = useLambdaRunner; diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala index 27c2ab10..d11188a7 100644 --- a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala +++ b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala @@ -24,6 +24,7 @@ import actionContainers.{ActionContainer, BasicActionRunnerTests, ResourceHelper import actionContainers.ActionContainer.withContainer import actionContainers.ResourceHelpers.ZipBuilder import spray.json._ +import spray.json.DefaultJsonProtocol._ abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with WskActorSystem { @@ -1049,4 +1050,37 @@ abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with Ws e shouldBe empty }) } + + Map( + "prelaunched" -> Map.empty[String, String], + "non-prelaunched" -> Map("OW_INIT_IN_ACTIONLOOP" -> "") + ).foreach { case (name, env) => + it should s"support a function with Lambda signature exported via CommonJS ($name)" in { + val (out, err) = withActionContainer(env) { c => + val code = + """ + | module.exports.main = async function (event, context) { + | return { + | event, + | contextKeys: Object.keys(context), + | }; + | } + """.stripMargin + + val (initCode, _) = c.init(initPayload(code)) + initCode should be(200) + + val (runCode, out) = c.run(runPayload( + JsObject( + "__ow_headers" -> "x".toJson, + "__ow_method" -> "get".toJson, + "__ow_path" -> "y".toJson) + )) + runCode should be(200) + + out.get.fields("contextKeys").convertTo[List[String]] should contain theSameElementsAs List("callbackWaitsForEmptyEventLoop", "done", "succeed", "fail", "getRemainingTimeInMillis") + out.get.fields("event") shouldBe JsObject("headers" -> "x".toJson, "httpMethod" -> "GET".toJson, "method" -> "get".toJson, "path" -> "y".toJson) + } + } + } } From 9b788d11818068fb8a9e84eaf8275a09fdb750a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Mon, 12 Dec 2022 19:17:50 +0100 Subject: [PATCH 20/29] SERVERLESS-2326 Implement context creation in the non-Lambda runner (#17) We've "merged" the Lambda and the non-Lambda runtimes with the goal of being able to benefit from Lambda's context capabilities. However, the runner does a lot of more things that don't really make sense outside of a "Lambda compatibility layer" context. Those are: 1. Forcing a Promise return for functions that have more than 1 argument. 2. Supporting a 3rd callback parameter. 3. Mangling the input event if it looks like an HTTP event constructed by the controller. 4. Supporting Lambda-specific capabilities like `callbackWaitsForEmptyEventLoop`. This backs some of the merge out again and implements context-mapping "natively" in the non-Lambda runner to make it behave like before but pass an additional context parameter. --- core/nodejsActionBase/runner.js | 17 ++++++- .../test/useLambdaRunner.spec.js | 8 +-- core/nodejsActionBase/useLambdaRunner.js | 11 ----- .../NodeJsActionContainerTests.scala | 49 ++++++++++++++----- 4 files changed, 56 insertions(+), 29 deletions(-) diff --git a/core/nodejsActionBase/runner.js b/core/nodejsActionBase/runner.js index 6de7f4eb..8c45bf9f 100644 --- a/core/nodejsActionBase/runner.js +++ b/core/nodejsActionBase/runner.js @@ -120,9 +120,24 @@ class NodeActionRunner { } run(args) { + let deadline = Number(process.env['__OW_DEADLINE']); + let context = { + functionName: process.env['__OW_ACTION_NAME'], + functionVersion: process.env['__OW_ACTION_VERSION'], + activationId: process.env['__OW_ACTIVATION_ID'], + requestId: process.env['__OW_TRANSACTION_ID'], + deadline: deadline, + apiHost: process.env['__OW_API_HOST'], + apiKey: process.env['__OW_API_KEY'] || '', + namespace: process.env['__OW_NAMESPACE'], + getRemainingTimeInMillis: function() { + return deadline - new Date().getTime(); + } + } + return new Promise((resolve, reject) => { try { - var result = this.userScriptMain(args); + var result = this.userScriptMain(args, context); } catch (e) { reject(e); } diff --git a/core/nodejsActionBase/test/useLambdaRunner.spec.js b/core/nodejsActionBase/test/useLambdaRunner.spec.js index 9c49e57c..9f3fca1f 100644 --- a/core/nodejsActionBase/test/useLambdaRunner.spec.js +++ b/core/nodejsActionBase/test/useLambdaRunner.spec.js @@ -27,15 +27,15 @@ describe('useLambdaRunner()', function () { expect(useLambdaRunner(fn)).to.equal(false); }); - it(`returns true when env var ${envVarName} is not set and it is given a function with two parameters`, function () { + it(`returns false when env var ${envVarName} is not set and it is given a function with two parameters`, function () { const fn = function(a, b) {}; - expect(useLambdaRunner(fn)).to.equal(true); + expect(useLambdaRunner(fn)).to.equal(false); }); - it(`returns true when env var ${envVarName} and it is given a function with three parameters`, function () { + it(`returns false when env var ${envVarName} and it is given a function with three parameters`, function () { const fn = function(a, b, c) {}; - expect(useLambdaRunner(fn)).to.equal(true); + expect(useLambdaRunner(fn)).to.equal(false); }); }); diff --git a/core/nodejsActionBase/useLambdaRunner.js b/core/nodejsActionBase/useLambdaRunner.js index 89d9974b..4b433566 100644 --- a/core/nodejsActionBase/useLambdaRunner.js +++ b/core/nodejsActionBase/useLambdaRunner.js @@ -13,17 +13,6 @@ function useLambdaRunner(fn) { if (process.env[envVarName] !== undefined && process.env[envVarName].toLowerCase() === 'true') { return true; } - - if (fn.length <= 1) { - // Includes no parameter case because we want to treat deployments after GA but before official Lambda support - // that have no parameters as OpenWhisk (not Lambda). - return false; - } - - // Includes >2 parameter cases because we want to maintain compatibility with deployments after GA that have - // more than two parameters. We have to choose OW or Lambda for them, so we choose Lambda (not for any - // particular reason though). - return true; } module.exports = useLambdaRunner; diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala index d11188a7..9db8665a 100644 --- a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala +++ b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala @@ -18,6 +18,7 @@ package runtime.actionContainers import java.io.File +import java.time.Instant import common.WskActorSystem import actionContainers.{ActionContainer, BasicActionRunnerTests, ResourceHelpers} @@ -1053,17 +1054,23 @@ abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with Ws Map( "prelaunched" -> Map.empty[String, String], - "non-prelaunched" -> Map("OW_INIT_IN_ACTIONLOOP" -> "") + "non-prelaunched" -> Map("OW_INIT_IN_ACTIONLOOP" -> ""), ).foreach { case (name, env) => - it should s"support a function with Lambda signature exported via CommonJS ($name)" in { - val (out, err) = withActionContainer(env) { c => + it should s"support a function with a lambda-like signature $name" in { + val (out, err) = withActionContainer(env + ("__OW_API_HOST" -> "testhost")) { c => val code = """ - | module.exports.main = async function (event, context) { + | function main(event, context) { | return { - | event, - | contextKeys: Object.keys(context), - | }; + | "remaining_time": context.getRemainingTimeInMillis(), + | "activation_id": context.activationId, + | "request_id": context.requestId, + | "function_name": context.functionName, + | "function_version": context.functionVersion, + | "api_host": context.apiHost, + | "api_key": context.apiKey, + | "namespace": context.namespace + | } | } """.stripMargin @@ -1071,15 +1078,31 @@ abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with Ws initCode should be(200) val (runCode, out) = c.run(runPayload( - JsObject( - "__ow_headers" -> "x".toJson, - "__ow_method" -> "get".toJson, - "__ow_path" -> "y".toJson) + JsObject(), + Some(JsObject( + "deadline" -> Instant.now.plusSeconds(10).toEpochMilli.toString.toJson, + "activation_id" -> "testaid".toJson, + "transaction_id" -> "testtid".toJson, + "action_name" -> "testfunction".toJson, + "action_version" -> "0.0.1".toJson, + "namespace" -> "testnamespace".toJson, + "api_key" -> "testkey".toJson + )) )) runCode should be(200) - out.get.fields("contextKeys").convertTo[List[String]] should contain theSameElementsAs List("callbackWaitsForEmptyEventLoop", "done", "succeed", "fail", "getRemainingTimeInMillis") - out.get.fields("event") shouldBe JsObject("headers" -> "x".toJson, "httpMethod" -> "GET".toJson, "method" -> "get".toJson, "path" -> "y".toJson) + val remainingTime = out.get.fields("remaining_time").convertTo[Int] + remainingTime should be > 9500 // We give the test 500ms of slack to invoke the function to avoid flakes. + out shouldBe Some(JsObject( + "remaining_time" -> remainingTime.toJson, + "activation_id" -> "testaid".toJson, + "request_id" -> "testtid".toJson, + "function_name" -> "testfunction".toJson, + "function_version" -> "0.0.1".toJson, + "api_host" -> "testhost".toJson, + "api_key" -> "testkey".toJson, + "namespace" -> "testnamespace".toJson + )) } } } From c8a63b12046542ceb04d0a16f0e9f1e93cc5c72f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Wed, 25 Jan 2023 15:54:08 +0100 Subject: [PATCH 21/29] SERVERLESS-2491 Rename action -> function in error messages (#18) --- core/nodejsActionBase/bin/compile | 2 +- core/nodejsActionBase/runner.js | 8 ++++---- .../actionContainers/NodeJsActionContainerTests.scala | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/nodejsActionBase/bin/compile b/core/nodejsActionBase/bin/compile index 206eafb4..f734f56a 100755 --- a/core/nodejsActionBase/bin/compile +++ b/core/nodejsActionBase/bin/compile @@ -58,7 +58,7 @@ def sources(launcher, source_dir, main): parts = main.split(".", 1) if len(parts) == 1: if not os.path.isfile("%s/index.js" % source_dir) and not os.path.isfile("%s/index.mjs" % source_dir) and not os.path.isfile("%s/package.json" % source_dir): - print("Zipped actions must contain either package.json or index.[m]js at the root.") + print("Zipped functions must contain either package.json or index.[m]js at the root.") sys.exit(1) main_file = "" diff --git a/core/nodejsActionBase/runner.js b/core/nodejsActionBase/runner.js index 8c45bf9f..2c401843 100644 --- a/core/nodejsActionBase/runner.js +++ b/core/nodejsActionBase/runner.js @@ -50,7 +50,7 @@ function initializeActionHandler(message) { const indexJSExists = fs.existsSync('index.js') const indexMJSExists = fs.existsSync('index.mjs') if (index === undefined && !packageJsonExists && !indexJSExists && !indexMJSExists) { - return Promise.reject('Zipped actions must contain either package.json or index.[m]js at the root.'); + return Promise.reject('Zipped functions must contain either package.json or index.[m]js at the root.'); } let mainFile @@ -183,14 +183,14 @@ function unzipInTmpDir(zipFileContents) { const zipFile = path.join(tmpDir, "action.zip"); fs.writeFile(zipFile, zipFileContents, "base64", err => { if (!err) resolve(zipFile); - else reject("There was an error reading the action archive."); + else reject("There was an error reading the function archive."); }); }); }).then(zipFile => { return exec(mkTempCmd).then(tmpDir => { return exec("unzip -qq " + zipFile + " -d " + tmpDir) .then(res => path.resolve(tmpDir)) - .catch(error => Promise.reject("There was an error uncompressing the action archive.")); + .catch(error => Promise.reject("There was an error uncompressing the function archive.")); }); }); } @@ -228,7 +228,7 @@ function assertMainIsFunction(handler, name) { if (typeof handler === 'function') { return Promise.resolve(handler); } else { - return Promise.reject("Action entrypoint '" + name + "' is not a function."); + return Promise.reject("Function entrypoint '" + name + "' is not a function."); } } diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala index 9db8665a..53b9fddb 100644 --- a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala +++ b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala @@ -749,7 +749,7 @@ abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with Ws checkStreams(out, err, { case (o, e) => - (o + e).toLowerCase should include("zipped actions must contain either package.json or index.[m]js at the root.") + (o + e).toLowerCase should include("zipped functions must contain either package.json or index.[m]js at the root.") }) } From 939afcb0eb6c5e3ff54980a7d46446f35053e9ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Fri, 3 Feb 2023 11:52:44 +0100 Subject: [PATCH 22/29] Downgrade npm to version 8 to fix UID remapping issues (#19) Recently, the Node.js docker image was updated from 18.13.0 to 18.14.0 which also caused an npm upgrade from 8.19.3 to 9.3.1. The 9.x series of npm has made changes in that it stops mucking with the ownership of the installed node_modules. That's causing us trouble right now. A discussion of the matter can be found in https://github.com/npm/cli/issues/5889. Downgrading npm to 8.x unwedges the issue for now. --- core/nodejs18Action/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/nodejs18Action/Dockerfile b/core/nodejs18Action/Dockerfile index 3f0c0428..f9767fe5 100644 --- a/core/nodejs18Action/Dockerfile +++ b/core/nodejs18Action/Dockerfile @@ -53,6 +53,9 @@ COPY package.json / # Customize runtime with additional packages. # Install package globally so user packages can override. RUN cd / \ + # Pinning npm to version 8 as 9 has known issues around UID. + # See https://github.com/npm/cli/issues/5889 for example. + && npm i -g npm@8 \ && npm install --no-package-lock --omit=dev \ && npm cache clean --force From 148f986a43f5b923f665aa3e22725dbcaf5ae08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Tue, 2 May 2023 17:08:35 +0200 Subject: [PATCH 23/29] SERVERLESS-2806 Move stretch repositories to archive (#20) The debian stretch repositories have been moved to the archive. To ensure we can still build from the same base image, this fixes the respective sources to pull from the archive. --- core/nodejs14Action/Dockerfile | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/nodejs14Action/Dockerfile b/core/nodejs14Action/Dockerfile index e56a715a..658c4cbd 100644 --- a/core/nodejs14Action/Dockerfile +++ b/core/nodejs14Action/Dockerfile @@ -40,12 +40,15 @@ FROM node:14-stretch ARG GO_PROXY_BUILD_FROM=source # Initial update and some basics. -# -RUN apt-get update && apt-get install -y \ - imagemagick \ - graphicsmagick \ - unzip \ - && rm -rf /var/lib/apt/lists/* +# Replace debian sources with debian archive since stretch has been pulled from the main repos. +RUN sed -i s/deb.debian.org/archive.debian.org/g /etc/apt/sources.list \ + && sed -i 's|security.debian.org|archive.debian.org/|g' /etc/apt/sources.list \ + && sed -i '/stretch-updates/d' /etc/apt/sources.list \ + && apt-get update && apt-get install -y \ + imagemagick \ + graphicsmagick \ + unzip \ + && rm -rf /var/lib/apt/lists/* # Copy the package.json to root container, # so npm packages from user functions take precendence. From 279d12d3c29bf7ec5a09ea8a0cba1eb0481a6dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Thu, 11 May 2023 17:09:45 +0200 Subject: [PATCH 24/29] SERVERLESS-2833 Write sentinels straight to stdout/stderr (#22) This changes the sentinels to be written directly to FD1 (stdout) and FD2 (stderr) to avoid users tampering with how the sentinels get written and thus break our expectations towards how the sentinels are written. This has been an issue with customers when they used packages like log-timestamp to patch the console functions to output timestamps as well. --- core/nodejsActionBase/launcher.js | 13 +++++---- core/nodejsActionBase/prelauncher.js | 13 +++++---- .../NodeJsActionContainerTests.scala | 27 +++++++++++++++++++ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/core/nodejsActionBase/launcher.js b/core/nodejsActionBase/launcher.js index 0de45300..d89af56b 100644 --- a/core/nodejsActionBase/launcher.js +++ b/core/nodejsActionBase/launcher.js @@ -16,11 +16,10 @@ */ const useLambdaRunner = require('/nodejsAction/useLambdaRunner'); +const readline = require('readline'); +const fs = require("fs") try { - const readline = require('readline'); - const fs = require("fs") - const { NodeActionRunner } = require('/nodejsAction/runner'); const NodeActionLambdaRunner = (() => { try { @@ -75,7 +74,11 @@ try { process.exit(1) } +// Create explicit stdout and stderr streams for the sentinels to avoid users tampering with the output. +const stdout = fs.createWriteStream(null, {fd: 1, encoding: "utf8"}) +const stderr = fs.createWriteStream(null, {fd: 2, encoding: "utf8"}) + function writeMarkers() { - console.log('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX'); - console.error('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX'); + stdout.write('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX\n'); + stderr.write('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX\n'); } diff --git a/core/nodejsActionBase/prelauncher.js b/core/nodejsActionBase/prelauncher.js index 61f2a354..4f9c0f0d 100755 --- a/core/nodejsActionBase/prelauncher.js +++ b/core/nodejsActionBase/prelauncher.js @@ -18,11 +18,10 @@ */ const useLambdaRunner = require('/nodejsAction/useLambdaRunner'); +const readline = require('readline'); +const fs = require("fs") try { - const readline = require('readline'); - const fs = require("fs") - const { NodeActionRunner, initializeActionHandler } = require('/nodejsAction/runner'); const NodeActionLambdaRunner = (() => { try { @@ -106,7 +105,11 @@ try { process.exit(1) } +// Create explicit stdout and stderr streams for the sentinels to avoid users tampering with the output. +const stdout = fs.createWriteStream(null, {fd: 1, encoding: "utf8"}) +const stderr = fs.createWriteStream(null, {fd: 2, encoding: "utf8"}) + function writeMarkers() { - console.log('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX'); - console.error('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX'); + stdout.write('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX\n'); + stderr.write('XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX\n'); } diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala index 53b9fddb..ad91d689 100644 --- a/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala +++ b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala @@ -928,6 +928,33 @@ abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with Ws } } + it should "allow the user to tamper with console functions" in { + assume(!isTypeScript) + val (out, err) = withNodeJsContainer { c => + val code = """ + | function main() { + | const baseLog = console.log + | console.log = function(arg) { + | baseLog("foo " + arg) + | } + | } + """.stripMargin; + + val (initCode, _) = c.init(initPayload(code)) + initCode should be(200) + + val (runCode, runRes) = c.run(runPayload(JsObject())) + runCode should be(200) + + runRes shouldBe defined + } + checkStreams(out, err, { + case (o, e) => + o shouldBe empty + e shouldBe empty + }) + } + it should "have openwhisk package available through an ES module import" in { val (out, err) = withNodeJsContainer { c => val code = From 56451ef109a218f01a8784216ba9d54a490430e1 Mon Sep 17 00:00:00 2001 From: jkosanam Date: Wed, 21 Jan 2026 10:27:12 +0530 Subject: [PATCH 25/29] Added nodejs22 support --- README.md | 21 ++++- core/nodejs22Action/CHANGELOG.md | 30 +++++++ core/nodejs22Action/Dockerfile | 84 +++++++++++++++++++ core/nodejs22Action/build.gradle | 66 +++++++++++++++ tests/dat/docker/nodejs22docker/Dockerfile | 19 +++++ tests/dat/docker/nodejs22docker/build.gradle | 19 +++++ tests/dat/docker/nodejs22docker/package.json | 8 ++ .../NodeJs22ActionContainerTests.scala | 27 ++++++ 8 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 core/nodejs22Action/CHANGELOG.md create mode 100644 core/nodejs22Action/Dockerfile create mode 100644 core/nodejs22Action/build.gradle create mode 100644 tests/dat/docker/nodejs22docker/Dockerfile create mode 100644 tests/dat/docker/nodejs22docker/build.gradle create mode 100644 tests/dat/docker/nodejs22docker/package.json create mode 100644 tests/src/test/scala/runtime/actionContainers/NodeJs22ActionContainerTests.scala diff --git a/README.md b/README.md index 9cbe8bfb..df236c8a 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ The following Node.js runtime versions (with kind & image labels) are generated - Node.js 10.23.0 (`nodejs:10` & `openwhisk/action-nodejs-v10`) - Node.js 12.19.1 (`nodejs:12` & `openwhisk/action-nodejs-v12`) - Node.js 14.15.1 (`nodejs:14` & `openwhisk/action-nodejs-v14`) +- Node.js 18.x (`nodejs:18` & `openwhisk/action-nodejs-v18`) +- Node.js 22.x (`nodejs:22` & `openwhisk/action-nodejs-v22`) This README documents the build, customisation and testing of these runtime images. @@ -56,6 +58,18 @@ wsk action update myAction myAction.js --kind nodejs:12 wsk action update myAction myAction.js --kind nodejs:14 ``` +### Node.js v18 + +``` +wsk action update myAction myAction.js --kind nodejs:18 +``` + +### Node.js v22 + +``` +wsk action update myAction myAction.js --kind nodejs:22 +``` + ## Images All the runtime images are published by the project to Docker Hub @ [https://hub.docker.com/u/openwhisk](https://hub.docker.com/u/openwhisk) @@ -63,6 +77,8 @@ All the runtime images are published by the project to Docker Hub @ [https://hub - [https://hub.docker.com/r/openwhisk/action-nodejs-v10](https://hub.docker.com/r/openwhisk/action-nodejs-v10) - [https://hub.docker.com/r/openwhisk/action-nodejs-v12](https://hub.docker.com/r/openwhisk/action-nodejs-v12) - [https://hub.docker.com/r/openwhisk/action-nodejs-v14](https://hub.docker.com/r/openwhisk/action-nodejs-v14) +- [https://hub.docker.com/r/openwhisk/action-nodejs-v18](https://hub.docker.com/r/openwhisk/action-nodejs-v18) +- [https://hub.docker.com/r/openwhisk/action-nodejs-v22](https://hub.docker.com/r/openwhisk/action-nodejs-v22) These images can be used to execute Node.js actions on any deployment of Apache OpenWhisk, even those without those images defined the in runtime manifest, using the `--docker` action parameter. @@ -92,9 +108,11 @@ The `core/nodejsActionBase` folder contains the Node.js app server used to imple ./gradlew core:nodejs10Action:distDocker ./gradlew core:nodejs12Action:distDocker ./gradlew core:nodejs14Action:distDocker +./gradlew core:nodejs18Action:distDocker +./gradlew core:nodejs22Action:distDocker ``` -This will return the following runtime images with the following names: `action-nodejs-v10`, `action-nodejs-v12` and `action-nodejs-v14`. +This will return the following runtime images with the following names: `action-nodejs-v10`, `action-nodejs-v12`, `action-nodejs-v14`, `action-nodejs-v18` and `action-nodejs-v22`. ### Testing @@ -113,6 +131,7 @@ This will return the following runtime images with the following names: `action- ./gradlew tests:dat:docker:nodejs10docker:distDocker ./gradlew tests:dat:docker:nodejs12docker:distDocker ./gradlew tests:dat:docker:nodejs14docker:distDocker +./gradlew tests:dat:docker:nodejs22docker:distDocker ``` - Run the project tests. diff --git a/core/nodejs22Action/CHANGELOG.md b/core/nodejs22Action/CHANGELOG.md new file mode 100644 index 00000000..def5abab --- /dev/null +++ b/core/nodejs22Action/CHANGELOG.md @@ -0,0 +1,30 @@ + + +# NodeJS 22 OpenWhisk Runtime Container + +# Next Release +Node.js version = [22.12.0](https://nodejs.org/en/blog/release/v22.12.0/) + +## Initial Release +Changes: + - Initial release with support for Node.js v22 + +Node.js version = [22.12.0](https://nodejs.org/en/blog/release/v22.12.0/) +OpenWhisk version = [OpenWhisk v3.21.3](https://www.npmjs.com/package/openwhisk) diff --git a/core/nodejs22Action/Dockerfile b/core/nodejs22Action/Dockerfile new file mode 100644 index 00000000..2dc39e7c --- /dev/null +++ b/core/nodejs22Action/Dockerfile @@ -0,0 +1,84 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# build go proxy from source +ARG GO_PROXY_BASE_IMAGE=golang:1.22 +FROM $GO_PROXY_BASE_IMAGE AS builder + +ARG GO_PROXY_GITHUB_USER=nimbella-corp +ARG GO_PROXY_GITHUB_BRANCH=dev +RUN git clone --branch ${GO_PROXY_GITHUB_BRANCH} https://github.com/${GO_PROXY_GITHUB_USER}/openwhisk-runtime-go /src \ + && cd /src \ + && env GO111MODULE=on CGO_ENABLED=0 go build -o /bin/proxy main/proxy.go + +FROM node:22-bookworm-slim + +# Initial update and some basics. +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + # For npm to work properly. + git \ + ssh \ + ca-certificates \ + # For the proxy. + unzip \ + python3 \ + # For function-deployer install + curl \ + # Dependencies for the users. + graphicsmagick \ + imagemagick \ + && update-ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Copy the package.json to root container, +# so npm packages from user functions take precendence. +WORKDIR /nodejsAction +COPY package.json / + +# Customize runtime with additional packages. +# Install package globally so user packages can override. +RUN cd / \ + && npm install --no-package-lock --omit=dev \ + && npm cache clean --force + +# Copy sources in after copying in package.json and running npm install to +# enable faster builds after only sources change. +COPY . /nodejsAction/ + +# install the functions-deployer +ARG DEPLOYER_DOWNLOAD +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +RUN curl -L ${DEPLOYER_DOWNLOAD} | tar xzf - \ + && rm -fr /usr/local/lib/dosls && mv dosls /usr/local/lib \ + && rm -f /usr/local/bin/dosls && ln -s /usr/local/lib/dosls/bootstrap /usr/local/bin/dosls + +ARG __OW_LAMBDA_COMPAT +ENV __OW_LAMBDA_COMPAT=$__OW_LAMBDA_COMPAT + +COPY bin/compile /bin/compile +ENV OW_COMPILER=/bin/compile + +# log initialization errors +ENV OW_LOG_INIT_ERROR=1 +# the launcher must wait for an ack +ENV OW_WAIT_FOR_ACK=1 + +ENV OW_INIT_IN_ACTIONLOOP=/nodejsAction/prelauncher.js + +COPY --from=builder /bin/proxy /bin/proxy +ENTRYPOINT [ "/bin/proxy" ] diff --git a/core/nodejs22Action/build.gradle b/core/nodejs22Action/build.gradle new file mode 100644 index 00000000..4e17805e --- /dev/null +++ b/core/nodejs22Action/build.gradle @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'eclipse' +eclipse { + project { + natures 'org.eclipse.wst.jsdt.core.jsNature' + buildCommand 'org.eclipse.wst.jsdt.core.javascriptValidator' + } +} + +ext.dockerImageName = 'action-nodejs-v22' +apply from: '../../gradle/docker.gradle' + +distDocker.dependsOn 'copyPackageJson' +distDocker.dependsOn 'copyRunner' +distDocker.dependsOn 'copyCompile' +distDocker.finalizedBy('cleanup') + +task copyPackageJson(type: Copy) { + from '../nodejsActionBase/package.json' + into '.' +} + +task copyRunner(type: Copy) { + from '../nodejsActionBase/runner.js' + into '.' + + from '../nodejsActionBase/lambda.js' + into '.' + + from '../nodejsActionBase/nim.js' + into '.' + + from '../nodejsActionBase/launcher.js' + into '.' +} + +task copyCompile(type: Copy) { + from '../nodejsActionBase/bin/compile' + into './bin' +} + +task cleanup(type: Delete) { + delete 'package.json' + delete 'launcher.js' + delete 'lambda.js' + delete 'nim.js' + delete 'runner.js' + delete 'src' + delete 'bin' +} diff --git a/tests/dat/docker/nodejs22docker/Dockerfile b/tests/dat/docker/nodejs22docker/Dockerfile new file mode 100644 index 00000000..3ca04720 --- /dev/null +++ b/tests/dat/docker/nodejs22docker/Dockerfile @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +FROM action-nodejs-v22 +COPY package.json . +RUN npm install --production diff --git a/tests/dat/docker/nodejs22docker/build.gradle b/tests/dat/docker/nodejs22docker/build.gradle new file mode 100644 index 00000000..8022bb09 --- /dev/null +++ b/tests/dat/docker/nodejs22docker/build.gradle @@ -0,0 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +ext.dockerImageName = 'nodejs22docker' +apply from: '../../../../gradle/docker.gradle' diff --git a/tests/dat/docker/nodejs22docker/package.json b/tests/dat/docker/nodejs22docker/package.json new file mode 100644 index 00000000..6822c092 --- /dev/null +++ b/tests/dat/docker/nodejs22docker/package.json @@ -0,0 +1,8 @@ +{ + "name": "testdocker", + "version": "1.0.0", + "main": "index.js", + "dependencies": { + "openwhisk": "2.0.0" + } +} diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJs22ActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJs22ActionContainerTests.scala new file mode 100644 index 00000000..3e45f5f1 --- /dev/null +++ b/tests/src/test/scala/runtime/actionContainers/NodeJs22ActionContainerTests.scala @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package runtime.actionContainers + +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class NodeJs22ActionContainerTests extends NodeJsActionContainerTests { + override lazy val nodejsContainerImageName = "action-nodejs-v22" + override lazy val nodejsTestDockerImageName = "nodejs22docker" +} From da9fff6dc912af49d6752907d9a5fa7aa6d4bbba Mon Sep 17 00:00:00 2001 From: jkosanam Date: Wed, 21 Jan 2026 12:34:19 +0530 Subject: [PATCH 26/29] removed changelog --- core/nodejs22Action/CHANGELOG.md | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 core/nodejs22Action/CHANGELOG.md diff --git a/core/nodejs22Action/CHANGELOG.md b/core/nodejs22Action/CHANGELOG.md deleted file mode 100644 index def5abab..00000000 --- a/core/nodejs22Action/CHANGELOG.md +++ /dev/null @@ -1,30 +0,0 @@ - - -# NodeJS 22 OpenWhisk Runtime Container - -# Next Release -Node.js version = [22.12.0](https://nodejs.org/en/blog/release/v22.12.0/) - -## Initial Release -Changes: - - Initial release with support for Node.js v22 - -Node.js version = [22.12.0](https://nodejs.org/en/blog/release/v22.12.0/) -OpenWhisk version = [OpenWhisk v3.21.3](https://www.npmjs.com/package/openwhisk) From eb1c28d494a5738dea10bc894199e12e0341c2e1 Mon Sep 17 00:00:00 2001 From: jkosanam Date: Wed, 21 Jan 2026 12:38:14 +0530 Subject: [PATCH 27/29] removed readme changes --- README.md | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/README.md b/README.md index df236c8a..9cbe8bfb 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,6 @@ The following Node.js runtime versions (with kind & image labels) are generated - Node.js 10.23.0 (`nodejs:10` & `openwhisk/action-nodejs-v10`) - Node.js 12.19.1 (`nodejs:12` & `openwhisk/action-nodejs-v12`) - Node.js 14.15.1 (`nodejs:14` & `openwhisk/action-nodejs-v14`) -- Node.js 18.x (`nodejs:18` & `openwhisk/action-nodejs-v18`) -- Node.js 22.x (`nodejs:22` & `openwhisk/action-nodejs-v22`) This README documents the build, customisation and testing of these runtime images. @@ -58,18 +56,6 @@ wsk action update myAction myAction.js --kind nodejs:12 wsk action update myAction myAction.js --kind nodejs:14 ``` -### Node.js v18 - -``` -wsk action update myAction myAction.js --kind nodejs:18 -``` - -### Node.js v22 - -``` -wsk action update myAction myAction.js --kind nodejs:22 -``` - ## Images All the runtime images are published by the project to Docker Hub @ [https://hub.docker.com/u/openwhisk](https://hub.docker.com/u/openwhisk) @@ -77,8 +63,6 @@ All the runtime images are published by the project to Docker Hub @ [https://hub - [https://hub.docker.com/r/openwhisk/action-nodejs-v10](https://hub.docker.com/r/openwhisk/action-nodejs-v10) - [https://hub.docker.com/r/openwhisk/action-nodejs-v12](https://hub.docker.com/r/openwhisk/action-nodejs-v12) - [https://hub.docker.com/r/openwhisk/action-nodejs-v14](https://hub.docker.com/r/openwhisk/action-nodejs-v14) -- [https://hub.docker.com/r/openwhisk/action-nodejs-v18](https://hub.docker.com/r/openwhisk/action-nodejs-v18) -- [https://hub.docker.com/r/openwhisk/action-nodejs-v22](https://hub.docker.com/r/openwhisk/action-nodejs-v22) These images can be used to execute Node.js actions on any deployment of Apache OpenWhisk, even those without those images defined the in runtime manifest, using the `--docker` action parameter. @@ -108,11 +92,9 @@ The `core/nodejsActionBase` folder contains the Node.js app server used to imple ./gradlew core:nodejs10Action:distDocker ./gradlew core:nodejs12Action:distDocker ./gradlew core:nodejs14Action:distDocker -./gradlew core:nodejs18Action:distDocker -./gradlew core:nodejs22Action:distDocker ``` -This will return the following runtime images with the following names: `action-nodejs-v10`, `action-nodejs-v12`, `action-nodejs-v14`, `action-nodejs-v18` and `action-nodejs-v22`. +This will return the following runtime images with the following names: `action-nodejs-v10`, `action-nodejs-v12` and `action-nodejs-v14`. ### Testing @@ -131,7 +113,6 @@ This will return the following runtime images with the following names: `action- ./gradlew tests:dat:docker:nodejs10docker:distDocker ./gradlew tests:dat:docker:nodejs12docker:distDocker ./gradlew tests:dat:docker:nodejs14docker:distDocker -./gradlew tests:dat:docker:nodejs22docker:distDocker ``` - Run the project tests. From a3b7ed65eb1ab4ddaf2b2793f350c4a6a493b6d9 Mon Sep 17 00:00:00 2001 From: jkosanam Date: Wed, 21 Jan 2026 12:48:51 +0530 Subject: [PATCH 28/29] Removed nodejs22 test docker as we are not deploying the image --- tests/dat/docker/nodejs22docker/Dockerfile | 19 ------------------- tests/dat/docker/nodejs22docker/build.gradle | 19 ------------------- tests/dat/docker/nodejs22docker/package.json | 8 -------- 3 files changed, 46 deletions(-) delete mode 100644 tests/dat/docker/nodejs22docker/Dockerfile delete mode 100644 tests/dat/docker/nodejs22docker/build.gradle delete mode 100644 tests/dat/docker/nodejs22docker/package.json diff --git a/tests/dat/docker/nodejs22docker/Dockerfile b/tests/dat/docker/nodejs22docker/Dockerfile deleted file mode 100644 index 3ca04720..00000000 --- a/tests/dat/docker/nodejs22docker/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -FROM action-nodejs-v22 -COPY package.json . -RUN npm install --production diff --git a/tests/dat/docker/nodejs22docker/build.gradle b/tests/dat/docker/nodejs22docker/build.gradle deleted file mode 100644 index 8022bb09..00000000 --- a/tests/dat/docker/nodejs22docker/build.gradle +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -ext.dockerImageName = 'nodejs22docker' -apply from: '../../../../gradle/docker.gradle' diff --git a/tests/dat/docker/nodejs22docker/package.json b/tests/dat/docker/nodejs22docker/package.json deleted file mode 100644 index 6822c092..00000000 --- a/tests/dat/docker/nodejs22docker/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "testdocker", - "version": "1.0.0", - "main": "index.js", - "dependencies": { - "openwhisk": "2.0.0" - } -} From d0519b63dce1b465d8989da70455feaaa18a05df Mon Sep 17 00:00:00 2001 From: jkosanam Date: Wed, 21 Jan 2026 15:23:22 +0530 Subject: [PATCH 29/29] Empty commit to add tag --- core/nodejs22Action/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/nodejs22Action/Dockerfile b/core/nodejs22Action/Dockerfile index 2dc39e7c..2a3ce91d 100644 --- a/core/nodejs22Action/Dockerfile +++ b/core/nodejs22Action/Dockerfile @@ -30,7 +30,7 @@ FROM node:22-bookworm-slim # Initial update and some basics. RUN apt-get update \ && apt-get install -y --no-install-recommends \ - # For npm to work properly. + # For npm to work properly git \ ssh \ ca-certificates \