This is an automated email from the ASF dual-hosted git repository.

mrutkowski pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/incubator-openwhisk-devtools.git


The following commit(s) were added to refs/heads/master by this push:
     new 6c50a64  Package action source along with its dependencies (#266)
6c50a64 is described below

commit 6c50a64602bda13cf302382359d49cb8dc4713f9
Author: Priti Desai <[email protected]>
AuthorDate: Fri Jun 28 07:22:03 2019 -0700

    Package action source along with its dependencies (#266)
    
    * read file if exists locally before downloading it
    
    * base64 for zip contents
    
    * adding marshal resources
    
    * adding more changes for packaging
    
    * adding more changes to package node
    
    * adding more changes to package node
    
    * adding more changes to package node
    
    * adding marshalresource
    
    * adding marshalresource
    
    * packaging npm actions
    
    * packaging npm actions
    
    * packaging npm actions
    
    * adding marshalresource
    
    * packaging npm actions
    
    * adding zip to runtime
    
    * adding init run json payload
    
    * removing debug statements
    
    * updating build template
    
    * updating build template
    
    * checking if path exists
    
    * adding production mode during npm install
---
 knative-build/runtimes/javascript/Dockerfile       |  1 +
 .../runtimes/javascript/buildtemplate.yaml         | 23 +++++--
 .../runtimes/javascript/platform/knative.js        | 78 ++++++++++++++++++++++
 .../javascript/tests/packageaction/build.yaml.tmpl | 29 ++++++++
 .../tests/packageaction/knative-data-init-run.json | 20 ++++++
 .../tests/packageaction/knative-data-init.json     |  8 +++
 .../tests/packageaction/knative-data-run.json      | 13 ++++
 .../tests/packageaction/service.yaml.tmpl          | 12 ++++
 8 files changed, 177 insertions(+), 7 deletions(-)

diff --git a/knative-build/runtimes/javascript/Dockerfile 
b/knative-build/runtimes/javascript/Dockerfile
index 621fcc7..9e5a7a7 100644
--- a/knative-build/runtimes/javascript/Dockerfile
+++ b/knative-build/runtimes/javascript/Dockerfile
@@ -18,6 +18,7 @@
 FROM node:10.15.0-stretch
 RUN apt-get update && apt-get install -y \
     imagemagick \
+    zip \
     unzip \
     && rm -rf /var/lib/apt/lists/*
 WORKDIR /nodejsAction
diff --git a/knative-build/runtimes/javascript/buildtemplate.yaml 
b/knative-build/runtimes/javascript/buildtemplate.yaml
index 0760ced..9de87e8 100644
--- a/knative-build/runtimes/javascript/buildtemplate.yaml
+++ b/knative-build/runtimes/javascript/buildtemplate.yaml
@@ -51,13 +51,21 @@ spec:
       if [ -z ${OW_PROJECT_URL} ]; then
         OW_ACTION_CODE="${OW_ACTION_CODE}"
       else
-        TEMPDIR="knative-"$((1 + RANDOM % 100))
-        TEMPFILE=`basename "${OW_PROJECT_URL}"`
-        mkdir $TEMPDIR
-        cd $TEMPDIR
-        wget -O $TEMPFILE "${OW_PROJECT_URL}"
-        OW_ACTION_CODE=`cat $TEMPFILE`
-        cd ..
+        if [ -f ${OW_PROJECT_URL} ]; then
+          if [ ${OW_ACTION_BINARY} ]; then
+            OW_ACTION_CODE=`base64 ${OW_PROJECT_URL}`
+          else
+            OW_ACTION_CODE=`cat ${OW_PROJECT_URL}`
+          fi
+        else
+            TEMPDIR="knative-"$((1 + RANDOM % 100))
+            TEMPFILE=`basename "${OW_PROJECT_URL}"`
+            mkdir $TEMPDIR
+            cd $TEMPDIR
+            wget -O $TEMPFILE "${OW_PROJECT_URL}"
+            OW_ACTION_CODE=`cat $TEMPFILE`
+            cd ..
+        fi
       fi
       cat <<EOF >> ${DOCKERFILE}
         ENV __OW_RUNTIME_DEBUG "${OW_RUNTIME_DEBUG}"
@@ -68,6 +76,7 @@ spec:
         ENV __OW_ACTION_BINARY "${OW_ACTION_BINARY}"
         ENV __OW_HTTP_METHODS "${OW_HTTP_METHODS}"
         ENV __OW_ACTION_RAW "${OW_ACTION_RAW}"
+        ENV __OW_PROJECT_URL "${OW_PROJECT_URL}"
       EOF
   - name: build-openwhisk-nodejs-runtime
     image: "gcr.io/kaniko-project/executor:latest"
diff --git a/knative-build/runtimes/javascript/platform/knative.js 
b/knative-build/runtimes/javascript/platform/knative.js
index 442381c..eb741fe 100644
--- a/knative-build/runtimes/javascript/platform/knative.js
+++ b/knative-build/runtimes/javascript/platform/knative.js
@@ -93,6 +93,7 @@ function createInitDataFromEnvironment(env) {
         // 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";
+        initdata.url = (typeof env.__OW_PROJECT_URL === 'undefined') ? "" : 
env.__OW_PROJECT_URL;
 
         DEBUG.dumpObject(initdata, "initdata");
         return initdata;
@@ -135,6 +136,9 @@ function preProcessInitData(initdata, valuedata, 
activationdata) {
                     throw ("Invalid Init. data; expected boolean for key 
'raw'.");
                 }
             }
+            if (initdata.url && typeof initdata.url === 'string') {
+                valuedata.url = initdata.url;
+            }
 
             // 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
@@ -249,6 +253,78 @@ function preProcessActivationData(env, activationdata) {
 }
 
 /**
+ * For actions having dependency on third party NPM modules, NodeJS runtime 
would
+ * install those NPM modules and package them as part of the action source 
using this function.
+ * In this function, runtime reads url from the initialization JSON payload,
+ * if the url points to an existing directory, run:
+ *      cd initdata.url && npm install --production && zip -r action.zip . && 
base64 action.zip
+ * Packaging actions as NodeJS module with NPM libraries are treated as zip 
actions by the runtime.
+ * Zipped actions must contain either package.json or index.js at the root.
+ * This validation is left to the user and not enforced while initializing the 
action.
+ */
+function marshalResources(initData, valueData) {
+    DEBUG.functionStart();
+    try {
+        // check if url is set and assigned some string value
+        if (typeof initData.url === "string" && initData.url !== undefined) {
+            const fs = require('fs');
+            if (fs.existsSync(initData.url)) {
+                const stats = fs.lstatSync(initData.url);
+                // check if specified url is an existing directory
+                if (stats.isDirectory()) {
+                    // import spawnSync routine from child_process NPM module
+                    // spawnSync spawns a new process using the given command 
and does not return until
+                    // the child process is fully closed/finished executing.
+                    // Note: Be very careful changing any of the child_process 
and spwanSync functionality
+                    DEBUG.dumpObject("Starting to install NPM modules from " + 
initData.url, "process packaging - npm", "marshalResources")
+                    const {spawnSync} = require('child_process'),
+                        npm = spawnSync('npm', ['install', '--production'], 
{cwd: initData.url});
+                    DEBUG.dumpObject(`stdout: 
${npm.stdout.toString().trim()}`, "npm install", "marshalResources");
+                    DEBUG.dumpObject(`stderr: 
${npm.stderr.toString().trim()}`, "npm install", "marshalResources");
+                    if (npm.status !== 0) {
+                        throw (npm.error);
+                    }
+
+                    var zipFile = "action.zip";
+                    // note here we are using same instance of spwanSync as we 
used for running npm install
+                    // to make sure the execution of zip command follows right 
after npm install closes (sequential)
+                    DEBUG.dumpObject("Starting to compress action resources at 
" + initData.url, "process packaging - zip", "marshalResources")
+                    const compressFile = spawnSync('zip', ['-r', zipFile, 
'.'], {cwd: initData.url});
+                    DEBUG.dumpObject(`stdout: 
${compressFile.stdout.toString().trim()}`, "zip -r action.zip *", 
"marshalResources");
+                    DEBUG.dumpObject(`stderr: 
${compressFile.stderr.toString().trim()}`, "zip -r action.zip *", 
"marshalResources");
+                    if (compressFile.status !== 0) {
+                        throw (compressFile.error);
+                    }
+
+                    // and same here, making sure base64 command follows right 
after zip command finishes by
+                    // using the same spawnSync instance of child_process.
+                    DEBUG.dumpObject("Starting to decode compressed action 
resource", "process packaging - base64", "marshalResources")
+                    const code = spawnSync('base64', [initData.url + '/' + 
zipFile]);
+                    DEBUG.dumpObject(`stdout: 
${code.stdout.toString().trim()}`, "base64 action.zip", "marshalResources");
+                    DEBUG.dumpObject(`stderr: 
${code.stderr.toString().trim()}`, "base64 action.zip", "marshalResources");
+                    if (code.status !== 0) {
+                        throw (code.error);
+                    }
+
+                    // assign base64 encoded zip file content to action code 
before initializing the action
+                    initData.code = code.stdout.toString().trim();
+                    valueData.code = initData.code;
+
+                    // mark this action as binary so that run routine can 
decode it appropriately
+                    initData.binary = true;
+                    valueData.binary = true;
+                }
+            }
+        }
+    } catch (e) {
+        console.error(e);
+        DEBUG.functionEndError("");
+        throw("Unable to marshall NPM resources: ");
+    }
+    DEBUG.functionEnd()
+}
+
+/**
  * Pre-process the incoming http request data, moving it to where the
  * route handlers expect it to be for an openwhisk runtime.
  */
@@ -269,6 +345,8 @@ function preProcessRequest(req){
             preProcessInitData(initData, valueData, activationData);
         }
 
+        marshalResources(initData, valueData);
+
         if(hasActivationData(req)) {
             // process HTTP request header and body to make it available to 
function as parameter data
             preProcessHTTPContext(req, valueData);
diff --git 
a/knative-build/runtimes/javascript/tests/packageaction/build.yaml.tmpl 
b/knative-build/runtimes/javascript/tests/packageaction/build.yaml.tmpl
new file mode 100644
index 0000000..1cbe955
--- /dev/null
+++ b/knative-build/runtimes/javascript/tests/packageaction/build.yaml.tmpl
@@ -0,0 +1,29 @@
+apiVersion: build.knative.dev/v1alpha1
+kind: Build
+metadata:
+  name: nodejs-10-package-npm
+spec:
+  serviceAccountName: openwhisk-runtime-builder
+  sources:
+    - name: runtime
+      git:
+        url: "https://github.com/apache/incubator-openwhisk-devtools.git";
+        revision: "master"
+    - name: application
+      targetPath: app
+      git:
+        url: "https://github.com/apache/incubator-openwhisk-test.git";
+        revision: "master"
+  template:
+    name: openwhisk-nodejs-runtime
+    arguments:
+      - name: TARGET_IMAGE_NAME
+        value: "docker.io/${DOCKER_USERNAME}/nodejs-10-package-npm"
+      - name: DOCKERFILE
+        value: "./knative-build/runtimes/javascript/Dockerfile"
+      - name: OW_ACTION_BINARY
+        value: "true"
+      - name: OW_ACTION_NAME
+        value: "nodejs-package-npm"
+      - name: OW_PROJECT_URL
+        value: "./app/packages/left-pad/"
diff --git 
a/knative-build/runtimes/javascript/tests/packageaction/knative-data-init-run.json
 
b/knative-build/runtimes/javascript/tests/packageaction/knative-data-init-run.json
new file mode 100644
index 0000000..96307b0
--- /dev/null
+++ 
b/knative-build/runtimes/javascript/tests/packageaction/knative-data-init-run.json
@@ -0,0 +1,20 @@
+{
+  "init": {
+    "name" : "nodejs-package-npm",
+    "main" : "main",
+    "binary": true,
+    "url" : "app/packages/left-pad/"
+  },
+  "activation": {
+    "namespace": "default",
+    "action_name": "nodejs-package-npm",
+    "api_host": "",
+    "api_key": "",
+    "activation_id": "",
+    "deadline": "4102498800000"
+  },
+  "value": {
+    "lines" : ["Hello","How are you?"]
+  }
+}
+
diff --git 
a/knative-build/runtimes/javascript/tests/packageaction/knative-data-init.json 
b/knative-build/runtimes/javascript/tests/packageaction/knative-data-init.json
new file mode 100644
index 0000000..badd5ec
--- /dev/null
+++ 
b/knative-build/runtimes/javascript/tests/packageaction/knative-data-init.json
@@ -0,0 +1,8 @@
+{
+  "init": {
+    "name" : "nodejs-package-npm",
+    "main" : "main",
+    "binary": true,
+    "url" : "app/packages/left-pad/"
+  }
+}
diff --git 
a/knative-build/runtimes/javascript/tests/packageaction/knative-data-run.json 
b/knative-build/runtimes/javascript/tests/packageaction/knative-data-run.json
new file mode 100644
index 0000000..93ad826
--- /dev/null
+++ 
b/knative-build/runtimes/javascript/tests/packageaction/knative-data-run.json
@@ -0,0 +1,13 @@
+{
+  "activation": {
+    "namespace": "default",
+    "action_name": "nodejs-package-npm",
+    "api_host": "",
+    "api_key": "",
+    "activation_id": "",
+    "deadline": "4102498800000"
+  },
+  "value": {
+    "lines" : ["Hello","How are you?"]
+  }
+}
diff --git 
a/knative-build/runtimes/javascript/tests/packageaction/service.yaml.tmpl 
b/knative-build/runtimes/javascript/tests/packageaction/service.yaml.tmpl
new file mode 100644
index 0000000..3c5a439
--- /dev/null
+++ b/knative-build/runtimes/javascript/tests/packageaction/service.yaml.tmpl
@@ -0,0 +1,12 @@
+apiVersion: serving.knative.dev/v1alpha1
+kind: Service
+metadata:
+  name: nodejs-package-npm
+  namespace: default
+spec:
+  runLatest:
+    configuration:
+      revisionTemplate:
+        spec:
+          container:
+            image: docker.io/${DOCKER_USERNAME}/nodejs-10-package-npm

Reply via email to