You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by mr...@apache.org on 2018/04/06 19:19:08 UTC

[incubator-openwhisk-wskdeploy] branch master updated: adding support to create api gateway based on sequences (#858)

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-wskdeploy.git


The following commit(s) were added to refs/heads/master by this push:
     new 2f1996c  adding support to create api gateway based on sequences (#858)
2f1996c is described below

commit 2f1996ca3fb53514fee10ed05975ada3084d16b0
Author: Priti Desai <pd...@us.ibm.com>
AuthorDate: Fri Apr 6 12:19:05 2018 -0700

    adding support to create api gateway based on sequences (#858)
---
 parsers/manifest_parser.go                       | 92 ++++++++++++++----------
 parsers/manifest_parser_test.go                  |  6 +-
 tests/dat/manifest_data_compose_api_records.yaml |  5 ++
 tests/src/integration/apigateway/manifest.yml    |  4 ++
 utils/webaction.go                               |  4 ++
 wski18n/i18n_ids.go                              | 40 ++++++-----
 wski18n/i18n_resources.go                        |  4 +-
 wski18n/resources/en_US.all.json                 |  8 ++-
 8 files changed, 100 insertions(+), 63 deletions(-)

diff --git a/parsers/manifest_parser.go b/parsers/manifest_parser.go
index b46f73a..c63e4dd 100644
--- a/parsers/manifest_parser.go
+++ b/parsers/manifest_parser.go
@@ -1027,13 +1027,7 @@ func (dm *YAMLParser) ComposeApiRecords(client *whisk.Config, packageName string
 				}
 				for actionName, gatewayMethod := range gatewayRelPathMap {
 					// verify that the action is defined under actions sections
-					if _, ok := pkg.Actions[actionName]; !ok {
-						return nil, wskderrors.NewYAMLFileFormatError(manifestPath,
-							wski18n.T(wski18n.ID_ERR_API_MISSING_ACTION_X_action_X_api_X,
-								map[string]interface{}{
-									wski18n.KEY_ACTION: actionName,
-									wski18n.KEY_API:    apiName}))
-					} else {
+					if _, ok := pkg.Actions[actionName]; ok {
 						// verify that the action is defined as web action
 						// web or web-export set to any of [true, yes, raw]
 						a := pkg.Actions[actionName]
@@ -1049,38 +1043,62 @@ func (dm *YAMLParser) ComposeApiRecords(client *whisk.Config, packageName string
 							a.Annotations[utils.WEB_EXPORT_ANNOT] = true
 							pkg.Actions[actionName] = a
 						}
-						request := new(whisk.ApiCreateRequest)
-						request.ApiDoc = new(whisk.Api)
-						request.ApiDoc.GatewayBasePath = gatewayBasePath
-						// is API verb is valid, it must be one of (GET, PUT, POST, DELETE)
-						request.ApiDoc.GatewayRelPath = gatewayRelPath
-						if _, ok := whisk.ApiVerbs[strings.ToUpper(gatewayMethod)]; !ok {
-							return nil, wskderrors.NewInvalidAPIGatewayMethodError(manifestPath,
-								gatewayBasePath+gatewayRelPath,
-								gatewayMethod,
-								dm.getGatewayMethods())
-						}
-						request.ApiDoc.GatewayMethod = strings.ToUpper(gatewayMethod)
-						request.ApiDoc.Namespace = client.Namespace
-						request.ApiDoc.ApiName = apiName
-						request.ApiDoc.Id = strings.Join([]string{API, request.ApiDoc.Namespace, request.ApiDoc.GatewayRelPath}, ":")
-						// set action of an API Doc
-						request.ApiDoc.Action = new(whisk.ApiAction)
-						if packageName == DEFAULT_PACKAGE {
-							request.ApiDoc.Action.Name = actionName
-						} else {
-							request.ApiDoc.Action.Name = packageName + PATH_SEPARATOR + actionName
+						// verify that the sequence is defined under sequences sections
+					} else if _, ok := pkg.Sequences[actionName]; ok {
+						// verify that the sequence is defined as web sequence
+						// web set to any of [true, yes, raw]
+						a := pkg.Sequences[actionName]
+						if !utils.IsWebSequence(a.Web) {
+							warningString := wski18n.T(wski18n.ID_WARN_API_MISSING_WEB_SEQUENCE_X_sequence_X_api_X,
+								map[string]interface{}{
+									wski18n.KEY_SEQUENCE: actionName,
+									wski18n.KEY_API:      apiName})
+							wskprint.PrintOpenWhiskWarning(warningString)
+							if a.Annotations == nil {
+								a.Annotations = make(map[string]interface{}, 0)
+							}
+							a.Annotations[utils.WEB_EXPORT_ANNOT] = true
+							pkg.Sequences[actionName] = a
 						}
-						url := []string{HTTPS + client.Host, strings.ToLower(API),
-							API_VERSION, WEB, client.Namespace, packageName,
-							actionName + "." + utils.HTTP_FILE_EXTENSION}
-						request.ApiDoc.Action.Namespace = client.Namespace
-						request.ApiDoc.Action.BackendUrl = strings.Join(url, PATH_SEPARATOR)
-						request.ApiDoc.Action.BackendMethod = gatewayMethod
-						request.ApiDoc.Action.Auth = client.AuthToken
-						// add a newly created ApiCreateRequest object to a list of requests
-						requests = append(requests, request)
+						// return failure since action or sequence are not defined in the manifest
+					} else {
+						return nil, wskderrors.NewYAMLFileFormatError(manifestPath,
+							wski18n.T(wski18n.ID_ERR_API_MISSING_ACTION_OR_SEQUENCE_X_action_or_sequence_X_api_X,
+								map[string]interface{}{
+									wski18n.KEY_ACTION: actionName,
+									wski18n.KEY_API:    apiName}))
+					}
+					request := new(whisk.ApiCreateRequest)
+					request.ApiDoc = new(whisk.Api)
+					request.ApiDoc.GatewayBasePath = gatewayBasePath
+					// is API verb is valid, it must be one of (GET, PUT, POST, DELETE)
+					request.ApiDoc.GatewayRelPath = gatewayRelPath
+					if _, ok := whisk.ApiVerbs[strings.ToUpper(gatewayMethod)]; !ok {
+						return nil, wskderrors.NewInvalidAPIGatewayMethodError(manifestPath,
+							gatewayBasePath+gatewayRelPath,
+							gatewayMethod,
+							dm.getGatewayMethods())
+					}
+					request.ApiDoc.GatewayMethod = strings.ToUpper(gatewayMethod)
+					request.ApiDoc.Namespace = client.Namespace
+					request.ApiDoc.ApiName = apiName
+					request.ApiDoc.Id = strings.Join([]string{API, request.ApiDoc.Namespace, request.ApiDoc.GatewayRelPath}, ":")
+					// set action of an API Doc
+					request.ApiDoc.Action = new(whisk.ApiAction)
+					if packageName == DEFAULT_PACKAGE {
+						request.ApiDoc.Action.Name = actionName
+					} else {
+						request.ApiDoc.Action.Name = packageName + PATH_SEPARATOR + actionName
 					}
+					url := []string{HTTPS + client.Host, strings.ToLower(API),
+						API_VERSION, WEB, client.Namespace, packageName,
+						actionName + "." + utils.HTTP_FILE_EXTENSION}
+					request.ApiDoc.Action.Namespace = client.Namespace
+					request.ApiDoc.Action.BackendUrl = strings.Join(url, PATH_SEPARATOR)
+					request.ApiDoc.Action.BackendMethod = gatewayMethod
+					request.ApiDoc.Action.Auth = client.AuthToken
+					// add a newly created ApiCreateRequest object to a list of requests
+					requests = append(requests, request)
 				}
 			}
 		}
diff --git a/parsers/manifest_parser_test.go b/parsers/manifest_parser_test.go
index c3d62d4..113049c 100644
--- a/parsers/manifest_parser_test.go
+++ b/parsers/manifest_parser_test.go
@@ -1305,8 +1305,6 @@ func TestComposeRules(t *testing.T) {
 	}
 }
 
-// TODO(752) We SHOULD automatically add "web-export" to each Action referenced in the "apis" section
-// as this is implied.  The user should not have to do this manually
 func TestComposeApiRecords(t *testing.T) {
 
 	p, m, _ := testLoadParseManifest(t, "../tests/dat/manifest_data_compose_api_records.yaml")
@@ -1323,7 +1321,7 @@ func TestComposeApiRecords(t *testing.T) {
 	if err != nil {
 		assert.Fail(t, "Failed to compose api records: "+err.Error())
 	}
-	assert.Equal(t, 6, len(apiList), "Failed to get api records")
+	assert.Equal(t, 7, len(apiList), "Failed to get api records")
 	for _, apiRecord := range apiList {
 		apiDoc := apiRecord.ApiDoc
 		action := apiDoc.Action
@@ -1354,10 +1352,12 @@ func TestComposeApiRecords(t *testing.T) {
 			assert.Equal(t, "/books2", apiDoc.GatewayRelPath, "Failed to set api rel path")
 			assert.Equal(t, "post", action.BackendMethod, "Failed to set api backend method")
 		case "apiTest/listMembers2":
+		case "apiTest/listAllMembers":
 			assert.Equal(t, "book-club2", apiDoc.ApiName, "Failed to set api name")
 			assert.Equal(t, "/club2", apiDoc.GatewayBasePath, "Failed to set api base path")
 			assert.Equal(t, "/members2", apiDoc.GatewayRelPath, "Failed to set api rel path")
 			assert.Equal(t, "get", action.BackendMethod, "Failed to set api backend method")
+
 		default:
 			assert.Fail(t, "Failed to get api action name")
 		}
diff --git a/tests/dat/manifest_data_compose_api_records.yaml b/tests/dat/manifest_data_compose_api_records.yaml
index 385c8e9..6191a1f 100644
--- a/tests/dat/manifest_data_compose_api_records.yaml
+++ b/tests/dat/manifest_data_compose_api_records.yaml
@@ -30,6 +30,10 @@ packages:
         function: ../tests/src/integration/helloworld/actions/hello.js
       listMembers2:
         function: ../tests/src/integration/helloworld/actions/hello.js
+    sequences:
+      listAllMembers:
+        actions: listMembers, listMembers2
+        web: true
     apis:
       book-club:
         club:
@@ -45,3 +49,4 @@ packages:
             postBooks2: post
           members2:
             listMembers2: get
+            listAllMembers: get
diff --git a/tests/src/integration/apigateway/manifest.yml b/tests/src/integration/apigateway/manifest.yml
index e2b26f5..5c22af2 100644
--- a/tests/src/integration/apigateway/manifest.yml
+++ b/tests/src/integration/apigateway/manifest.yml
@@ -34,6 +34,9 @@ packages:
                 function: src/delete-books.js
             listMembers:
                 function: src/list-members.js
+        sequences:
+            listAllMembers:
+                actions: listMembers
         # new top-level key for defining groups of named APIs
         apis:
             hello-world:
@@ -49,3 +52,4 @@ packages:
                         deleteBooks: DELETE
                     members:
                         listMembers: GET
+                        listAllMembers: GET
diff --git a/utils/webaction.go b/utils/webaction.go
index 087a773..64fe346 100644
--- a/utils/webaction.go
+++ b/utils/webaction.go
@@ -121,3 +121,7 @@ func IsWebAction(webexport string) bool {
 	}
 	return false
 }
+
+func IsWebSequence(webexport string) bool {
+	return IsWebAction(webexport)
+}
diff --git a/wski18n/i18n_ids.go b/wski18n/i18n_ids.go
index 1ede72a..eae4a0b 100644
--- a/wski18n/i18n_ids.go
+++ b/wski18n/i18n_ids.go
@@ -77,6 +77,7 @@ const (
 	KEY_BINDINGS        = "bindings"
 	KEY_DEPENDENCY      = "dependency"
 	KEY_LOCATION        = "location"
+	KEY_SEQUENCE        = "sequence"
 )
 
 // DO NOT TRANSLATE
@@ -162,25 +163,25 @@ const (
 	ID_MSG_MANAGED_FOUND_DELETED_X_key_X_name_X_project_X = "msg_managed_found_deleted_entity"
 
 	// Errors
-	ID_ERR_DEPENDENCY_UNKNOWN_TYPE                                   = "msg_err_dependency_unknown_type"
-	ID_ERR_ENTITY_CREATE_X_key_X_err_X_code_X                        = "msg_err_entity_create"
-	ID_ERR_ENTITY_DELETE_X_key_X_err_X_code_X                        = "msg_err_entity_delete"
-	ID_ERR_FEED_INVOKE_X_err_X_code_X                                = "msg_err_feed_invoke"
-	ID_ERR_KEY_MISSING_X_key_X                                       = "msg_err_key_missing_mandatory"
-	ID_ERR_MANIFEST_FILE_NOT_FOUND_X_path_X                          = "msg_err_manifest_not_found"
-	ID_ERR_NAME_MISMATCH_X_key_X_dname_X_dpath_X_mname_X_moath_X     = "msg_err_name_mismatch"
-	ID_ERR_RUNTIME_INVALID_X_runtime_X_action_X                      = "msg_err_runtime_invalid"
-	ID_ERR_RUNTIME_MISMATCH_X_runtime_X_ext_X_action_X               = "msg_err_runtime_mismatch"
-	ID_ERR_RUNTIMES_GET_X_err_X                                      = "msg_err_runtimes_get"
-	ID_ERR_RUNTIME_ACTION_SOURCE_NOT_SUPPORTED_X_ext_X_action_X      = "msg_err_runtime_action_source_not_supported"
-	ID_ERR_URL_INVALID_X_urltype_X_url_X_filetype_X                  = "msg_err_url_invalid"
-	ID_ERR_URL_MALFORMED_X_urltype_X_url_X                           = "msg_err_url_malformed"
-	ID_ERR_API_MISSING_ACTION_X_action_X_api_X                       = "msg_err_api_missing_action"
-	ID_ERR_ACTION_INVALID_X_action_X                                 = "msg_err_action_invalid"
-	ID_ERR_ACTION_MISSING_RUNTIME_WITH_CODE_X_action_X               = "msg_err_action_missing_runtime_with_code"
-	ID_ERR_ACTION_FUNCTION_REMOTE_DIR_NOT_SUPPORTED_X_action_X_url_X = "msg_err_action_function_remote_dir_not_supported"
-	ID_ERR_CANT_SAVE_DOCKER_RUNTIME                                  = "msg_err_cant_save_docker"
-	ID_ERR_FILE_ALREADY_EXISTS                                       = "msg_err_file_already_exists"
+	ID_ERR_DEPENDENCY_UNKNOWN_TYPE                                     = "msg_err_dependency_unknown_type"
+	ID_ERR_ENTITY_CREATE_X_key_X_err_X_code_X                          = "msg_err_entity_create"
+	ID_ERR_ENTITY_DELETE_X_key_X_err_X_code_X                          = "msg_err_entity_delete"
+	ID_ERR_FEED_INVOKE_X_err_X_code_X                                  = "msg_err_feed_invoke"
+	ID_ERR_KEY_MISSING_X_key_X                                         = "msg_err_key_missing_mandatory"
+	ID_ERR_MANIFEST_FILE_NOT_FOUND_X_path_X                            = "msg_err_manifest_not_found"
+	ID_ERR_NAME_MISMATCH_X_key_X_dname_X_dpath_X_mname_X_moath_X       = "msg_err_name_mismatch"
+	ID_ERR_RUNTIME_INVALID_X_runtime_X_action_X                        = "msg_err_runtime_invalid"
+	ID_ERR_RUNTIME_MISMATCH_X_runtime_X_ext_X_action_X                 = "msg_err_runtime_mismatch"
+	ID_ERR_RUNTIMES_GET_X_err_X                                        = "msg_err_runtimes_get"
+	ID_ERR_RUNTIME_ACTION_SOURCE_NOT_SUPPORTED_X_ext_X_action_X        = "msg_err_runtime_action_source_not_supported"
+	ID_ERR_URL_INVALID_X_urltype_X_url_X_filetype_X                    = "msg_err_url_invalid"
+	ID_ERR_URL_MALFORMED_X_urltype_X_url_X                             = "msg_err_url_malformed"
+	ID_ERR_API_MISSING_ACTION_OR_SEQUENCE_X_action_or_sequence_X_api_X = "msg_err_api_missing_action_or_sequence"
+	ID_ERR_ACTION_INVALID_X_action_X                                   = "msg_err_action_invalid"
+	ID_ERR_ACTION_MISSING_RUNTIME_WITH_CODE_X_action_X                 = "msg_err_action_missing_runtime_with_code"
+	ID_ERR_ACTION_FUNCTION_REMOTE_DIR_NOT_SUPPORTED_X_action_X_url_X   = "msg_err_action_function_remote_dir_not_supported"
+	ID_ERR_CANT_SAVE_DOCKER_RUNTIME                                    = "msg_err_cant_save_docker"
+	ID_ERR_FILE_ALREADY_EXISTS                                         = "msg_err_file_already_exists"
 
 	// Server-side Errors (wskdeploy as an Action)
 	ID_ERR_JSON_MISSING_KEY_CMD = "msg_err_json_missing_cmd_key"
@@ -207,6 +208,7 @@ const (
 	ID_WARN_PACKAGE_IS_PUBLIC_X_package_X                     = "msg_warn_package_is_public"
 	ID_WARN_ACTION_WEB_X_action_X                             = "msg_warn_action_web_export_ignored"
 	ID_WARN_API_MISSING_WEB_ACTION_X_action_X_api_X           = "msg_warn_api_missing_web_action"
+	ID_WARN_API_MISSING_WEB_SEQUENCE_X_sequence_X_api_X       = "msg_warn_api_missing_web_sequence"
 
 	// Verbose (Debug/Trace) messages
 	ID_DEBUG_PROJECT_SEARCH_X_path_X_key_X                = "msg_dbg_searching_project_directory"
diff --git a/wski18n/i18n_resources.go b/wski18n/i18n_resources.go
index 7bc2343..e77a8f5 100644
--- a/wski18n/i18n_resources.go
+++ b/wski18n/i18n_resources.go
@@ -97,7 +97,7 @@ func wski18nResourcesDe_deAllJson() (*asset, error) {
 	return a, nil
 }
 
-var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x5b\x6d\x8f\xdb\x36\xf2\x7f\x9f\x4f\x31\x08\xfe\x40\x5a\xc0\x51\xd2\xfe\x71\xc0\x21\xc0\xbe\xc8\x75\xd3\x76\xaf\x4d\x36\xd8\xcd\x5e\x50\xe4\x16\x0a\x2d\x8d\x6d\xd6\x12\x29\x90\x94\x1d\x77\xe1\xef\x7e\x98\x21\xf5\x60\xef\x52\xd2\x3a\xed\x5d\xdf\xd4\x09\x87\x33\xbf\x19\x0e\xe7\x89\xca\xa7\x27\x00\x77\x4f\x00\x00\x9e\xca\xfc\xe9\x2b\x78\x5a\xda\x65\x5a\x19\x5c\xc8\x2f\x29\x1a\xa3\xcd\xd3\x99\x5f\x75\x46 [...]
+var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x5b\x6f\x8f\xdb\x36\xd2\x7f\x9f\x4f\x31\x08\x1e\x20\x2d\xe0\x28\x69\x1f\x3c\xc0\x83\x00\x79\x91\x6b\xd2\x76\xaf\x4d\x36\xd8\xcd\x5e\x50\xe4\x16\x0a\x2d\x8d\x6d\xd6\x12\xa9\x23\x29\x3b\xae\xe1\xef\x7e\x98\x21\xf5\xc7\xde\xa5\xa4\x75\xda\xbb\xbe\xa9\xbb\x1c\xce\xfc\x66\x38\x9c\x7f\x54\x3f\x3d\x02\xd8\x3f\x02\x00\x78\x2c\xf3\xc7\x2f\xe0\x71\x69\x97\x69\x65\x70\x21\xbf\xa4\x68\x8c\x36\x8f\x67\x7e\xd5\x19 [...]
 
 func wski18nResourcesEn_usAllJsonBytes() ([]byte, error) {
 	return bindataRead(
@@ -112,7 +112,7 @@ func wski18nResourcesEn_usAllJson() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 14019, mode: os.FileMode(420), modTime: time.Unix(1522283010, 0)}
+	info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 14286, mode: os.FileMode(420), modTime: time.Unix(1523039220, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
diff --git a/wski18n/resources/en_US.all.json b/wski18n/resources/en_US.all.json
index b03692a..f765820 100644
--- a/wski18n/resources/en_US.all.json
+++ b/wski18n/resources/en_US.all.json
@@ -292,8 +292,8 @@
     "translation": "JSON input data Missing 'cmd' key"
   },
   {
-    "id": "msg_err_api_missing_action",
-    "translation": "Action [{{.action}}] is missing from manifest file, API [{{.api}}] can only be created based on the action from manifest file. Please update manifest file to include [{{.action}}] as a web action.\n"
+    "id": "msg_err_api_missing_action_or_sequence",
+    "translation": "Action/Sequence [{{.action}}] is missing from manifest file, API [{{.api}}] can only be created based on the action/sequence from manifest file. Please update manifest file to include [{{.action}}] as a web action/sequence.\n"
   },
   {
     "id": "msg_err_action_invalid",
@@ -404,6 +404,10 @@
     "translation": "Action [{{.action}}] is not a web action, API [{{.api}}] can only be created using web action. Converting [{{.action}}] to a web action.\n"
   },
   {
+    "id": "msg_warn_api_missing_web_sequence",
+    "translation": "Sequence [{{.sequence}}] is not a web sequence, API [{{.api}}] can only be created using web sequence. Converting [{{.sequence}}] to a web sequence.\n"
+  },
+  {
     "id": "DEBUG",
     "translation": "================= DEBUG ==================="
   },

-- 
To stop receiving notification emails like this one, please contact
mrutkowski@apache.org.