Merge pull request #5 from csantanapr/nodejs8

NodeJS 8 Runtime
diff --git a/.gitignore b/.gitignore
index f65f024..52f108d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@
 
 # NodeJS
 node_modules
+package-lock.json
 
 # Vagrant
 .vagrant*
diff --git a/README.md b/README.md
index ff09334..4d6d23d 100644
--- a/README.md
+++ b/README.md
@@ -3,31 +3,58 @@
 
 
 ### Give it a try today
-To use as a docker action
+To use as a docker action for Node.js 6
 ```
-wsk action update myAction myAction.js --docker openwhisk/nodejs6action:1.0.0
+wsk action update myAction myAction.js --docker openwhisk/nodejs6action
+```
+To use as a docker action for Node.js 8
+```
+wsk action update myAction myAction.js --docker openwhisk/action-nodejs-v8
 ```
 This works on any deployment of Apache OpenWhisk
 
 ### To use on deployment that contains the rutime as a kind
-To use as a kind action
+To use as a kind action using Node.js 6
 ```
 wsk action update myAction myAction.js --kind nodejs:6
 ```
+To use as a kind action using Node.js 8
+```
+wsk action update myAction myAction.js --kind nodejs:8
+```
 
 ### Local development
+For Node.js 6
 ```
 ./gradlew core:nodejs6Action:distDocker
 ```
 This will produce the image `whisk/nodejs6action`
 
-Build and Push image
+For Node.js 8
+```
+./gradlew core:nodejs8Action:distDocker
+```
+This will produce the image `whisk/action-nodejs-v8`
+
+
+Build and Push image for Node.js 6
 ```
 docker login
 ./gradlew core:nodejs6Action:distDocker -PdockerImagePrefix=$prefix-user -PdockerRegistry=docker.io 
 ```
 
-Deploy OpenWhisk using ansible environment that contains the kind `nodejs:6`
+Build and Push image for Node.js 8
+```
+docker login
+./gradlew core:nodejs8Action:distDocker -PdockerImagePrefix=$prefix-user -PdockerRegistry=docker.io 
+```
+Then create the action using your image from dockerhub
+```
+wsk action update myAction myAction.js --docker $user_prefix/nodejs6action
+```
+The `$user_prefix` is usually your dockerhub user id.
+
+Deploy OpenWhisk using ansible environment that contains the kind `nodejs:6` and `nodejs:8`
 Assuming you have OpenWhisk already deployed locally and `OPENWHISK_HOME` pointing to root directory of OpenWhisk core repository.
 
 Set `ROOTDIR` to the root directory of this repository.
@@ -49,19 +76,6 @@
 wskdev fresh -t local-nodejs
 ```
 
-To use as docker action push to your own dockerhub account
-```
-docker tag whisk/nodejs6action $user_prefix/nodejs6action
-docker push $user_prefix/nodejs6action
-```
-Then create the action using your image from dockerhub
-```
-wsk action update myAction myAction.js --docker $user_prefix/nodejs6action
-```
-The `$user_prefix` is usually your dockerhub user id.
-
-
-
 # License
 [Apache 2.0](LICENSE.txt)
 
diff --git a/ansible/environments/local/group_vars/all b/ansible/environments/local/group_vars/all
index 3ba8955..925ae29 100755
--- a/ansible/environments/local/group_vars/all
+++ b/ansible/environments/local/group_vars/all
@@ -34,5 +34,10 @@
       image:
         name: "nodejs6action"
       deprecated: false
+    - kind: "nodejs:8"
+      default: false
+      image:
+        name: "action-nodejs-v8"
+      deprecated: false
   blackboxes:
     - name: "dockerskeleton"
diff --git a/core/nodejs8Action/.dockerignore b/core/nodejs8Action/.dockerignore
new file mode 100644
index 0000000..3081e3e
--- /dev/null
+++ b/core/nodejs8Action/.dockerignore
@@ -0,0 +1,8 @@
+node_modules
+package-lock.json
+Dockerfile
+build.gradle
+.project
+.settings
+build.xml
+logs
\ No newline at end of file
diff --git a/core/nodejs8Action/CHANGELOG.md b/core/nodejs8Action/CHANGELOG.md
new file mode 100644
index 0000000..b81a414
--- /dev/null
+++ b/core/nodejs8Action/CHANGELOG.md
@@ -0,0 +1,7 @@
+# NodeJS 8 OpenWhisk Runtime Container
+
+## 1.0.0
+Change: Initial release
+
+Node version = 8.9.1
+- [openwhisk v3.10.0](https://www.npmjs.com/package/openwhisk) - JavaScript client library for the OpenWhisk platform. Provides a wrapper around the OpenWhisk APIs.
\ No newline at end of file
diff --git a/core/nodejs8Action/Dockerfile b/core/nodejs8Action/Dockerfile
new file mode 100644
index 0000000..21771cc
--- /dev/null
+++ b/core/nodejs8Action/Dockerfile
@@ -0,0 +1,11 @@
+FROM node:8.9.1
+RUN apt-get update && apt-get install -y \
+    imagemagick \
+    unzip \
+    && rm -rf /var/lib/apt/lists/*
+WORKDIR /nodejsAction
+COPY . .
+RUN npm install \
+    && npm cache clean --force
+EXPOSE 8080
+CMD node --expose-gc app.js
diff --git a/core/nodejs8Action/build.gradle b/core/nodejs8Action/build.gradle
new file mode 100644
index 0000000..f796acb
--- /dev/null
+++ b/core/nodejs8Action/build.gradle
@@ -0,0 +1,36 @@
+apply plugin: 'eclipse'
+eclipse {
+    project {
+        natures 'org.eclipse.wst.jsdt.core.jsNature'
+        buildCommand 'org.eclipse.wst.jsdt.core.javascriptValidator'
+    }
+}
+
+ext.dockerImageName = 'action-nodejs-v8'
+apply from: '../../gradle/docker.gradle'
+
+distDocker.dependsOn 'copyProxy'
+distDocker.dependsOn 'copyRunner'
+distDocker.dependsOn 'copyService'
+distDocker.finalizedBy('cleanup')
+
+task copyProxy(type: Copy) {
+    from '../nodejsActionBase/app.js'
+    into '.'
+}
+
+task copyRunner(type: Copy) {
+    from '../nodejsActionBase/runner.js'
+    into '.'
+}
+
+task copyService(type: Copy) {
+    from '../nodejsActionBase/src/service.js'
+    into './src'
+}
+
+task cleanup(type: Delete) {
+    delete 'app.js'
+    delete 'runner.js'
+    delete 'src'
+}
\ No newline at end of file
diff --git a/core/nodejs8Action/package.json b/core/nodejs8Action/package.json
new file mode 100644
index 0000000..e715dc5
--- /dev/null
+++ b/core/nodejs8Action/package.json
@@ -0,0 +1,15 @@
+{
+  "name": "action-nodejs-v8",
+  "version": "1.0.0",
+  "description": "Apache OpenWhisk NodeJS Runtime",
+  "repository": {
+    "type": "git",
+    "url": "git@github.com:apache/incubator-openwhisk-runtime-nodejs.git"
+  },
+  "license": "Apache-2.0",
+  "dependencies": {
+    "openwhisk": "3.10.0",
+    "body-parser": "1.18.2",
+    "express": "4.16.2"
+  }
+}
diff --git a/core/nodejsActionBase/app.js b/core/nodejsActionBase/app.js
index eb81856..2da2b89 100644
--- a/core/nodejsActionBase/app.js
+++ b/core/nodejsActionBase/app.js
@@ -25,12 +25,11 @@
 
 var app = express();
 
-var logger  = require('./src/logger').getLogger('logs/nodejsaction.log', 'nodejsAction');
 
 /**
  * instantiate an object which handles REST calls from the Invoker
  */
-var service = require('./src/service').getService(config, logger);
+var service = require('./src/service').getService(config);
 
 app.set('port', config.port);
 app.use(bodyParser.json({ limit: "48mb" }));
@@ -65,7 +64,7 @@
                 if (typeof error.code === "number" && typeof error.response !== "undefined") {
                     res.status(error.code).json(error.response);
                 } else {
-                    logger.error("[wrapEndpoint]", "invalid errored promise", JSON.stringify(error));
+                    console.error("[wrapEndpoint]", "invalid errored promise", JSON.stringify(error));
                     res.status(500).json({ error: "Internal error." });
                 }
             });
@@ -73,7 +72,7 @@
             // 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.
-            logger.error("[wrapEndpoint]", "exception caught", e);
+            console.error("[wrapEndpoint]", "exception caught", e.message);
 
             res.status(500).json({ error: "Internal error (exception)." });
         }
diff --git a/core/nodejsActionBase/src/logger.js b/core/nodejsActionBase/src/logger.js
deleted file mode 100644
index bb59857..0000000
--- a/core/nodejsActionBase/src/logger.js
+++ /dev/null
@@ -1,60 +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.
- */
-
-'use strict';
-
-var fs = require('fs');
-var path = require('path');
-var log4js = require('log4js');
-
-function Logger(filename) {
-    this.filename = filename;
-}
-
-Logger.prototype.makeLogger = function makeLogger(category) {
-    var dir = path.dirname(this.filename);
-    if (dir && !fs.existsSync(dir)) {
-        fs.mkdirSync(dir);
-    }
-    log4js.configure(loggerConfig(this.filename));
-    var thelogger = log4js.getLogger(category);
-    thelogger.shutdown = function(cb) {
-        log4js.shutdown(cb);
-    }
-    return thelogger;
-}
-
-Logger.getLogger = function(filename, category) {
-    return new Logger(filename).makeLogger(category);
-}
-
-function loggerConfig(filename) {
-    return {
-        appenders : [ {
-            type : 'dateFile',
-            filename : filename,
-            pattern : "-yyyy-MM-dd",
-            alwaysIncludePattern : true,
-            layout : {
-                type : 'pattern',
-                pattern : "[%d{yyyy-MM-ddThh:mm:ss.SSSO}] [%h] [%p] [%c] %m"
-            }
-        }]
-    };
-}
-
-module.exports = Logger;
diff --git a/core/nodejsActionBase/src/service.js b/core/nodejsActionBase/src/service.js
index 73aac46..536aad4 100644
--- a/core/nodejsActionBase/src/service.js
+++ b/core/nodejsActionBase/src/service.js
@@ -18,7 +18,7 @@
 var NodeActionRunner = require('../runner');
 var fs = require('fs');
 
-function NodeActionService(config, logger) {
+function NodeActionService(config) {
     var Status = {
         ready: 'ready',
         starting: 'starting',
@@ -123,7 +123,7 @@
                 return Promise.reject(errorMessage(500, "An error has occurred: " + error));
             });
         } else {
-            logger.info('[runCode]', 'cannot schedule runCode due to status', status);
+            console.log('[runCode]', 'cannot schedule runCode due to status', status);
             return Promise.reject(errorMessage(500, "Internal system error: container not ready, status: " + status));
         }
     };
@@ -168,8 +168,8 @@
     }
 }
 
-NodeActionService.getService = function(config, logger) {
-    return new NodeActionService(config, logger);
+NodeActionService.getService = function(config) {
+    return new NodeActionService(config);
 };
 
 module.exports = NodeActionService;
diff --git a/settings.gradle b/settings.gradle
index 00e1bed..501f3c4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -15,6 +15,8 @@
 include 'core:nodejsActionBase'
 include 'core:nodejs6Action'
 
+include 'core:nodejs8Action'
+
 rootProject.name = 'runtime-nodejs'
 
 gradle.ext.scala = [
diff --git a/tests/src/test/scala/actionContainers/NodeJs8ActionContainerTests.scala b/tests/src/test/scala/actionContainers/NodeJs8ActionContainerTests.scala
new file mode 100644
index 0000000..8727a7f
--- /dev/null
+++ b/tests/src/test/scala/actionContainers/NodeJs8ActionContainerTests.scala
@@ -0,0 +1,54 @@
+/*
+ * 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 actionContainers
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+import spray.json.JsObject
+
+@RunWith(classOf[JUnitRunner])
+class NodeJs8ActionContainerTests extends NodeJsActionContainerTests {
+
+  override lazy val nodejsContainerImageName = "action-nodejs-v8"
+
+  it should "support async and await" in {
+    withNodeJsContainer { c =>
+      val code = """
+                   | const util = require('util');
+                   | const fs = require('fs');
+                   |
+                   | const stat = util.promisify(fs.stat);
+                   |
+                   | async function main() {
+                   |   const stats = await stat('.');
+                   |   return stats
+                   | }
+                 """.stripMargin;
+
+      val (initCode, _) = c.init(initPayload(code))
+      initCode should be(200)
+
+      val (runCode, runRes) = c.run(runPayload(JsObject()))
+      runCode should be(200) // action writer returning an error is OK
+
+      runRes shouldBe defined
+      runRes.get.fields.get("uid") shouldBe defined
+    }
+  }
+
+}
diff --git a/tests/src/test/scala/actionContainers/NodeJsActionContainerTests.scala b/tests/src/test/scala/actionContainers/NodeJsActionContainerTests.scala
index 928118b..be45a52 100644
--- a/tests/src/test/scala/actionContainers/NodeJsActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/NodeJsActionContainerTests.scala
@@ -260,13 +260,12 @@
     })
   }
 
-  it should "have ws and socket.io-client packages available" in {
+  it should "have openwhisk package available" in {
     // GIVEN that it should "error when requiring a non-existent package" (see test above for this)
     val (out, err) = withNodeJsContainer { c =>
       val code = """
                 | function main(args) {
-                |     require('ws');
-                |     require('socket.io-client');
+                |     require('openwhisk');
                 | }
             """.stripMargin
 
diff --git a/tools/travis/build.sh b/tools/travis/build.sh
index e23e934..fb914d8 100755
--- a/tools/travis/build.sh
+++ b/tools/travis/build.sh
@@ -15,6 +15,7 @@
 cd $ROOTDIR
 TERM=dumb ./gradlew \
 :core:nodejs6Action:distDocker \
+:core:nodejs8Action:distDocker \
 -PdockerImagePrefix=${IMAGE_PREFIX}