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

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


The following commit(s) were added to refs/heads/master by this push:
     new db5e34e  Enable Web Secure token for sequences on API create (#1087)
db5e34e is described below

commit db5e34e35825900c52017b545e56935c5bea5578
Author: Matt Rutkowski <mrutk...@us.ibm.com>
AuthorDate: Fri Jan 31 18:14:23 2020 -0600

    Enable Web Secure token for sequences on API create (#1087)
    
    * Enable Web Secure token for sequences on API create
    
    * Enable Web Secure token for sequences on API create
    
    * Fix non-working code that attempted to add web annotations
    
    * refine procedural logic for reuse
    
    * refine procedural logic for reuse
    
    * refine procedural logic for reuse
    
    * refine procedural logic for reuse
    
    * refine procedural logic for reuse
---
 deployers/manifestreader.go                        |  2 +-
 deployers/servicedeployer.go                       | 11 +++--
 parsers/manifest_parser.go                         | 57 +++++++++-------------
 parsers/manifest_parser_test.go                    |  2 +-
 specification/html/spec_sequences.md               |  7 +++
 ...ng_web_annotation_on_api_action_or_sequence.yml | 53 ++++++++++++++++++++
 ...manifest_require_whisk_auth_sequence_valid.yaml | 41 ++++++++++++++++
 tests/src/integration/webaction/src/hello.js       | 24 +++++++++
 .../webaction/src/hello_http_validate.js           | 36 ++++++++++++++
 .../integration/webaction/src/hello_http_wrap.js   | 28 +++++++++++
 utils/misc.go                                      | 11 +++++
 webaction/webaction.go                             | 52 +++++++++++++++++---
 wskderrors/wskdeployerror.go                       | 32 ++++++++++++
 wski18n/i18n_ids.go                                |  5 ++
 wski18n/i18n_resources.go                          |  4 +-
 wski18n/resources/en_US.all.json                   | 12 ++++-
 16 files changed, 326 insertions(+), 51 deletions(-)

diff --git a/deployers/manifestreader.go b/deployers/manifestreader.go
index b039a30..63fe49d 100644
--- a/deployers/manifestreader.go
+++ b/deployers/manifestreader.go
@@ -108,7 +108,7 @@ func (reader *ManifestReader) HandleYaml(manifestParser 
*parsers.YAMLParser, man
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
 
-       apis, responses, err := 
manifestParser.ComposeApiRecordsFromAllPackages(reader.serviceDeployer.ClientConfig,
 manifest)
+       apis, responses, err := 
manifestParser.ComposeApiRecordsFromAllPackages(reader.serviceDeployer.ClientConfig,
 manifest, actions, sequences)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
diff --git a/deployers/servicedeployer.go b/deployers/servicedeployer.go
index 47f6036..1bba645 100644
--- a/deployers/servicedeployer.go
+++ b/deployers/servicedeployer.go
@@ -1012,15 +1012,18 @@ func (deployer *ServiceDeployer) createAction(pkgname 
string, action *whisk.Acti
        return nil
 }
 
-func (deployer *ServiceDeployer) 
getAnnotationsFromPackageAction(packageActionName string) *whisk.KeyValueArr {
+func (deployer *ServiceDeployer) 
getAnnotationsFromPackageActionOrSequence(packageActionName string) 
*whisk.KeyValueArr {
 
        if len(packageActionName)!=0 {
                // Split the package name and action name being searched for
-               aActionName := strings.Split(packageActionName,"/")
+               aActionName := strings.Split(packageActionName, 
parsers.PATH_SEPARATOR)
 
+               // Attempt to locate the named action (or sequence) to return 
its annotations
                if pkg, found := deployer.Deployment.Packages[aActionName[0]]; 
found {
                        if atemp, found := pkg.Actions[aActionName[1]]; found {
                                return &(atemp.Action.Annotations)
+                       } else if atemp, found := 
pkg.Sequences[aActionName[1]]; found {
+                               return &(atemp.Action.Annotations)
                        }
                }
        }
@@ -1041,9 +1044,11 @@ func (deployer *ServiceDeployer) createApi(api 
*whisk.ApiCreateRequest) error {
 
        // Retrieve annotations on the action we are attempting to create an 
API for
        var actionAnnotations *whisk.KeyValueArr
-       actionAnnotations = 
deployer.getAnnotationsFromPackageAction(api.ApiDoc.Action.Name)
+       actionAnnotations = 
deployer.getAnnotationsFromPackageActionOrSequence(api.ApiDoc.Action.Name)
 
        // Process any special annotations (e.g., "require-whisk-auth") on the 
associated Action
+       // NOTE: we do not throw an error if annotations are NOT found (nil) 
since this is already done in
+       // the parsing phase and would be redundant.
        if actionAnnotations != nil {
                wskprint.PrintlnOpenWhiskVerbose(utils.Flags.Verbose, 
fmt.Sprintf("Processing action annotations: %v", actionAnnotations))
 
diff --git a/parsers/manifest_parser.go b/parsers/manifest_parser.go
index b1ece3e..d29e496 100644
--- a/parsers/manifest_parser.go
+++ b/parsers/manifest_parser.go
@@ -1131,7 +1131,9 @@ func (dm *YAMLParser) ComposeRules(pkg Package, 
packageName string, managedAnnot
        return rules, nil
 }
 
-func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(client *whisk.Config, 
manifest *YAML) ([]*whisk.ApiCreateRequest, 
map[string]*whisk.ApiCreateRequestOptions, error) {
+func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(client *whisk.Config, 
manifest *YAML,
+       actionrecords []utils.ActionRecord,
+       sequencerecords []utils.ActionRecord) ([]*whisk.ApiCreateRequest, 
map[string]*whisk.ApiCreateRequestOptions, error) {
        var requests = make([]*whisk.ApiCreateRequest, 0)
        var responses = make(map[string]*whisk.ApiCreateRequestOptions, 0)
        manifestPackages := make(map[string]Package)
@@ -1143,7 +1145,8 @@ func (dm *YAMLParser) 
ComposeApiRecordsFromAllPackages(client *whisk.Config, man
        }
 
        for packageName, p := range manifestPackages {
-               r, response, err := dm.ComposeApiRecords(client, packageName, 
p, manifest.Filepath)
+               r, response, err := dm.ComposeApiRecords(client, packageName, 
p, manifest.Filepath,
+                       actionrecords, sequencerecords)
                if err == nil {
                        requests = append(requests, r...)
                        for k, v := range response {
@@ -1181,7 +1184,8 @@ func (dm *YAMLParser) 
ComposeApiRecordsFromAllPackages(client *whisk.Config, man
  *     }
  * }
  */
-func (dm *YAMLParser) ComposeApiRecords(client *whisk.Config, packageName 
string, pkg Package, manifestPath string) ([]*whisk.ApiCreateRequest, 
map[string]*whisk.ApiCreateRequestOptions, error) {
+func (dm *YAMLParser) ComposeApiRecords(client *whisk.Config, packageName 
string, pkg Package, manifestPath string,
+       actionrecords []utils.ActionRecord, sequencerecords 
[]utils.ActionRecord) ([]*whisk.ApiCreateRequest, 
map[string]*whisk.ApiCreateRequestOptions, error) {
        var requests = make([]*whisk.ApiCreateRequest, 0)
 
        // supply a dummy API GW token as it is optional
@@ -1217,41 +1221,24 @@ func (dm *YAMLParser) ComposeApiRecords(client 
*whisk.Config, packageName string
                                        gatewayRelPath = PATH_SEPARATOR + 
gatewayRelPath
                                }
                                for actionName, gatewayMethodResponse := range 
gatewayRelPathMap {
-                                       // verify that the action is defined 
under actions sections
+                                       // verify that the action is defined 
under action records
                                        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]
-                                               if 
!webaction.IsWebAction(a.GetWeb()) {
-                                                       warningString := 
wski18n.T(wski18n.ID_WARN_API_MISSING_WEB_ACTION_X_action_X_api_X,
-                                                               
map[string]interface{}{
-                                                                       
wski18n.KEY_ACTION: actionName,
-                                                                       
wski18n.KEY_API:    apiName})
-                                                       
wskprint.PrintOpenWhiskWarning(warningString)
-                                                       if a.Annotations == nil 
{
-                                                               a.Annotations = 
make(map[string]interface{}, 0)
-                                                       }
-                                                       
a.Annotations[webaction.WEB_EXPORT_ANNOT] = true
-                                                       pkg.Actions[actionName] 
= a
+                                               // verify that the action is 
defined as web action;
+                                               // web or web-export set to any 
of [true, yes, raw]; if not,
+                                               // we will try to add it (if no 
strict" flag) and warn user that we did so
+                                               if err := 
webaction.TryUpdateAPIsActionToWebAction(actionrecords, packageName,
+                                                       apiName, actionName, 
false); err!=nil {
+                                                       return requests, 
requestOptions, err
                                                }
-                                               // verify that the sequence is 
defined under sequences sections
+                                               // verify that the sequence 
action is defined under sequence records
                                        } 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 
!webaction.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[webaction.WEB_EXPORT_ANNOT] = true
-                                                       
pkg.Sequences[actionName] = a
+                                               // verify that the sequence 
action is defined as web sequence
+                                               // web or web-export set to any 
of [true, yes, raw]; if not,
+                                               // we will try to add it (if no 
strict" flag) and warn user that we did so
+                                               if err := 
webaction.TryUpdateAPIsActionToWebAction(sequencerecords, packageName,
+                                                       apiName, actionName, 
true); err!=nil {
+                                                       return requests, 
requestOptions, err
                                                }
-                                               // return failure since action 
or sequence are not defined in the manifest
                                        } else {
                                                return nil, nil, 
wskderrors.NewYAMLFileFormatError(manifestPath,
                                                        
wski18n.T(wski18n.ID_ERR_API_MISSING_ACTION_OR_SEQUENCE_X_action_or_sequence_X_api_X,
@@ -1275,7 +1262,7 @@ func (dm *YAMLParser) ComposeApiRecords(client 
*whisk.Config, packageName string
                                                gatewayMethodResponse.Response 
= utils.HTTP_FILE_EXTENSION
                                        }
 
-                                       // Chekc if API verb is valid, it must 
be one of (GET, PUT, POST, DELETE)
+                                       // Check if API verb is valid, it must 
be one of (GET, PUT, POST, DELETE)
                                        if _, ok := 
whisk.ApiVerbs[strings.ToUpper(gatewayMethodResponse.Method)]; !ok {
                                                return nil, nil, 
wskderrors.NewInvalidAPIGatewayMethodError(manifestPath,
                                                        
gatewayBasePath+gatewayRelPath,
diff --git a/parsers/manifest_parser_test.go b/parsers/manifest_parser_test.go
index 5fcb5ef..ea5ef55 100644
--- a/parsers/manifest_parser_test.go
+++ b/parsers/manifest_parser_test.go
@@ -1576,7 +1576,7 @@ func TestComposeApiRecords(t *testing.T) {
                ApigwAccessToken: "token",
        }
 
-       apiList, apiRequestOptions, err := 
p.ComposeApiRecordsFromAllPackages(&config, m)
+       apiList, apiRequestOptions, err := 
p.ComposeApiRecordsFromAllPackages(&config, m, nil, nil)
        if err != nil {
                assert.Fail(t, "Failed to compose api records: "+err.Error())
        }
diff --git a/specification/html/spec_sequences.md 
b/specification/html/spec_sequences.md
index 146ec83..0529d89 100644
--- a/specification/html/spec_sequences.md
+++ b/specification/html/spec_sequences.md
@@ -67,6 +67,12 @@ sequences:
   <sequence name>:
      <Entity schema>
      actions: <ordered list of action names>
+     web: <boolean> | yes | no | raw
+  annotations:
+    <map of annotation key-values>
+    web-export: <boolean> | yes | no | raw # optional
+    web-custom-options: <boolean> # optional, only valid when `web-export` 
enabled
+    require-whisk-auth: <boolean> | <string> | <positive integer> # optional, 
only valid when `web-export` enabled
   ...
 ```
 
@@ -75,6 +81,7 @@ sequences:
 sequences:
   newbot:
     actions: newbot-create, newbot-select-persona, newbot-greeting
+    web: true
 ```
 
 <!--
diff --git 
a/tests/src/integration/webaction/manifest_missing_web_annotation_on_api_action_or_sequence.yml
 
b/tests/src/integration/webaction/manifest_missing_web_annotation_on_api_action_or_sequence.yml
new file mode 100644
index 0000000..ebb7868
--- /dev/null
+++ 
b/tests/src/integration/webaction/manifest_missing_web_annotation_on_api_action_or_sequence.yml
@@ -0,0 +1,53 @@
+#
+# 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.
+#
+
+# TODO automate this testcase
+# Test automatically adding web annotations on Actions that do not have them 
declared
+# when these actions are used to create APIs.
+# 1) Test an Action missing web-export, but with existing Annotations declared
+# 2) Test a Sequence missing web-export with NO existing Annotations (to 
verify we allocate)
+# 3) Test if web-action is set to false that we error out as we cannot 
override explicit value
+packages:
+    TestMissingWebAnnotation:
+        actions:
+            hello_validate:
+                function: src/hello_http_validate.js
+            hello:
+                function: src/hello.js
+                annotations:
+                    foo: bar
+            hello_wrap:
+                function: src/hello_http_wrap.js
+            helloWebFalse:
+                function: src/hello.js
+                web: false
+        sequences:
+            hellosequence:
+                actions: hello_validate, hello, hello_wrap
+        apis:
+            actionmissingweb:
+                helloworlds:
+                    helloweb:
+                        hello:
+                            method: GET
+                            response: http
+                        hellosequence:
+                            method: GET
+                            response: http
+                        helloWebFalse:
+                            method: GET
+                            response: http
diff --git 
a/tests/src/integration/webaction/manifest_require_whisk_auth_sequence_valid.yaml
 
b/tests/src/integration/webaction/manifest_require_whisk_auth_sequence_valid.yaml
new file mode 100644
index 0000000..4a8b8df
--- /dev/null
+++ 
b/tests/src/integration/webaction/manifest_require_whisk_auth_sequence_valid.yaml
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+
+packages:
+  hellosequencespkg:
+    version: 1.0
+    license: Apache-2.0
+    actions:
+      hello_validate:
+        function: src/hello_http_validate.js
+      hello:
+        function: src/hello.js
+      hello_wrap:
+        function: src/hello_http_wrap.js
+    sequences:
+      hellosequence:
+        actions: hello_validate, hello, hello_wrap
+        web: true
+        annotations:
+          require-whisk-auth: "mytoken"
+    apis:
+      web-secure-sequences:
+        helloworlds:
+          hellosequence:
+            hellosequence:
+              method: GET
+              response: http
diff --git a/tests/src/integration/webaction/src/hello.js 
b/tests/src/integration/webaction/src/hello.js
new file mode 100644
index 0000000..d0ba584
--- /dev/null
+++ b/tests/src/integration/webaction/src/hello.js
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/*
+ * Hello, world
+ */
+function main(params) {
+    msg = "Hello, " + params.name + " from " + params.place;
+    return { greeting:  msg };
+}
diff --git a/tests/src/integration/webaction/src/hello_http_validate.js 
b/tests/src/integration/webaction/src/hello_http_validate.js
new file mode 100644
index 0000000..9f9c7be
--- /dev/null
+++ b/tests/src/integration/webaction/src/hello_http_validate.js
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/*
+ * This action validates the parameters passed to the hello world action and
+ * returns an error if any of them is missing.
+ */
+function main(params) {
+    if(params.name && params.place) {
+        return params;
+    } else {
+        return {
+            error: {
+                body: {
+                    message: 'Attributes name and place are mandatory'
+                },
+                statusCode: 400,
+                headers: {'Content-Type': 'application/json'}
+            }
+        }
+    }
+}
diff --git a/tests/src/integration/webaction/src/hello_http_wrap.js 
b/tests/src/integration/webaction/src/hello_http_wrap.js
new file mode 100644
index 0000000..ba786fe
--- /dev/null
+++ b/tests/src/integration/webaction/src/hello_http_wrap.js
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+/*
+ * This action take a result from the previous action and wraps it into a
+ * HTTP response structure.
+ */
+function main(params) {
+    return {
+        body: params,
+        statusCode: 200,
+        headers: {'Content-Type': 'application/json'}
+    };
+}
diff --git a/utils/misc.go b/utils/misc.go
index 65193fc..30fb601 100644
--- a/utils/misc.go
+++ b/utils/misc.go
@@ -187,3 +187,14 @@ func getKeyValueFormattedJSON(data map[string]interface{}) 
whisk.KeyValueArr {
        }
        return keyValueArr
 }
+
+func GetActionFromActionRecords( records []ActionRecord, packageName string, 
actionName string ) *whisk.Action {
+       for _, record := range records {
+               if record.Packagename == packageName {
+                       if record.Action.Name == actionName {
+                               return record.Action
+                       }
+               }
+       }
+       return nil
+}
diff --git a/webaction/webaction.go b/webaction/webaction.go
index b02b1b0..e69c073 100644
--- a/webaction/webaction.go
+++ b/webaction/webaction.go
@@ -82,9 +82,7 @@ func SetWebActionAnnotations(filePath string, action string, 
webMode string, ann
 
 type WebActionAnnotationMethod func(annotations whisk.KeyValueArr) 
whisk.KeyValueArr
 
-func webActionAnnotations(
-       fetchAnnotations bool,
-       annotations whisk.KeyValueArr,
+func webActionAnnotations( fetchAnnotations bool, annotations 
whisk.KeyValueArr,
        webActionAnnotationMethod WebActionAnnotationMethod) 
(whisk.KeyValueArr, error) {
 
                if annotations != nil || !fetchAnnotations {
@@ -147,14 +145,54 @@ func IsWebAction(webexport string) bool {
        return false
 }
 
-func IsWebSequence(webexport string) bool {
-       return IsWebAction(webexport)
-}
-
 func HasAnnotation(annotations *whisk.KeyValueArr, key string) bool {
        return (annotations.FindKeyValue(key) >= 0)
 }
 
+func warnWebAnnotationMissingFromActionOrSequence(apiName string, actionName 
string, isSequence bool){
+       nameKey := wski18n.KEY_ACTION
+       i18nWarningID := wski18n.ID_WARN_API_MISSING_WEB_ACTION_X_action_X_api_X
+
+       if isSequence {
+               nameKey = wski18n.KEY_SEQUENCE
+               i18nWarningID = 
wski18n.ID_WARN_API_MISSING_WEB_SEQUENCE_X_sequence_X_api_X
+       }
+
+       warningString := wski18n.T(i18nWarningID,
+               map[string]interface{}{
+                       nameKey: actionName,
+                       wski18n.KEY_API:      apiName})
+       wskprint.PrintOpenWhiskWarning(warningString)
+}
+
+func TryUpdateAPIsActionToWebAction(records []utils.ActionRecord, pkgName 
string, apiName string, actionName string, isSequence bool) error {
+
+       // if records are nil; it may be that the Action already exists at 
target provider OR
+       // this is a unit test.  If the former case, we pass through and allow 
provider to validate
+       // and return an error.
+       if records!=nil {
+               action := 
utils.GetActionFromActionRecords(records,pkgName,actionName)
+
+               if !HasAnnotation(&action.Annotations,WEB_EXPORT_ANNOT) {
+                       if !utils.Flags.Strict {
+                               
warnWebAnnotationMissingFromActionOrSequence(apiName,actionName,isSequence)
+                               action.Annotations = 
addWebAnnotations(action.Annotations)
+                               
wskprint.PrintOpenWhiskVerbose(utils.Flags.Verbose,
+                                       fmt.Sprintf("Web Annotations to Action; 
result: %v\n",action.Annotations))
+                       } else {
+                               return 
wskderrors.NewInvalidWebActionError(apiName,actionName,isSequence)
+                       }
+               } else {
+                       // verify its web-export annotation value is "true", 
else error
+                       if !action.WebAction() {
+                               return 
wskderrors.NewInvalidWebActionError(apiName,actionName,isSequence)
+                       }
+               }
+       }
+
+       return nil
+}
+
 func ValidateRequireWhiskAuthAnnotationValue(actionName string, value 
interface{}) (string, error) {
        var isValid = false
        var enabled = wski18n.FEATURE_DISABLED
diff --git a/wskderrors/wskdeployerror.go b/wskderrors/wskdeployerror.go
index de06d99..70e0bcd 100644
--- a/wskderrors/wskdeployerror.go
+++ b/wskderrors/wskdeployerror.go
@@ -19,6 +19,8 @@ package wskderrors
 
 import (
        "fmt"
+       "github.com/apache/openwhisk-wskdeploy/wski18n"
+       "github.com/apache/openwhisk-wskdeploy/wskprint"
        "io/ioutil"
        "net/http"
        "path/filepath"
@@ -63,6 +65,7 @@ const (
        ERROR_YAML_INVALID_PARAMETER_TYPE     = 
"ERROR_YAML_INVALID_PARAMETER_TYPE"
        ERROR_YAML_INVALID_RUNTIME            = "ERROR_YAML_INVALID_RUNTIME"
        ERROR_YAML_INVALID_WEB_EXPORT         = "ERROR_YAML_INVALID_WEB_EXPORT"
+       ERROR_YAML_INVALID_API                = "ERROR_YAML_INVALID_API"
        ERROR_YAML_INVALID_API_GATEWAY_METHOD = 
"ERROR_YAML_INVALID_API_GATEWAY_METHOD"
        ERROR_RUNTIME_PARSER_FAILURE          = "ERROR_RUNTIME_PARSER_FAILURE"
        ERROR_ACTION_ANNOTATION               = "ERROR_ACTION_ANNOTATION"
@@ -446,6 +449,35 @@ func NewInvalidAPIGatewayMethodError(fpath string, api 
string, method string, su
 }
 
 /*
+ * Invalid Web Action API
+ */
+type InvalidWebActionAPIError struct {
+       WskDeployBaseErr
+}
+
+func NewInvalidWebActionError(apiName string, actionName string, isSequence 
bool) *InvalidWebActionAPIError {
+       var err = &InvalidWebActionAPIError{
+       }
+
+       i18nErrorID := wski18n.ID_ERR_API_MISSING_WEB_ACTION_X_action_X_api_X
+
+       if isSequence {
+               i18nErrorID = 
wski18n.ID_ERR_API_MISSING_WEB_SEQUENCE_X_sequence_X_api_X
+       }
+
+       errString := wski18n.T(i18nErrorID,
+               map[string]interface{}{
+                       wski18n.KEY_SEQUENCE: actionName,
+                       wski18n.KEY_API:      apiName})
+       wskprint.PrintOpenWhiskWarning(errString)
+
+       err.SetErrorType(ERROR_YAML_INVALID_API)
+       err.SetCallerByStackFrameSkip(2)
+       err.SetMessage(errString)
+       return err
+}
+
+/*
  * Failed to Retrieve/Parse Runtime
  */
 type RuntimeParserError struct {
diff --git a/wski18n/i18n_ids.go b/wski18n/i18n_ids.go
index 9fda5f7..09ac1f3 100644
--- a/wski18n/i18n_ids.go
+++ b/wski18n/i18n_ids.go
@@ -217,6 +217,8 @@ const (
        ID_ERR_INVALID_PARAM_FILE_X_file_X                                   = 
"msg_err_invalid_param_file"
        ID_ERR_REQUIRED_INPUTS_MISSING_VALUE_X_inputs_X                      = 
"msg_err_required_inputs_missing_value"
        ID_ERR_API_GATEWAY_BASE_PATH_INVALID_X_api_X                         = 
"msg_err_api_gateway_base_path_invalid"
+       ID_ERR_API_MISSING_WEB_ACTION_X_action_X_api_X                          
         = "msg_err_api_missing_web_action"
+       ID_ERR_API_MISSING_WEB_SEQUENCE_X_sequence_X_api_X                      
         = "msg_err_api_missing_web_sequence"
        ID_ERR_RUNTIME_PARSER_ERROR                                          = 
"msg_err_runtime_parser_error"
        ID_ERR_WEB_ACTION_REQUIRE_AUTH_TOKEN_INVALID_X_action_X_key_X_value  = 
"msg_err_web_action_require_auth_token_invalid"
 
@@ -296,6 +298,9 @@ var I18N_ID_SET = [](string){
        ID_DEBUG_PACKAGES_FOUND_UNDER_PROJECT_X_path_X_name_X,
        ID_DEBUG_PACKAGES_FOUND_UNDER_ROOT_X_path_X,
        ID_DEBUG_PROJECT_SEARCH_X_path_X_key_X,
+       ID_ERR_API_GATEWAY_BASE_PATH_INVALID_X_api_X,
+       ID_ERR_API_MISSING_WEB_ACTION_X_action_X_api_X,
+       ID_ERR_API_MISSING_WEB_SEQUENCE_X_sequence_X_api_X,
        ID_ERR_CANT_SAVE_DOCKER_RUNTIME,
        ID_ERR_DEPENDENCY_UNKNOWN_TYPE,
        ID_ERR_ENTITY_CREATE_X_key_X_err_X_code_X,
diff --git a/wski18n/i18n_resources.go b/wski18n/i18n_resources.go
index aae595c..d26c1e5 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\xcc\x3c\x6b\x6f\x1b\x39\x92\xdf\xe7\x57\x14\x06\x0b\x64\x16\x90\xe5\xec\xe2\x70\x58\xf8\x2e\x07\x78\x13\x67\xc7\x3b\xc9\x38\xe7\xc7\x0e\xe6\x12\xa3\x43\x75\x97\x24\xae\xbb\xc9\x5e\x92\x2d\x45\x63\xe8\xbf\x1f\xaa\x48\x76\xb7\x64\xf5\x43\x4e\x06\x77\xf9\x12\x49\x24\xeb\xc5\x62\xb1\x5e\xf4\xc7\xef\x00\x1e\xbf\x03\x00\xf8\x5e\x66\xdf\x9f\xc1\xf7\x85\x5d\x24\xa5\xc1\xb9\xfc\x92\xa0\x31\xda\x7c\x3f\xf1\xa3\xce
 [...]
+var _wski18nResourcesEn_usAllJson = 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x7c\x7b\x8f\x1b\x37\x92\xf8\xff\xf9\x14\x85\x60\x01\x27\x80\x46\xf6\x2e\x7e\xf8\x61\x31\x77\x3e\x60\xd6\x1e\x27\xb3\xb1\x33\xbe\x79\x24\xc8\xd9\x83\x36\xd5\x5d\x92\xb8\xd3\x4d\xf6\x92\x6c\xc9\xca\x40\xdf\xfd\x50\x45\xb2\xbb\xa5\x51\x3f\x34\x76\x70\xf1\x3f\xd6\x88\x64\xbd\x58\x2c\xd6\x8b\xfa\xf0\x0d\xc0\xc3\x37\x00\x00\xdf\xca\xec\xdb\x53\xf8\xb6\xb0\x8b\xa4\x34\x38\x97\x9f\x13\x34\x46\x9b\x6f\x27\x7e
 [...]
 
 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: 
21565, mode: os.FileMode(420), modTime: time.Unix(1579715078, 0)}
+       info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 
21925, mode: os.FileMode(420), modTime: time.Unix(1580408211, 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 bc0aba4..27dab3a 100644
--- a/wski18n/resources/en_US.all.json
+++ b/wski18n/resources/en_US.all.json
@@ -388,6 +388,14 @@
     "translation": "API Gateway base path [{{.apibasepath}}] is invalid. It 
has path parameters which is not supported, only relative path supports path 
parameters."
   },
   {
+    "id": "msg_err_api_missing_web_action",
+    "translation": "Action [{{.action}}] is not a web action, API [{{.api}}] 
can only be created using a web action.\n"
+  },
+  {
+    "id": "msg_err_api_missing_web_sequence",
+    "translation": "Sequence [{{.sequence}}] is not a web sequence, API 
[{{.api}}] can only be created using a web sequence.\n"
+  },
+  {
     "id": "msg_err_runtime_parser_error",
     "translation": "Failed to retrieve runtimes {{.err}}."
   },
@@ -481,11 +489,11 @@
   },
   {
     "id": "msg_warn_api_missing_web_action",
-    "translation": "Action [{{.action}}] is not a web action, API [{{.api}}] 
can only be created using web action. Converting [{{.action}}] to a web 
action.\n"
+    "translation": "Action [{{.action}}] is not a web action, API [{{.api}}] 
can only be created using a 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"
+    "translation": "Sequence [{{.sequence}}] is not a web sequence, API 
[{{.api}}] can only be created using a web sequence. Converting [{{.sequence}}] 
to a web sequence.\n"
   },
   {
     "id": "msg_warn_api_invalid_response_type",

Reply via email to