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

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


The following commit(s) were added to refs/heads/master by this push:
     new cd409cd  API GW V2 updates (#2436)
cd409cd is described below

commit cd409cd664a9ae66c2298a410ba4236cc16437e8
Author: Mark Deuser <[email protected]>
AuthorDate: Wed Jul 12 12:46:04 2017 -0400

    API GW V2 updates (#2436)
    
    - Do not enforce need for gwUrl parameter in api gw actions
    - Enable http redirect forwarding
    - Add automated test to validate rejection of api creation with invalid 
auth key
---
 core/routemgmt/common/apigw-utils.js               |  3 ++
 core/routemgmt/common/utils.js                     |  5 ++
 core/routemgmt/createApi/createApi.js              |  5 +-
 core/routemgmt/deleteApi/deleteApi.js              | 56 +++++++++----------
 core/routemgmt/getApi/getApi.js                    | 62 +++++++++++-----------
 .../actions/test/ApiGwRoutemgmtActionTests.scala   |  8 +--
 .../scala/whisk/core/cli/test/ApiGwTests.scala     | 35 +++++++++++-
 tools/cli/go-whisk-cli/commands/action.go          |  7 ++-
 .../go-whisk-cli/wski18n/resources/en_US.all.json  |  8 +--
 9 files changed, 115 insertions(+), 74 deletions(-)

diff --git a/core/routemgmt/common/apigw-utils.js 
b/core/routemgmt/common/apigw-utils.js
index c903f0d..5f60e1c 100644
--- a/core/routemgmt/common/apigw-utils.js
+++ b/core/routemgmt/common/apigw-utils.js
@@ -39,6 +39,7 @@ function addApiToGateway(gwInfo, spaceGuid, swaggerApi, 
apiId) {
   console.log('addApiToGateway: ');
   try {
   var options = {
+    followAllRedirects: true,
     url: gwInfo.gwUrl+'/'+encodeURIComponent(spaceGuid) + '/apis',
     json: swaggerApi,  // Use of json automatically sets header: 
'Content-Type': 'application/json'
   };
@@ -98,6 +99,7 @@ function addApiToGateway(gwInfo, spaceGuid, swaggerApi, 
apiId) {
  */
 function deleteApiFromGateway(gwInfo, spaceGuid, apiId) {
   var options = {
+    followAllRedirects: true,
     url: 
gwInfo.gwUrl+'/'+encodeURIComponent(spaceGuid)+'/apis/'+encodeURIComponent(apiId),
     agentOptions: {rejectUnauthorized: false},
     headers: {
@@ -150,6 +152,7 @@ function getApis(gwInfo, spaceGuid, bpOrApiName) {
     }
   }
   var options = {
+    followAllRedirects: true,
     url: gwInfo.gwUrl+'/'+encodeURIComponent(spaceGuid)+'/apis',
     headers: {
       'Accept': 'application/json'
diff --git a/core/routemgmt/common/utils.js b/core/routemgmt/common/utils.js
index 2f626b0..6e3c3a7 100644
--- a/core/routemgmt/common/utils.js
+++ b/core/routemgmt/common/utils.js
@@ -37,6 +37,7 @@ var utils2 = require('./apigw-utils.js');
 function createTenant(gwInfo, namespace, tenantInstance) {
   var instance = tenantInstance || 'openwhisk';  // Default to a fixed 
instance so all openwhisk tenants have a common instance
   var options = {
+    followAllRedirects: true,
     url: gwInfo.gwUrl+'/tenants',
     headers: {
       'Accept': 'application/json'
@@ -93,6 +94,7 @@ function getTenants(gwInfo, ns, tenantInstance) {
   var qs = qsNsOnly;
   if (tenantInstance) qs = qsNsAndInstance;
   var options = {
+    followAllRedirects: true,
     url: gwInfo.gwUrl+'/tenants',
     qs: qs,
     headers: {
@@ -174,6 +176,7 @@ function addApiToGateway(gwInfo, tenantId, swaggerApi, 
gwApiId) {
   gwApi.tenantId = tenantId;
 
   var options = {
+    followAllRedirects: true,
     url: gwInfo.gwUrl+'/apis',
     headers: {
       'Accept': 'application/json'
@@ -232,6 +235,7 @@ function addApiToGateway(gwInfo, tenantId, swaggerApi, 
gwApiId) {
  */
 function deleteApiFromGateway(gwInfo, gwApiId) {
   var options = {
+    followAllRedirects: true,
     url: gwInfo.gwUrl+'/apis/'+gwApiId,
     agentOptions: {rejectUnauthorized: false},
     headers: {
@@ -285,6 +289,7 @@ function getApis(gwInfo, tenantId, bpOrApiName) {
     }
   }
   var options = {
+    followAllRedirects: true,
     url: gwInfo.gwUrl+'/tenants/'+tenantId+'/apis',
     headers: {
       'Accept': 'application/json'
diff --git a/core/routemgmt/createApi/createApi.js 
b/core/routemgmt/createApi/createApi.js
index 4a72dcb..e71b50a 100644
--- a/core/routemgmt/createApi/createApi.js
+++ b/core/routemgmt/createApi/createApi.js
@@ -66,6 +66,7 @@ function main(message) {
   };
 
   // Replace the CLI provided namespace values with the controller provided 
namespace value
+  // If __ow_user is not set, the namespace values are left alone
   if (message.accesstoken) {
     utils2.updateNamespace(message.apidoc, message.__ow_user);
   } else {
@@ -234,12 +235,12 @@ function validateArgs(message) {
     return 'Internal error.  A message parameter was not supplied.';
   }
 
-  if (!message.gwUrl) {
+  if (!message.gwUrl && !message.gwUrlV2) {
     return 'gwUrl is required.';
   }
 
   if (!message.__ow_user) {
-    return '__ow_user is required.';
+    return 'A valid auth key is required.';
   }
 
   if(!message.apidoc) {
diff --git a/core/routemgmt/deleteApi/deleteApi.js 
b/core/routemgmt/deleteApi/deleteApi.js
index b29d95a..4fd4c5e 100644
--- a/core/routemgmt/deleteApi/deleteApi.js
+++ b/core/routemgmt/deleteApi/deleteApi.js
@@ -15,37 +15,39 @@
  * limitations under the License.
  */
 
- /**
-  * Delete an API Gateway to action mapping document from the database:
-  * https://docs.cloudant.com/document.html#delete
-  *
-  * Parameters (all as fields in the message JSON object)
-  *   gwUrlV2              Required when accesstoken is provided. The V2 API 
Gateway base path (i.e. http://gw.com)
-  *   gwUrl                Required. The API Gateway base path (i.e. 
http://gw.com)
-  *   gwUser               Optional. The API Gateway authentication
-  *   gwPwd                Optional. The API Gateway authentication
-  *   namespace            Required if __ow_user not specified.  Namespace of 
API author
-  *   __ow_user            Required. Namespace of API author
-  *   accesstoken          Optional. Dynamic API GW auth.  Overrides 
gwUser/gwPwd
-  *   spaceguid            Optional. Namespace unique id.
-  *   tenantInstance       Optional. Instance identifier used when creating 
the specific API GW Tenant
-  *   basepath             Required. Base path or API name of the API
-  *   relpath              Optional. Delete just this relative path from the 
API.  Required if operation is specified
-  *   operation            Optional. Delete just this relpath's operation from 
the API.
-  *
-  * NOTE: The package containing this action will be bound to the following 
values:
-  *         gwUrl, gwAuth
-  *       As such, the caller to this action should normally avoid explicitly 
setting
-  *       these values
-  */
+/**
+ *
+ * Delete an API Gateway to action mapping document from the database:
+ * https://docs.cloudant.com/document.html#delete
+ *
+ * Parameters (all as fields in the message JSON object)
+ *   gwUrlV2              Required when accesstoken is provided. The V2 API 
Gateway base path (i.e. http://gw.com)
+ *   gwUrl                Required. The API Gateway base path (i.e. 
http://gw.com)
+ *   gwUser               Optional. The API Gateway authentication
+ *   gwPwd                Optional. The API Gateway authentication
+ *   __ow_user            Optional. Set to the authenticated API authors's 
namespace when valid authentication is supplied.
+ *   namespace            Required if __ow_user not specified.  Namespace of 
API author
+ *   accesstoken          Optional. Dynamic API GW auth.  Overrides 
gwUser/gwPwd
+ *   spaceguid            Optional. Namespace unique id.
+ *   tenantInstance       Optional. Instance identifier used when creating the 
specific API GW Tenant
+ *   basepath             Required. Base path or API name of the API
+ *   relpath              Optional. Delete just this relative path from the 
API.  Required if operation is specified
+ *   operation            Optional. Delete just this relpath's operation from 
the API.
+ *
+ * NOTE: The package containing this action will be bound to the following 
values:
+ *         gwUrl, gwAuth
+ *       As such, the caller to this action should normally avoid explicitly 
setting
+ *       these values
+ **/
 var utils = require('./utils.js');
 var utils2 = require('./apigw-utils.js');
 var _ = require('lodash');
 
 function main(message) {
+  //console.log('message: '+JSON.stringify(message));  // ONLY FOR 
TEMPORARY/LOCAL DEBUG; DON'T ENABLE PERMANENTLY
   var badArgMsg = validateArgs(message);
   if (badArgMsg) {
-    return Promise.reject(utils2.makeErrorResponseObject(badArgMsg), 
(message.__ow_method != undefined));
+    return Promise.reject(utils2.makeErrorResponseObject(badArgMsg, 
(message.__ow_method != undefined)));
   }
 
   var gwInfo = {
@@ -211,12 +213,12 @@ function validateArgs(message) {
     return 'Internal error.  A message parameter was not supplied.';
   }
 
-  if (!message.gwUrl) {
+  if (!message.gwUrl && !message.gwUrlV2) {
     return 'gwUrl is required.';
   }
 
-  if (!message.__ow_user) {
-    return '__ow_user is required.';
+  if (!message.__ow_user && !message.namespace) {
+    return 'Invalid authentication.';
   }
 
   if (!message.basepath) {
diff --git a/core/routemgmt/getApi/getApi.js b/core/routemgmt/getApi/getApi.js
index 53ffc4e..04766ed 100644
--- a/core/routemgmt/getApi/getApi.js
+++ b/core/routemgmt/getApi/getApi.js
@@ -15,33 +15,33 @@
  * limitations under the License.
  */
 
- /**
-  * Retrieve API configuration from the API Gateway:
-  *
-  * Parameters (all as fields in the message JSON object)
-  *   gwUrlV2              Required when accesstoken is provided. The V2 API 
Gateway base path (i.e. http://gw.com)
-  *   gwUrl                Required. The API Gateway base path (i.e. 
http://gw.com)
-  *   gwUser               Optional. The API Gateway authentication
-  *   gwPwd                Optional. The API Gateway authentication
-  *   namespace            Optional. Input value is now overwritten by 
__ow_user.  Namespace of API author
-  *   __ow_user            Required. Namespace of API author
-  *   tenantInstance       Optional. Instance identifier used when creating 
the specific API GW Tenant
-  *   accesstoken          Optional. Dynamic API GW auth.  Overrides 
gwUser/gwPwd
-  *   spaceguid            Optional. Namespace unique id.
-  *   basepath             Optional. Base path or API name of the API.
-  *                                  If not provided, all APIs for the 
namespace are returned
-  *   relpath              Optional. Must be defined with 'operation'.  
Filters API result to path/operation
-  *   operation            Optional. Must be defined with 'relpath'.  Filters 
API result to path/operation
-  *   outputFormat         Optional. Defaults to 'swagger'.  Possible values:
-  *                                  'apigw' = return API as obtained from the 
API Gateway
-  *                                  'swagger' = return API as swagger 
compliant JSON
-  *
-  * NOTE: The package containing this action will be bound to the following 
values:
-  *         gwUrl, gwAuth
-  *       As such, the caller to this action should normally avoid explicitly 
setting
-  *       these values
-  */
-var request = require('request');
+/**
+ *
+ * Retrieve API configuration from the API Gateway:
+ *
+ * Parameters (all as fields in the message JSON object)
+ *   gwUrlV2              Required when accesstoken is provided. The V2 API 
Gateway base path (i.e. http://gw.com)
+ *   gwUrl                Required. The API Gateway base path (i.e. 
http://gw.com)
+ *   gwUser               Optional. The API Gateway authentication
+ *   gwPwd                Optional. The API Gateway authentication
+ *   __ow_user            Optional. Set to the authenticated API authors's 
namespace when valid authentication is supplied.
+ *   namespace            Required if __ow_user not specified.  Namespace of 
API author
+ *   tenantInstance       Optional. Instance identifier used when creating the 
specific API GW Tenant
+ *   accesstoken          Optional. Dynamic API GW auth.  Overrides 
gwUser/gwPwd
+ *   spaceguid            Optional. Namespace unique id.
+ *   basepath             Optional. Base path or API name of the API.
+ *                                  If not provided, all APIs for the 
namespace are returned
+ *   relpath              Optional. Must be defined with 'operation'.  Filters 
API result to path/operation
+ *   operation            Optional. Must be defined with 'relpath'.  Filters 
API result to path/operation
+ *   outputFormat         Optional. Defaults to 'swagger'.  Possible values:
+ *                                  'apigw' = return API as obtained from the 
API Gateway
+ *                                  'swagger' = return API as swagger 
compliant JSON
+ *
+ * NOTE: The package containing this action will be bound to the following 
values:
+ *         gwUrl, gwAuth
+ *       As such, the caller to this action should normally avoid explicitly 
setting
+ *       these values
+ **/
 var utils = require('./utils.js');
 var utils2 = require('./apigw-utils.js');
 
@@ -154,12 +154,12 @@ function validateArgs(message) {
     return 'Internal error. A message parameter was not supplied.';
   }
 
-  if (!message.__ow_user) {
-    return '__ow_user is required.';
+  if (!message.gwUrl && !message.gwUrlV2) {
+    return 'gwUrl is required.';
   }
 
-  if (!message.gwUrl) {
-    return 'gwUrl is required.';
+  if (!message.__ow_user && !message.namespace) {
+    return 'Invalid authentication.';
   }
 
   if (message.outputFormat && !(message.outputFormat.toLowerCase() === 'apigw' 
|| message.outputFormat.toLowerCase() === 'swagger')) {
diff --git 
a/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwRoutemgmtActionTests.scala
 
b/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwRoutemgmtActionTests.scala
index 5e8b5dd..5a0f97c 100644
--- 
a/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwRoutemgmtActionTests.scala
+++ 
b/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwRoutemgmtActionTests.scala
@@ -427,10 +427,10 @@ class ApiGwRoutemgmtActionTests
     it should "reject routemgmt actions that are invoked with not enough 
parameters" in {
         val invalidArgs = Seq(
             //getApi
-            ("/whisk.system/routemgmt/getApi", ANY_ERROR_EXIT, "__ow_user is 
required", Seq()),
+            ("/whisk.system/routemgmt/getApi", ANY_ERROR_EXIT, "Invalid 
authentication.", Seq()),
 
             //deleteApi
-            ("/whisk.system/routemgmt/deleteApi", ANY_ERROR_EXIT, "__ow_user 
is required", Seq("-p", "basepath", "/ApiGwRoutemgmtActionTests_bp")),
+            ("/whisk.system/routemgmt/deleteApi", ANY_ERROR_EXIT, "Invalid 
authentication.", Seq("-p", "basepath", "/ApiGwRoutemgmtActionTests_bp")),
             ("/whisk.system/routemgmt/deleteApi", ANY_ERROR_EXIT, "basepath is 
required", Seq("-p", "__ow_user", "_")),
             ("/whisk.system/routemgmt/deleteApi", ANY_ERROR_EXIT, "When 
specifying an operation, the path is required",
                 Seq("-p", "__ow_user", "_", "-p", "basepath", 
"/ApiGwRoutemgmtActionTests_bp", "-p", "operation", "get")),
@@ -560,10 +560,10 @@ class ApiGwRoutemgmtActionTests
     it should "reject apimgmt actions that are invoked with not enough 
parameters" in {
         val invalidArgs = Seq(
             //getApi
-            ("/whisk.system/apimgmt/getApi", ANY_ERROR_EXIT, "__ow_user is 
required", Seq()),
+            ("/whisk.system/apimgmt/getApi", ANY_ERROR_EXIT, "Invalid 
authentication.", Seq()),
 
             //deleteApi
-            ("/whisk.system/apimgmt/deleteApi", ANY_ERROR_EXIT, "__ow_user is 
required", Seq("-p", "basepath", "/ApiGwRoutemgmtActionTests_bp")),
+            ("/whisk.system/apimgmt/deleteApi", ANY_ERROR_EXIT, "Invalid 
authentication.", Seq("-p", "basepath", "/ApiGwRoutemgmtActionTests_bp")),
             ("/whisk.system/apimgmt/deleteApi", ANY_ERROR_EXIT, "basepath is 
required", Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN")),
             ("/whisk.system/apimgmt/deleteApi", ANY_ERROR_EXIT, "When 
specifying an operation, the path is required",
               Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN", "-p", 
"basepath", "/ApiGwRoutemgmtActionTests_bp", "-p", "operation", "get")),
diff --git a/tests/src/test/scala/whisk/core/cli/test/ApiGwTests.scala 
b/tests/src/test/scala/whisk/core/cli/test/ApiGwTests.scala
index 9c8e239..14970db 100644
--- a/tests/src/test/scala/whisk/core/cli/test/ApiGwTests.scala
+++ b/tests/src/test/scala/whisk/core/cli/test/ApiGwTests.scala
@@ -43,7 +43,7 @@ class ApiGwTests
     with WskTestHelpers
     with BeforeAndAfterAll {
 
-    implicit val wskprops = WskProps()
+    implicit var wskprops = WskProps()
     val wsk = new Wsk
     val (cliuser, clinamespace) = WskAdmin.getUser(wskprops.authKey)
 
@@ -1194,7 +1194,7 @@ class ApiGwTests
 
     it should "reject creation of an API from invalid YAML formatted API 
configuration file" in {
         val testName = "CLI_APIGWTEST22"
-        val testbasepath = "/bp"
+        val testbasepath = "/"+testName+"_bp"
         val swaggerPath = TestUtils.getTestApiGwFilename(s"local.api.bad.yaml")
         try {
             var rr = apiCreate(swagger = Some(swaggerPath), expectedExitCode = 
ANY_ERROR_EXIT)
@@ -1245,4 +1245,35 @@ class ApiGwTests
             val deleteresult = apiDelete(basepathOrApiName = testbasepath, 
expectedExitCode = DONTCARE_EXIT)
         }
     }
+
+    it should "reject creation of an API with invalid auth key" in {
+        val testName = "CLI_APIGWTEST24"
+        val testbasepath = "/" + testName + "_bp"
+        val testrelpath = "/path"
+        val testurlop = "get"
+        val testapiname = testName + " API Name"
+        val actionName = testName + "_action"
+        val wskpropsBackup = wskprops
+        try {
+            // Create the action for the API.
+            val file = TestUtils.getTestActionFilename(s"echo.js")
+            wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+
+            // Set an invalid auth key
+            wskprops = WskProps(authKey = "bad-auth-key")
+
+            var rr = apiCreate(
+                basepath = Some(testbasepath),
+                relpath = Some(testrelpath),
+                operation = Some(testurlop),
+                action = Some(actionName),
+                apiname = Some(testapiname),
+                expectedExitCode = ANY_ERROR_EXIT)
+            rr.stderr should include("The supplied authentication is invalid")
+        } finally {
+            wskprops = wskpropsBackup
+            val finallydeleteActionResult = wsk.action.delete(name = 
actionName, expectedExitCode = DONTCARE_EXIT)
+            var deleteresult = apiDelete(basepathOrApiName = testbasepath, 
expectedExitCode = DONTCARE_EXIT)
+        }
+    }
 }
diff --git a/tools/cli/go-whisk-cli/commands/action.go 
b/tools/cli/go-whisk-cli/commands/action.go
index dccd42d..20a7926 100644
--- a/tools/cli/go-whisk-cli/commands/action.go
+++ b/tools/cli/go-whisk-cli/commands/action.go
@@ -857,9 +857,12 @@ func isWebAction(client *whisk.Client, qname 
QualifiedName) error {
     if err != nil {
         whisk.Debug(whisk.DbgError, "client.Actions.Get(%s) error: %s\n", 
fullActionName, err)
         whisk.Debug(whisk.DbgError, "Unable to obtain action '%s' for web 
action validation\n", fullActionName)
-        err = errors.New(wski18n.T("API action '{{.name}}' does not exist", 
map[string]interface{}{"name": fullActionName}))
+        errMsg := wski18n.T("Unable to get action '{{.name}}': {{.err}}",
+            map[string]interface{}{"name": fullActionName, "err": err})
+        err = whisk.MakeWskErrorFromWskError(errors.New(errMsg), err, 
whisk.EXITCODE_ERR_NETWORK, whisk.DISPLAY_MSG,
+            whisk.NO_DISPLAY_USAGE)
     } else {
-        err = errors.New(wski18n.T("API action '{{.name}}' is not a web 
action. Issue 'wsk action update {{.name}} --web true' to convert the action to 
a web action.",
+        err = errors.New(wski18n.T("Action '{{.name}}' is not a web action. 
Issue 'wsk action update {{.name}} --web true' to convert the action to a web 
action.",
             map[string]interface{}{"name": fullActionName}))
         weVal := getValue(action.Annotations, "web-export")
         if (weVal == nil) {
diff --git a/tools/cli/go-whisk-cli/wski18n/resources/en_US.all.json 
b/tools/cli/go-whisk-cli/wski18n/resources/en_US.all.json
index 765f961..ec409ad 100644
--- a/tools/cli/go-whisk-cli/wski18n/resources/en_US.all.json
+++ b/tools/cli/go-whisk-cli/wski18n/resources/en_US.all.json
@@ -1384,12 +1384,8 @@
     "translation": "Invalid argument '{{.arg}}' for --web flag. Valid input 
consist of 'yes', 'true', 'raw', 'false', or 'no'."
   },
   {
-    "id": "API action '{{.name}}' does not exist",
-    "translation": "API action '{{.name}}' does not exist"
-  },
-  {
-    "id": "API action '{{.name}}' is not a web action. Issue 'wsk action 
update {{.name}} --web true' to convert the action to a web action.",
-    "translation": "API action '{{.name}}' is not a web action. Issue 'wsk 
action update {{.name}} --web true' to convert the action to a web action."
+    "id": "Action '{{.name}}' is not a web action. Issue 'wsk action update 
{{.name}} --web true' to convert the action to a web action.",
+    "translation": "Action '{{.name}}' is not a web action. Issue 'wsk action 
update {{.name}} --web true' to convert the action to a web action."
   },
   {
     "id": "Invalid configuration. The x-openwhisk stanza is missing.",

-- 
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].

Reply via email to