You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@openwhisk.apache.org by GitBox <gi...@apache.org> on 2018/11/20 15:40:56 UTC

[GitHub] csantanapr closed pull request #184: Add support for IAM based Cloudant DB instances

csantanapr closed pull request #184: Add support for IAM based Cloudant DB instances
URL: https://github.com/apache/incubator-openwhisk-package-cloudant/pull/184
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/.gitignore b/.gitignore
index 4891796..009fe45 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ actions/event-actions/*.zip
 actions/event-actions/package.json
 .idea
 *.iml
+package-lock.json
 
 # Eclipse
 bin/
diff --git a/Dockerfile b/Dockerfile
index 2df3aac..e5e8a21 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,17 +1,4 @@
-FROM ubuntu:14.04
-
-ENV DEBIAN_FRONTEND noninteractive
-
-# Initial update and some basics.
-# This odd double update seems necessary to get curl to download without 404 errors.
-RUN apt-get update --fix-missing && \
-  apt-get install -y wget && \
-  apt-get update && \
-  apt-get install -y curl && \
-  apt-get update && \
-  apt-get remove -y nodejs && \
-  curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
-  apt-get install -y nodejs
+FROM node:8.12.0
 
 # only package.json
 ADD package.json /
@@ -23,4 +10,4 @@ ADD provider/. /cloudantTrigger/
 EXPOSE 8080
 
 # Run the app
-CMD ["/bin/bash", "-c", "node /cloudantTrigger/app.js >> /logs/cloudantTrigger_logs.log 2>&1"]
+CMD ["/bin/bash", "-c", "node /cloudantTrigger/app.js"]
diff --git a/actions/event-actions/changesWebAction.js b/actions/event-actions/changesWebAction.js
index af2b0e8..1e171ea 100644
--- a/actions/event-actions/changesWebAction.js
+++ b/actions/event-actions/changesWebAction.js
@@ -29,11 +29,10 @@ function main(params) {
         if (!params.host) {
             return common.sendError(400, 'cloudant trigger feed: missing host parameter');
         }
-        if (!params.username) {
-            return common.sendError(400, 'cloudant trigger feed: missing username parameter');
-        }
-        if (!params.password) {
-            return common.sendError(400, 'cloudant trigger feed: missing password parameter');
+        if (!params.iamApiKey) {
+            if (!params.username || !params.password) {
+                return common.sendError(400, 'cloudant trigger feed: Must specify parameter/s of iamApiKey or username/password');
+            }
         }
 
         var query_params;
@@ -56,30 +55,34 @@ function main(params) {
             return common.sendError(400, 'The query_params parameter is only allowed if the filter parameter is defined');
         }
 
-        var newTrigger = {
-            id: triggerID,
-            host: params.host,
-            port: params.port,
-            protocol: params.protocol || 'https',
-            dbname: params.dbname,
-            user: params.username,
-            pass: params.password,
-            apikey: triggerData.apikey,
-            since: params.since,
-            maxTriggers: params.maxTriggers || -1,
-            filter: params.filter,
-            query_params: query_params,
-            status: {
-                'active': true,
-                'dateChanged': Date.now()
-            },
-            additionalData: triggerData.additionalData
-        };
-
         return new Promise(function (resolve, reject) {
+            var newTrigger;
+
             common.verifyTriggerAuth(triggerData, false)
             .then(() => {
                 db = new Database(params.DB_URL, params.DB_NAME);
+
+                newTrigger = {
+                    id: triggerID,
+                    host: params.host,
+                    port: params.port,
+                    protocol: params.protocol || 'https',
+                    dbname: params.dbname,
+                    user: params.username,
+                    pass: params.password,
+                    apikey: triggerData.apikey,
+                    since: params.since,
+                    maxTriggers: params.maxTriggers || -1,
+                    filter: params.filter,
+                    query_params: query_params,
+                    status: {
+                        'active': true,
+                        'dateChanged': Date.now()
+                    },
+                    additionalData: triggerData.additionalData,
+                    iamApiKey: params.iamApiKey,
+                    iamUrl: params.iamUrl || 'https://iam.bluemix.net/identity/token'
+                };
                 return verifyUserDB(newTrigger);
             })
             .then(() => {
@@ -124,6 +127,8 @@ function main(params) {
                         since: doc.since,
                         filter: doc.filter,
                         query_params: doc.query_params,
+                        iamApiKey: doc.iamApiKey,
+                        iamUrl: doc.iamUrl
                     },
                     status: {
                         active: doc.status.active,
@@ -242,17 +247,28 @@ function main(params) {
 }
 
 function verifyUserDB(triggerObj) {
-    var dbURL = `${triggerObj.protocol}://${triggerObj.user}:${triggerObj.pass}@${triggerObj.host}`;
 
-    // add port if specified
-    if (triggerObj.port) {
-        dbURL += ':' + triggerObj.port;
+    var Cloudant = require('@cloudant/cloudant');
+    var cloudant;
+
+    if (triggerObj.iamApiKey) {
+        var dbURL = `${triggerObj.protocol}://${triggerObj.host}`;
+        if (triggerObj.port) {
+            dbURL += ':' + triggerObj.port;
+        }
+        cloudant = new Cloudant({ url: dbURL, plugins: { iamauth: { iamApiKey: triggerObj.iamApiKey, iamTokenUrl: triggerObj.iamUrl } } });
+    }
+    else {
+        var url = `${triggerObj.protocol}://${triggerObj.user}:${triggerObj.pass}@${triggerObj.host}`;
+        if (triggerObj.port) {
+            url += ':' + triggerObj.port;
+        }
+        cloudant = Cloudant(url);
     }
 
     return new Promise(function(resolve, reject) {
         try {
-            var nanoConnection = require('nano')(dbURL);
-            var userDB = nanoConnection.use(triggerObj.dbname);
+            var userDB = cloudant.use(triggerObj.dbname);
             userDB.info(function(err, body) {
                 if (!err) {
                     resolve();
diff --git a/actions/event-actions/changesWeb_package.json b/actions/event-actions/changesWeb_package.json
index f2b3fc6..5c46d8d 100644
--- a/actions/event-actions/changesWeb_package.json
+++ b/actions/event-actions/changesWeb_package.json
@@ -1,5 +1,8 @@
 {
   "name": "changesWebAction",
   "version": "1.0.0",
-  "main": "changesWebAction.js"
+  "main": "changesWebAction.js",
+  "dependencies" : {
+    "@cloudant/cloudant": "3.0.0"
+  }
 }
diff --git a/actions/event-actions/lib/Database.js b/actions/event-actions/lib/Database.js
index 962b2df..9bc180d 100644
--- a/actions/event-actions/lib/Database.js
+++ b/actions/event-actions/lib/Database.js
@@ -2,8 +2,8 @@ const common = require('./common');
 
 // constructor for DB object - a thin, promise-loving wrapper around nano
 module.exports = function(dbURL, dbName) {
-    var nano = require('nano')(dbURL);
-    this.db = nano.db.use(dbName);
+    var cloudant = require('@cloudant/cloudant')(dbURL);
+    this.db = cloudant.db.use(dbName);
     var utilsDB = this;
 
     this.getWorkerID = function(availabeWorkers) {
diff --git a/installCatalog.sh b/installCatalog.sh
index 7ce6d5a..7787ec7 100755
--- a/installCatalog.sh
+++ b/installCatalog.sh
@@ -51,12 +51,8 @@ echo Installing Cloudant package.
 
 $WSK_CLI -i --apihost "$EDGEHOST" package update --auth "$AUTH" --shared yes cloudant \
     -a description "Cloudant database service" \
-    -a parameters '[ {"name":"bluemixServiceName", "required":false, "bindTime":true}, {"name":"username", "required":true, "bindTime":true, "description": "Your Cloudant username"}, {"name":"password", "required":true, "type":"password", "bindTime":true, "description": "Your Cloudant password"}, {"name":"host", "required":true, "bindTime":true, "description": "This is usually your username.cloudant.com"}, {"name":"dbname", "required":false, "description": "The name of your Cloudant database"}, {"name":"overwrite", "required":false, "type": "boolean"} ]' \
+    -a parameters '[  {"name":"bluemixServiceName", "required":false, "bindTime":true}, {"name":"username", "required":false, "bindTime":true, "description": "Your Cloudant username"}, {"name":"password", "required":false, "type":"password", "bindTime":true, "description": "Your Cloudant password"}, {"name":"host", "required":true, "bindTime":true, "description": "This is usually your username.cloudant.com"}, {"name":"iamApiKey", "required":false}, {"name":"iamUrl", "required":false}, {"name":"dbname", "required":false, "description": "The name of your Cloudant database"}, {"name":"overwrite", "required":false, "type": "boolean"} ]' \
     -p bluemixServiceName 'cloudantNoSQLDB' \
-    -p host '' \
-    -p username '' \
-    -p password '' \
-    -p dbname '' \
     -p apihost "$APIHOST"
 
 # make changesFeed.zip
@@ -73,7 +69,7 @@ $WSK_CLI -i --apihost "$EDGEHOST" action update --kind "$ACTION_RUNTIME_VERSION"
     -t 90000 \
     -a feed true \
     -a description 'Database change feed' \
-    -a parameters '[ {"name":"dbname", "required":true, "updatable":false}, {"name": "filter", "required":false, "updatable":true, "type": "string", "description": "The name of your Cloudant database filter"}, {"name": "query_params", "required":false, "updatable":true, "description": "JSON Object containing query parameters that are passed to the filter"} ]' \
+    -a parameters '[ {"name":"dbname", "required":true, "updatable":false}, {"name":"iamApiKey", "required":false, "updatable":false}, {"name":"iamUrl", "required":false, "updatable":false}, {"name": "filter", "required":false, "updatable":true, "type": "string", "description": "The name of your Cloudant database filter"}, {"name": "query_params", "required":false, "updatable":true, "description": "JSON Object containing query parameters that are passed to the filter"} ]' \
     -a sampleInput '{ "dbname": "mydb", "filter": "mailbox/by_status", "query_params": {"status": "new"} }'
 
 COMMAND=" -i --apihost $EDGEHOST package update --auth $AUTH --shared no cloudantWeb \
@@ -89,12 +85,13 @@ $WSK_CLI $COMMAND
 
 # make changesWebAction.zip
 cp -f changesWeb_package.json package.json
+npm install
 
 if [ -e changesWebAction.zip ]; then
     rm -rf changesWebAction.zip
 fi
 
-zip -r changesWebAction.zip lib package.json changesWebAction.js
+zip -r changesWebAction.zip lib package.json changesWebAction.js node_modules
 
 $WSK_CLI -i --apihost "$EDGEHOST" action update --kind "$ACTION_RUNTIME_VERSION" --auth "$AUTH" cloudantWeb/changesWebAction "$PACKAGE_HOME/actions/event-actions/changesWebAction.zip" \
     -a description 'Create/Delete a trigger in cloudant provider Database' \
diff --git a/package.json b/package.json
index 2b8ecb0..6214f12 100644
--- a/package.json
+++ b/package.json
@@ -12,12 +12,12 @@
     "moment": "^2.11.1",
     "lodash": "^3.10.1",
     "request": "^2.83.0",
-    "cloudant-nano": "6.7.0",
+    "@cloudant/cloudant": "3.0.0",
     "json-stringify-safe": "^5.0.1",
     "http-status-codes": "^1.0.5",
     "request-promise": "^1.0.2",
-    "redis":"^2.7.1",
+    "redis": "^2.7.1",
     "bluebird": "^3.5.0",
     "systeminformation": "^3.19.0"
   }
-}
\ No newline at end of file
+}
diff --git a/provider/app.js b/provider/app.js
index fc9149d..2488931 100644
--- a/provider/app.js
+++ b/provider/app.js
@@ -49,11 +49,11 @@ function createDatabase() {
     var method = 'createDatabase';
     logger.info(method, 'creating the trigger database');
 
-    var nano = require('cloudant-nano')(dbProtocol + '://' + dbUsername + ':' + dbPassword + '@' + dbHost);
+    var cloudant = require('@cloudant/cloudant')(dbProtocol + '://' + dbUsername + ':' + dbPassword + '@' + dbHost);
 
-    if (nano !== null) {
+    if (cloudant !== null) {
         return new Promise(function (resolve, reject) {
-            nano.db.create(databaseName, function (err, body) {
+            cloudant.db.create(databaseName, function (err, body) {
                 if (!err) {
                     logger.info(method, 'created trigger database:', databaseName);
                 }
@@ -74,7 +74,7 @@ function createDatabase() {
                     }
                 };
 
-                createDesignDoc(nano.db.use(databaseName), viewDDName, viewDD)
+                createDesignDoc(cloudant.db.use(databaseName), viewDDName, viewDD)
                 .then(db => {
                     var filterDD = {
                         filters: {
@@ -114,7 +114,7 @@ function createDatabase() {
         });
     }
     else {
-        Promise.reject('nano provider did not get created.  check db URL: ' + dbHost);
+        Promise.reject('cloudant provider did not get created.  check db URL: ' + dbHost);
     }
 }
 
@@ -181,7 +181,7 @@ function createRedisClient() {
 // Initialize the Provider Server
 function init(server) {
     var method = 'init';
-    var nanoDb;
+    var cloudantDb;
     var providerUtils;
 
     if (server !== null) {
@@ -194,11 +194,11 @@ function init(server) {
 
     createDatabase()
     .then(db => {
-        nanoDb = db;
+        cloudantDb = db;
         return createRedisClient();
     })
     .then(client => {
-        providerUtils = new ProviderUtils(logger, nanoDb, client);
+        providerUtils = new ProviderUtils(logger, cloudantDb, client);
         return providerUtils.initRedis();
     })
     .then(() => {
diff --git a/provider/lib/utils.js b/provider/lib/utils.js
index 4f085308..aa12c6d 100644
--- a/provider/lib/utils.js
+++ b/provider/lib/utils.js
@@ -30,17 +30,26 @@ module.exports = function(logger, triggerDB, redisClient) {
     this.createTrigger = function(triggerData) {
         var method = 'createTrigger';
 
-        // both couch and cloudant should have their URLs in the username:password@host format
-        var dbURL = `${triggerData.protocol}://${triggerData.user}:${triggerData.pass}@${triggerData.host}`;
+        var Cloudant = require('@cloudant/cloudant');
+        var cloudantConnection;
 
-        // add port if specified
-        if (triggerData.port) {
-            dbURL += ':' + triggerData.port;
+        if (triggerData.iamApiKey) {
+            var dbURL = `${triggerData.protocol}://${triggerData.host}`;
+            if (triggerData.port) {
+                dbURL += ':' + triggerData.port;
+            }
+            cloudantConnection = new Cloudant({ url: dbURL, plugins: { iamauth: { iamApiKey: triggerData.iamApiKey, iamTokenUrl: triggerData.iamUrl } } });
+        }
+        else {
+            var url = `${triggerData.protocol}://${triggerData.user}:${triggerData.pass}@${triggerData.host}`;
+            if (triggerData.port) {
+                url += ':' + triggerData.port;
+            }
+            cloudantConnection = Cloudant(url);
         }
 
         try {
-            var nanoConnection = require('cloudant-nano')(dbURL);
-            var triggeredDB = nanoConnection.use(triggerData.dbname);
+            var triggeredDB = cloudantConnection.use(triggerData.dbname);
 
             // Listen for changes on this database.
             var feed = triggeredDB.follow({since: triggerData.since, include_docs: false});
@@ -107,7 +116,9 @@ module.exports = function(logger, triggerDB, redisClient) {
             triggersLeft: maxTriggers,
             filter: newTrigger.filter,
             query_params: newTrigger.query_params,
-            additionalData: newTrigger.additionalData
+            additionalData: newTrigger.additionalData,
+            iamApiKey: newTrigger.iamApiKey,
+            iamUrl: newTrigger.iamUrl
         };
 
         return trigger;
diff --git a/tests/src/test/scala/system/packages/CloudantFeedTests.scala b/tests/src/test/scala/system/packages/CloudantFeedTests.scala
index 00c370a..7e70d8c 100644
--- a/tests/src/test/scala/system/packages/CloudantFeedTests.scala
+++ b/tests/src/test/scala/system/packages/CloudantFeedTests.scala
@@ -132,7 +132,7 @@ class CloudantFeedTests
                         "host" -> myCloudantCreds.host().toJson),
                         expectedExitCode = 246)
             }
-            feedCreationResult.stderr should include("cloudant trigger feed: missing password parameter")
+            feedCreationResult.stderr should include("cloudant trigger feed: Must specify parameter/s of iamApiKey or username/password")
 
     }
 
@@ -163,7 +163,7 @@ class CloudantFeedTests
                         "host" -> myCloudantCreds.host().toJson),
                         expectedExitCode = 246)
             }
-            feedCreationResult.stderr should include("cloudant trigger feed: missing username parameter")
+            feedCreationResult.stderr should include("cloudant trigger feed: Must specify parameter/s of iamApiKey or username/password")
 
     }
 
diff --git a/tests/src/test/scala/system/packages/CloudantFeedWebTests.scala b/tests/src/test/scala/system/packages/CloudantFeedWebTests.scala
index da9d518..499e61a 100644
--- a/tests/src/test/scala/system/packages/CloudantFeedWebTests.scala
+++ b/tests/src/test/scala/system/packages/CloudantFeedWebTests.scala
@@ -70,13 +70,13 @@ class CloudantFeedWebTests
     it should "reject post of a trigger due to missing username argument" in {
         val params = JsObject(requiredParams.fields - "username")
 
-        makePostCallWithExpectedResult(params, JsObject("error" -> JsString("cloudant trigger feed: missing username parameter")), 400)
+        makePostCallWithExpectedResult(params, JsObject("error" -> JsString("cloudant trigger feed: Must specify parameter/s of iamApiKey or username/password")), 400)
     }
 
     it should "reject post of a trigger due to missing password argument" in {
         val params = JsObject(requiredParams.fields - "password")
 
-        makePostCallWithExpectedResult(params, JsObject("error" -> JsString("cloudant trigger feed: missing password parameter")), 400)
+        makePostCallWithExpectedResult(params, JsObject("error" -> JsString("cloudant trigger feed: Must specify parameter/s of iamApiKey or username/password")), 400)
     }
 
     it should "reject post of a trigger due to missing dbname argument" in {


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services