Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 5EB01200CBE for ; Fri, 7 Jul 2017 20:40:26 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 5D0F9169BEE; Fri, 7 Jul 2017 18:40:26 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 560FF169BEA for ; Fri, 7 Jul 2017 20:40:25 +0200 (CEST) Received: (qmail 28806 invoked by uid 500); 7 Jul 2017 18:40:22 -0000 Mailing-List: contact commits-help@openwhisk.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@openwhisk.apache.org Delivered-To: mailing list commits@openwhisk.apache.org Received: (qmail 28797 invoked by uid 99); 7 Jul 2017 18:40:22 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 07 Jul 2017 18:40:22 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id 43EC587586; Fri, 7 Jul 2017 18:40:22 +0000 (UTC) Date: Fri, 07 Jul 2017 18:40:22 +0000 To: "commits@openwhisk.apache.org" Subject: [incubator-openwhisk] branch master updated: wsk CLI should tolerate APIs that do not yet have a mapped action (#2458) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Message-ID: <149945282213.3559.7792601128797230686@gitbox.apache.org> From: houshengbo@apache.org Reply-To: "commits@openwhisk.apache.org" X-Git-Host: gitbox.apache.org X-Git-Repo: incubator-openwhisk X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 7a0444cbb98164b28d0187684b05238360ebc283 X-Git-Newrev: 9c4ff87da2658f25bcb7ea6fc920fc54d806fb0d X-Git-Rev: 9c4ff87da2658f25bcb7ea6fc920fc54d806fb0d X-Git-NotificationType: ref_changed_plus_diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated archived-at: Fri, 07 Jul 2017 18:40:26 -0000 This is an automated email from the ASF dual-hosted git repository. houshengbo 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 9c4ff87 wsk CLI should tolerate APIs that do not yet have a mapped action (#2458) 9c4ff87 is described below commit 9c4ff87da2658f25bcb7ea6fc920fc54d806fb0d Author: Mark Deuser AuthorDate: Fri Jul 7 14:40:19 2017 -0400 wsk CLI should tolerate APIs that do not yet have a mapped action (#2458) * wsk CLI should tolerate APIs that do not yet have a mapped action - bump API GW version so that action-less APIs can be created via cli/swagger * Add `wsk api list --full` test for action-less apis --- ansible/group_vars/all | 2 +- ansible/roles/apigateway/tasks/deploy.yml | 2 +- .../apigw/endpoints.without.action.swagger.json | 76 ++++++++++++++++++++++ .../scala/whisk/core/cli/test/ApiGwTests.scala | 33 ++++++++++ tools/cli/go-whisk-cli/commands/api.go | 45 +++++++++---- .../go-whisk-cli/wski18n/resources/en_US.all.json | 4 ++ tools/cli/go-whisk/whisk/api.go | 18 ++--- 7 files changed, 153 insertions(+), 27 deletions(-) diff --git a/ansible/group_vars/all b/ansible/group_vars/all index 5fa8eed..91e3fa7 100644 --- a/ansible/group_vars/all +++ b/ansible/group_vars/all @@ -192,7 +192,7 @@ apigateway: api: 9000 api_secure: 443 mgmt: 9001 - version: 0.7.0 + version: 0.8.2 redis: version: 3.2 diff --git a/ansible/roles/apigateway/tasks/deploy.yml b/ansible/roles/apigateway/tasks/deploy.yml index a2dd2be..9d18488 100644 --- a/ansible/roles/apigateway/tasks/deploy.yml +++ b/ansible/roles/apigateway/tasks/deploy.yml @@ -1,7 +1,7 @@ --- # This role will install apigateway -- name: "pull the openwhisk/apigateway image" +- name: "pull the openwhisk/apigateway:{{ apigateway.version }} image" shell: "docker pull openwhisk/apigateway:{{ apigateway.version }}" when: apigateway_local_build is undefined retries: 3 diff --git a/tests/dat/apigw/endpoints.without.action.swagger.json b/tests/dat/apigw/endpoints.without.action.swagger.json new file mode 100644 index 0000000..2305643 --- /dev/null +++ b/tests/dat/apigw/endpoints.without.action.swagger.json @@ -0,0 +1,76 @@ +{ + "swagger": "2.0", + "basePath": "/NoActions", + "info": { + "title": "A descriptive name", + "version": "1.0" + }, + "paths": { + "/": { + "delete": { + "operationId": "", + "responses": { + "200": { + "description": "A successful invocation response" + } + } + }, + "get": { + "operationId": "", + "responses": { + "200": { + "description": "A successful invocation response" + } + } + }, + "head": { + "operationId": "", + "responses": { + "200": { + "description": "A successful invocation response" + } + } + }, + "options": { + "operationId": "", + "responses": { + "200": { + "description": "A successful invocation response" + } + } + }, + "patch": { + "operationId": "", + "responses": { + "200": { + "description": "A successful invocation response" + } + } + }, + "post": { + "operationId": "", + "responses": { + "200": { + "description": "A successful invocation response" + } + } + }, + "put": { + "operationId": "", + "responses": { + "200": { + "description": "A successful invocation response" + } + } + } + } + }, + "x-ibm-configuration": { + "assembly": { + "execute": [] + }, + "cors": { + "enabled": true + } + } +} 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 5894bcd..9c8e239 100644 --- a/tests/src/test/scala/whisk/core/cli/test/ApiGwTests.scala +++ b/tests/src/test/scala/whisk/core/cli/test/ApiGwTests.scala @@ -1212,4 +1212,37 @@ class ApiGwTests var rr = apiDelete(basepathOrApiName = nonexistentApi, expectedExitCode = ANY_ERROR_EXIT) rr.stderr should include (s"API '${nonexistentApi}' does not exist") } + + it should "successfully list an API whose endpoints are not mapped to actions" in { + val testName = "CLI_APIGWTEST23" + var testapiname = "A descriptive name" + val testbasepath = "/NoActions" + val testrelpath = "/" + val testops: Seq[String] = Seq("put", "delete", "get", "head", "options", "patch", "post") + val swaggerPath = TestUtils.getTestApiGwFilename(s"endpoints.without.action.swagger.json") + + try { + var rr = apiCreate(swagger = Some(swaggerPath)) + println("api create stdout: " + rr.stdout) + println("api create stderror: " + rr.stderr) + rr.stdout should include("ok: created API") + + rr = apiList(basepathOrApiName = Some(testbasepath)) + println("api list:\n" + rr.stdout) + testops foreach { testurlop => + rr.stdout should include regex (s"\\s+${testurlop}\\s+${testapiname}\\s+") + } + rr.stdout should include(testbasepath + testrelpath) + + rr = apiList(basepathOrApiName = Some(testbasepath), full = Some(true)) + println("api full list:\n" + rr.stdout) + testops foreach { testurlop => + rr.stdout should include regex (s"Verb:\\s+${testurlop}") + } + rr.stdout should include(testbasepath + testrelpath) + + } finally { + val deleteresult = apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT) + } + } } diff --git a/tools/cli/go-whisk-cli/commands/api.go b/tools/cli/go-whisk-cli/commands/api.go index 00167eb..d27a42e 100644 --- a/tools/cli/go-whisk-cli/commands/api.go +++ b/tools/cli/go-whisk-cli/commands/api.go @@ -864,21 +864,34 @@ var apiCreateCmdV2 = &cobra.Command{ for op, opv := range retApi.Swagger.Paths[path] { whisk.Debug(whisk.DbgInfo, "Path operation: %s\n", op) var fqActionName string - if (len(opv.XOpenWhisk.Package) > 0) { + if (opv.XOpenWhisk == nil) { + fqActionName = "" + } else if (len(opv.XOpenWhisk.Package) > 0) { fqActionName = "/"+opv.XOpenWhisk.Namespace+"/"+opv.XOpenWhisk.Package+"/"+opv.XOpenWhisk.ActionName } else { fqActionName = "/"+opv.XOpenWhisk.Namespace+"/"+opv.XOpenWhisk.ActionName } whisk.Debug(whisk.DbgInfo, "baseUrl %s Path %s Path obj %+v\n", baseUrl, path, opv) - fmt.Fprintf(color.Output, - wski18n.T("{{.ok}} created API {{.path}} {{.verb}} for action {{.name}}\n{{.fullpath}}\n", - map[string]interface{}{ - "ok": color.GreenString("ok:"), - "path": strings.TrimSuffix(retApi.Swagger.BasePath, "/") + path, - "verb": op, - "name": boldString(fqActionName), - "fullpath": managedUrl, - })) + if len(fqActionName) > 0 { + fmt.Fprintf(color.Output, + wski18n.T("{{.ok}} created API {{.path}} {{.verb}} for action {{.name}}\n{{.fullpath}}\n", + map[string]interface{}{ + "ok": color.GreenString("ok:"), + "path": strings.TrimSuffix(retApi.Swagger.BasePath, "/") + path, + "verb": op, + "name": boldString(fqActionName), + "fullpath": managedUrl, + })) + } else { + fmt.Fprintf(color.Output, + wski18n.T("{{.ok}} created API {{.path}} {{.verb}}\n{{.fullpath}}\n", + map[string]interface{}{ + "ok": color.GreenString("ok:"), + "path": strings.TrimSuffix(retApi.Swagger.BasePath, "/") + path, + "verb": op, + "fullpath": managedUrl, + })) + } } } } @@ -1218,7 +1231,9 @@ func printFilteredListApiV2(resultApi *whisk.RetApiV2, apiPath string, apiVerb s if ( len(apiVerb) == 0 || strings.ToLower(op) == strings.ToLower(apiVerb)) { whisk.Debug(whisk.DbgInfo, "printFilteredListApiV2: operation matches: %#v\n", opv) var actionName string - if (len(opv.XOpenWhisk.Package) > 0) { + if (opv.XOpenWhisk == nil) { + actionName = "" + } else if (len(opv.XOpenWhisk.Package) > 0) { actionName = "/"+opv.XOpenWhisk.Namespace+"/"+opv.XOpenWhisk.Package+"/"+opv.XOpenWhisk.ActionName } else { actionName = "/"+opv.XOpenWhisk.Namespace+"/"+opv.XOpenWhisk.ActionName @@ -1256,7 +1271,9 @@ func printFilteredListRowV2(resultApi *whisk.RetApiV2, apiPath string, apiVerb s if ( len(apiVerb) == 0 || strings.ToLower(op) == strings.ToLower(apiVerb)) { whisk.Debug(whisk.DbgInfo, "printFilteredListRowV2: operation matches: %#v\n", opv) var actionName string - if (len(opv.XOpenWhisk.Package) > 0) { + if (opv.XOpenWhisk == nil) { + actionName = "" + } else if (len(opv.XOpenWhisk.Package) > 0) { actionName = "/"+opv.XOpenWhisk.Namespace+"/"+opv.XOpenWhisk.Package+"/"+opv.XOpenWhisk.ActionName } else { actionName = "/"+opv.XOpenWhisk.Namespace+"/"+opv.XOpenWhisk.ActionName @@ -1287,7 +1304,9 @@ func getLargestActionNameSizeV2(retApiArray *whisk.RetApiArrayV2, apiPath string if ( len(apiVerb) == 0 || strings.ToLower(op) == strings.ToLower(apiVerb)) { whisk.Debug(whisk.DbgInfo, "getLargestActionNameSize: operation matches: %#v\n", opv) var fullActionName string - if (len(opv.XOpenWhisk.Package) > 0) { + if (opv.XOpenWhisk == nil) { + fullActionName = "" + } else if (len(opv.XOpenWhisk.Package) > 0) { fullActionName = "/"+opv.XOpenWhisk.Namespace+"/"+opv.XOpenWhisk.Package+"/"+opv.XOpenWhisk.ActionName } else { fullActionName = "/"+opv.XOpenWhisk.Namespace+"/"+opv.XOpenWhisk.ActionName 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 7d3a9bd..765f961 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 @@ -1188,6 +1188,10 @@ "translation": "{{.ok}} created API {{.path}} {{.verb}} for action {{.name}}\n{{.fullpath}}\n" }, { + "id": "{{.ok}} created API {{.path}} {{.verb}}\n{{.fullpath}}\n", + "translation": "{{.ok}} created API {{.path}} {{.verb}}\n{{.fullpath}}\n" + }, + { "id": "Unable to parse api command arguments: {{.err}}", "translation": "Unable to parse api command arguments: {{.err}}" }, diff --git a/tools/cli/go-whisk/whisk/api.go b/tools/cli/go-whisk/whisk/api.go index baeb0c5..6b9d4a6 100644 --- a/tools/cli/go-whisk/whisk/api.go +++ b/tools/cli/go-whisk/whisk/api.go @@ -545,21 +545,15 @@ func validateApiPath(path map[string]*ApiSwaggerOperationV2) error { } func validateApiOperation(opName string, op *ApiSwaggerOperationV2) error { - if len(op.OperationId) == 0 { - Debug(DbgError, "validateApiResponse: No operationId field in operation %v\n", op) + if (op.XOpenWhisk != nil && len(op.OperationId) == 0) { + Debug(DbgError, "validateApiOperation: No operationId field in operation %v\n", op) errMsg := wski18n.T("Missing operationId field in API configuration for operation {{.op}}", map[string]interface{}{"op": opName}) whiskErr := MakeWskError(errors.New(errMsg), EXITCODE_ERR_NETWORK, DISPLAY_MSG, NO_DISPLAY_USAGE) return whiskErr } - if op.XOpenWhisk == nil { - Debug(DbgError, "validateApiResponse: No x-openwhisk stanza in operation %v\n", op) - errMsg := wski18n.T("Missing x-openwhisk stanza in API configuration for operation {{.op}}", - map[string]interface{}{"op": opName}) - whiskErr := MakeWskError(errors.New(errMsg), EXITCODE_ERR_NETWORK, DISPLAY_MSG, NO_DISPLAY_USAGE) - return whiskErr - } - if len(op.XOpenWhisk.Namespace) == 0 { + + if (op.XOpenWhisk != nil && len(op.XOpenWhisk.Namespace) == 0) { Debug(DbgError, "validateApiOperation: no x-openwhisk.namespace stanza in operation %v\n", op) errMsg := wski18n.T("Missing x-openwhisk.namespace field in API configuration for operation {{.op}}", map[string]interface{}{"op": opName}) @@ -569,14 +563,14 @@ func validateApiOperation(opName string, op *ApiSwaggerOperationV2) error { // Note: The op.XOpenWhisk.Package field can have a value of "", so don't enforce a value - if len(op.XOpenWhisk.ActionName) == 0 { + if (op.XOpenWhisk != nil && len(op.XOpenWhisk.ActionName) == 0) { Debug(DbgError, "validateApiOperation: no x-openwhisk.action stanza in operation %v\n", op) errMsg := wski18n.T("Missing x-openwhisk.action field in API configuration for operation {{.op}}", map[string]interface{}{"op": opName}) whiskErr := MakeWskError(errors.New(errMsg), EXITCODE_ERR_NETWORK, DISPLAY_MSG, NO_DISPLAY_USAGE) return whiskErr } - if len(op.XOpenWhisk.ApiUrl) == 0 { + if (op.XOpenWhisk != nil && len(op.XOpenWhisk.ApiUrl) == 0) { Debug(DbgError, "validateApiOperation: no x-openwhisk.url stanza in operation %v\n", op) errMsg := wski18n.T("Missing x-openwhisk.url field in API configuration for operation {{.op}}", map[string]interface{}{"op": opName}) -- To stop receiving notification emails like this one, please contact ['"commits@openwhisk.apache.org" '].