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/02/09 20:11:22 UTC
[GitHub] mrutkows closed pull request #717: API Gateway deployment/undeployment
mrutkows closed pull request #717: API Gateway deployment/undeployment
URL: https://github.com/apache/incubator-openwhisk-wskdeploy/pull/717
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/Godeps/Godeps.json b/Godeps/Godeps.json
index 4576bf6b..1758c5d9 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -105,11 +105,11 @@
},
{
"ImportPath": "github.com/apache/incubator-openwhisk-client-go/whisk",
- "Rev": "cef179c81f07f86413c720623995c17bd1bddd7d"
+ "Rev": "d7cab4297a25e2cc25492b85b64e7ec000da9ffb"
},
{
"ImportPath": "github.com/apache/incubator-openwhisk-client-go/wski18n",
- "Rev": "cef179c81f07f86413c720623995c17bd1bddd7d"
+ "Rev": "d7cab4297a25e2cc25492b85b64e7ec000da9ffb"
},
{
"ImportPath": "github.com/pelletier/go-buffruneio",
diff --git a/deployers/manifestreader.go b/deployers/manifestreader.go
index 06fbdcea..0442abc4 100644
--- a/deployers/manifestreader.go
+++ b/deployers/manifestreader.go
@@ -93,7 +93,7 @@ func (deployer *ManifestReader) HandleYaml(sdeployer *ServiceDeployer, manifestP
return wskderrors.NewYAMLFileFormatError(manifestName, err)
}
- apis, err := manifestParser.ComposeApiRecordsFromAllPackages(manifest)
+ apis, err := manifestParser.ComposeApiRecordsFromAllPackages(deployer.serviceDeployer.ClientConfig, manifest)
if err != nil {
return wskderrors.NewYAMLFileFormatError(manifestName, err)
}
@@ -373,17 +373,16 @@ func (reader *ManifestReader) SetRules(rules []*whisk.Rule) error {
func (reader *ManifestReader) SetApis(ar []*whisk.ApiCreateRequest) error {
dep := reader.serviceDeployer
- var apis []*whisk.ApiCreateRequest = make([]*whisk.ApiCreateRequest, 0)
dep.mt.Lock()
defer dep.mt.Unlock()
- for _, api := range apis {
- existApi, exist := dep.Deployment.Apis[api.ApiDoc.ApiName]
+ for _, api := range ar {
+ existApi, exist := dep.Deployment.Apis[api.ApiDoc.Action.Name]
if exist {
existApi.ApiDoc.ApiName = api.ApiDoc.ApiName
} else {
- dep.Deployment.Apis[api.ApiDoc.ApiName] = api
+ dep.Deployment.Apis[api.ApiDoc.Action.Name] = api
}
}
diff --git a/deployers/servicedeployer.go b/deployers/servicedeployer.go
index 8861619b..14fc1c8b 100644
--- a/deployers/servicedeployer.go
+++ b/deployers/servicedeployer.go
@@ -927,14 +927,20 @@ func (deployer *ServiceDeployer) createAction(pkgname string, action *whisk.Acti
// create api (API Gateway functionality)
func (deployer *ServiceDeployer) createApi(api *whisk.ApiCreateRequest) error {
- displayPreprocessingInfo(parsers.YAML_KEY_API, api.ApiDoc.ApiName, true)
+ apiPath := api.ApiDoc.ApiName + " " + api.ApiDoc.GatewayBasePath +
+ api.ApiDoc.GatewayRelPath + " " + api.ApiDoc.GatewayMethod
+ displayPreprocessingInfo(parsers.YAML_KEY_API, apiPath, true)
var err error
var response *http.Response
- // TODO() Is there an api delete function? could not find it
+ apiCreateReqOptions := new(whisk.ApiCreateRequestOptions)
+ apiCreateReqOptions.SpaceGuid = strings.Split(deployer.Client.Config.AuthToken, ":")[0]
+ apiCreateReqOptions.AccessToken = deployer.Client.Config.ApigwAccessToken
+ // TODO() Add Response type apiCreateReqOptions.ResponseType
+
err = retry(DEFAULT_ATTEMPTS, DEFAULT_INTERVAL, func() error {
- _, response, err = deployer.Client.Apis.Insert(api, nil, true)
+ _, response, err = deployer.Client.Apis.Insert(api, apiCreateReqOptions, true)
return err
})
@@ -942,7 +948,7 @@ func (deployer *ServiceDeployer) createApi(api *whisk.ApiCreateRequest) error {
return createWhiskClientError(err.(*whisk.WskError), response, parsers.YAML_KEY_API, true)
}
- displayPostprocessingInfo(parsers.YAML_KEY_API, api.ApiDoc.ApiName, true)
+ displayPostprocessingInfo(parsers.YAML_KEY_API, apiPath, true)
return nil
}
@@ -990,6 +996,9 @@ func (deployer *ServiceDeployer) UnDeploy(verifiedPlan *DeploymentProject) error
}
func (deployer *ServiceDeployer) unDeployAssets(verifiedPlan *DeploymentProject) error {
+ if err := deployer.UnDeployApis(verifiedPlan); err != nil {
+ return err
+ }
if err := deployer.UnDeployRules(verifiedPlan); err != nil {
return err
@@ -1147,6 +1156,17 @@ func (deployer *ServiceDeployer) UnDeployRules(deployment *DeploymentProject) er
return nil
}
+func (deployer *ServiceDeployer) UnDeployApis(deployment *DeploymentProject) error {
+
+ for _, api := range deployment.Apis {
+ err := deployer.deleteApi(api)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
func (deployer *ServiceDeployer) deletePackage(packa *whisk.Package) error {
displayPreprocessingInfo(parsers.YAML_KEY_PACKAGE, packa.Name, false)
@@ -1255,6 +1275,58 @@ func (deployer *ServiceDeployer) deleteRule(rule *whisk.Rule) error {
return nil
}
+func (deployer *ServiceDeployer) isApi(api *whisk.ApiCreateRequest) bool {
+ apiReqOptions := new(whisk.ApiGetRequestOptions)
+ apiReqOptions.AccessToken = deployer.Client.Config.ApigwAccessToken
+ apiReqOptions.ApiBasePath = api.ApiDoc.GatewayBasePath
+ apiReqOptions.SpaceGuid = strings.Split(deployer.Client.Config.AuthToken, ":")[0]
+
+ a := new(whisk.ApiGetRequest)
+
+ retApi, _, err := deployer.Client.Apis.Get(a, apiReqOptions)
+ if err == nil {
+ if retApi.Apis != nil && len(retApi.Apis) > 0 &&
+ retApi.Apis[0].ApiValue != nil {
+ return true
+ }
+
+ }
+ return false
+}
+
+// delete api (API Gateway functionality)
+func (deployer *ServiceDeployer) deleteApi(api *whisk.ApiCreateRequest) error {
+
+ apiPath := api.ApiDoc.ApiName + " " + api.ApiDoc.GatewayBasePath +
+ api.ApiDoc.GatewayRelPath + " " + api.ApiDoc.GatewayMethod
+ displayPreprocessingInfo(parsers.YAML_KEY_API, apiPath, false)
+
+ if deployer.isApi(api) {
+ var err error
+ var response *http.Response
+
+ apiDeleteReqOptions := new(whisk.ApiDeleteRequestOptions)
+ apiDeleteReqOptions.AccessToken = deployer.Client.Config.ApigwAccessToken
+ apiDeleteReqOptions.SpaceGuid = strings.Split(deployer.Client.Config.AuthToken, ":")[0]
+ apiDeleteReqOptions.ApiBasePath = api.ApiDoc.GatewayBasePath
+ apiDeleteReqOptions.ApiRelPath = api.ApiDoc.GatewayRelPath
+ apiDeleteReqOptions.ApiVerb = api.ApiDoc.GatewayMethod
+
+ a := new(whisk.ApiDeleteRequest)
+
+ err = retry(DEFAULT_ATTEMPTS, DEFAULT_INTERVAL, func() error {
+ response, err = deployer.Client.Apis.Delete(a, apiDeleteReqOptions)
+ return err
+ })
+
+ if err != nil {
+ return createWhiskClientError(err.(*whisk.WskError), response, parsers.YAML_KEY_API, false)
+ }
+ }
+ displayPostprocessingInfo(parsers.YAML_KEY_API, apiPath, false)
+ return nil
+}
+
// Utility function to call go-whisk framework to make action
func (deployer *ServiceDeployer) deleteAction(pkgname string, action *whisk.Action) error {
// call ActionService through Client
diff --git a/deployers/whiskclient.go b/deployers/whiskclient.go
index 83d2380e..4935b810 100644
--- a/deployers/whiskclient.go
+++ b/deployers/whiskclient.go
@@ -42,6 +42,15 @@ const (
SOURCE_DEFAULT_VALUE = "wskdeploy default" // TODO() i18n?
)
+var (
+ credential = PropertyValue{}
+ namespace = PropertyValue{}
+ apiHost = PropertyValue{}
+ key = PropertyValue{}
+ cert = PropertyValue{}
+ apigwAccessToken = PropertyValue{}
+)
+
type PropertyValue struct {
Value string
Source string
@@ -63,8 +72,8 @@ var GetWskPropFromWhiskProperty = func(pi whisk.Properties) (*whisk.Wskprops, er
return whisk.GetWskPropFromWhiskProperty(pi)
}
-var GetCommandLineFlags = func() (string, string, string, string, string) {
- return utils.Flags.ApiHost, utils.Flags.Auth, utils.Flags.Namespace, utils.Flags.Key, utils.Flags.Cert
+var GetCommandLineFlags = func() (string, string, string, string, string, string) {
+ return utils.Flags.ApiHost, utils.Flags.Auth, utils.Flags.Namespace, utils.Flags.Key, utils.Flags.Cert, utils.Flags.ApigwAccessToken
}
var CreateNewClient = func(config_input *whisk.Config) (*whisk.Client, error) {
@@ -74,106 +83,80 @@ var CreateNewClient = func(config_input *whisk.Config) (*whisk.Client, error) {
return whisk.NewClient(netClient, config_input)
}
-// we are reading openwhisk credentials (apihost, namespace, and auth) in the following precedence order:
-// (1) wskdeploy command line `wskdeploy --apihost --namespace --auth`
-// (2) deployment file
-// (3) manifest file
-// (4) .wskprops
-// (5) prompt for values in interactive mode if any of them are missing
-func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string, isInteractive bool) (*whisk.Config, error) {
- // struct to store credential, namespace, and host with their respective source
- credential := PropertyValue{}
- namespace := PropertyValue{}
- apiHost := PropertyValue{}
- key := PropertyValue{}
- cert := PropertyValue{}
-
- // read credentials from command line
- apihost, auth, ns, keyfile, certfile := GetCommandLineFlags()
+func resetWhiskConfig() {
+ credential = PropertyValue{}
+ namespace = PropertyValue{}
+ apiHost = PropertyValue{}
+ key = PropertyValue{}
+ cert = PropertyValue{}
+ apigwAccessToken = PropertyValue{}
+}
+
+func readFromCLI() {
+ // read credentials, namespace, API host, key file, cert file, and APIGW access token from command line
+ apihost, auth, ns, keyfile, certfile, accessToken := GetCommandLineFlags()
credential = GetPropertyValue(credential, auth, wski18n.COMMAND_LINE)
namespace = GetPropertyValue(namespace, ns, wski18n.COMMAND_LINE)
apiHost = GetPropertyValue(apiHost, apihost, wski18n.COMMAND_LINE)
key = GetPropertyValue(key, keyfile, wski18n.COMMAND_LINE)
cert = GetPropertyValue(cert, certfile, wski18n.COMMAND_LINE)
+ apigwAccessToken = GetPropertyValue(apigwAccessToken, accessToken, wski18n.COMMAND_LINE)
+}
- // TODO() i18n
- // Print all flags / values if verbose
- wskprint.PrintlnOpenWhiskVerbose(utils.Flags.Verbose, wski18n.CONFIGURATION+":\n"+utils.Flags.Format())
+func setWhiskConfig(cred string, ns string, host string, token string, source string) {
+ credential = GetPropertyValue(credential, cred, source)
+ namespace = GetPropertyValue(namespace, ns, source)
+ apiHost = GetPropertyValue(apiHost, host, source)
+ apigwAccessToken = GetPropertyValue(apigwAccessToken, token, source)
+}
- // TODO() split this logic into its own function
- // TODO() merge with the same logic used against manifest file (below)
- // now, read them from deployment file if not found on command line
+func readFromDeploymentFile(deploymentPath string) {
if len(credential.Value) == 0 || len(namespace.Value) == 0 || len(apiHost.Value) == 0 {
if utils.FileExists(deploymentPath) {
mm := parsers.NewYAMLParser()
deployment, _ := mm.ParseDeployment(deploymentPath)
- credential = GetPropertyValue(credential,
- deployment.GetProject().Credential,
- path.Base(deploymentPath))
- namespace = GetPropertyValue(namespace,
- deployment.GetProject().Namespace,
- path.Base(deploymentPath))
- apiHost = GetPropertyValue(apiHost,
- deployment.GetProject().ApiHost,
- path.Base(deploymentPath))
+ p := deployment.GetProject()
+ setWhiskConfig(p.Credential, p.Namespace, p.ApiHost, p.ApigwAccessToken, path.Base(deploymentPath))
}
}
+}
- // TODO() split this logic into its own function
- // TODO() merge with the same logic used against deployment file (above)
- // read credentials from manifest file as didn't find them on command line and in deployment file
+func readFromManifestFile(manifestPath string) {
if len(credential.Value) == 0 || len(namespace.Value) == 0 || len(apiHost.Value) == 0 {
if utils.FileExists(manifestPath) {
mm := parsers.NewYAMLParser()
manifest, _ := mm.ParseManifest(manifestPath)
+ var p = parsers.Package{}
if manifest.Package.Packagename != "" {
- credential = GetPropertyValue(credential,
- manifest.Package.Credential,
- path.Base(manifestPath))
- namespace = GetPropertyValue(namespace,
- manifest.Package.Namespace,
- path.Base(manifestPath))
- apiHost = GetPropertyValue(apiHost,
- manifest.Package.ApiHost,
- path.Base(manifestPath))
+ p = manifest.Package
} else if manifest.Packages != nil {
if len(manifest.Packages) == 1 {
for _, pkg := range manifest.Packages {
- credential = GetPropertyValue(credential,
- pkg.Credential,
- path.Base(manifestPath))
- namespace = GetPropertyValue(namespace,
- pkg.Namespace,
- path.Base(manifestPath))
- apiHost = GetPropertyValue(apiHost,
- pkg.ApiHost,
- path.Base(manifestPath))
+ p = pkg
}
}
}
+ setWhiskConfig(p.Credential, p.Namespace, p.ApiHost, p.ApigwAccessToken, path.Base(manifestPath))
}
}
+}
- // Third, we need to look up the variables in .wskprops file.
- pi := whisk.PropertiesImp{
- OsPackage: whisk.OSPackageImp{},
- }
-
- // The error raised here can be neglected, because we will handle it in the end of this function.
+func readFromWskprops(pi whisk.PropertiesImp, proppath string) {
+ // The error raised here can be neglected, because we will handle it in the end of its calling function.
wskprops, _ := GetWskPropFromWskprops(pi, proppath)
credential = GetPropertyValue(credential, wskprops.AuthKey, SOURCE_WSKPROPS)
namespace = GetPropertyValue(namespace, wskprops.Namespace, SOURCE_WSKPROPS)
apiHost = GetPropertyValue(apiHost, wskprops.APIHost, SOURCE_WSKPROPS)
key = GetPropertyValue(key, wskprops.Key, SOURCE_WSKPROPS)
cert = GetPropertyValue(cert, wskprops.Cert, SOURCE_WSKPROPS)
+ apigwAccessToken = GetPropertyValue(apigwAccessToken, wskprops.AuthAPIGWKey, SOURCE_WSKPROPS)
+}
- // TODO() see if we can split the following whisk prop logic into a separate function
+func readFromWhiskProperty(pi whisk.PropertiesImp) {
// now, read credentials from whisk.properties but this is only acceptable within Travis
// whisk.properties will soon be deprecated and should not be used for any production deployment
whiskproperty, _ := GetWskPropFromWhiskProperty(pi)
-
var warnMsg string
-
credential = GetPropertyValue(credential, whiskproperty.AuthKey, SOURCE_WHISK_PROPERTIES)
if credential.Source == SOURCE_WHISK_PROPERTIES {
warnMsg = wski18n.T(wski18n.ID_WARN_WHISK_PROPS_DEPRECATED,
@@ -192,29 +175,26 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
map[string]interface{}{wski18n.KEY_KEY: wski18n.API_HOST})
wskprint.PrintlnOpenWhiskWarning(warnMsg)
}
-
- // set namespace to default namespace if not yet found
- if len(apiHost.Value) != 0 && len(credential.Value) != 0 && len(namespace.Value) == 0 {
- namespace.Value = whisk.DEFAULT_NAMESPACE
- namespace.Source = SOURCE_DEFAULT_VALUE
+ apigwAccessToken = GetPropertyValue(apigwAccessToken, whiskproperty.AuthAPIGWKey, SOURCE_WHISK_PROPERTIES)
+ if apigwAccessToken.Source == SOURCE_WHISK_PROPERTIES {
+ warnMsg = wski18n.T(wski18n.ID_WARN_WHISK_PROPS_DEPRECATED,
+ map[string]interface{}{wski18n.KEY_KEY: wski18n.APIGW_ACCESS_TOKEN})
+ wskprint.PrintlnOpenWhiskWarning(warnMsg)
}
+}
- // TODO() See if we can split off the interactive logic into a separate function
- // If we still can not find the values we need, check if it is interactive mode.
- // If so, we prompt users for the input.
- // The namespace is set to a default value at this point if not provided.
- if len(apiHost.Value) == 0 && isInteractive == true {
+func readInteractivly() {
+ if len(apiHost.Value) == 0 {
host := promptForValue(wski18n.T(wski18n.ID_MSG_PROMPT_APIHOST))
if host == "" {
// TODO() programmatically tell caller that we are using this default
// TODO() make this configurable or remove
host = "openwhisk.ng.bluemix.net"
}
- apiHost.Value = host
- apiHost.Source = SOURCE_INTERACTIVE_INPUT
+ apiHost = GetPropertyValue(apiHost, host, SOURCE_INTERACTIVE_INPUT)
}
- if len(credential.Value) == 0 && isInteractive == true {
+ if len(credential.Value) == 0 {
cred := promptForValue(wski18n.T(wski18n.ID_MSG_PROMPT_AUTHKEY))
credential.Value = cred
credential.Source = SOURCE_INTERACTIVE_INPUT
@@ -230,24 +210,83 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
source = SOURCE_DEFAULT_VALUE
}
- namespace.Value = tempNamespace
- namespace.Source = source
+ namespace = GetPropertyValue(namespace, tempNamespace, source)
}
}
+ if len(apigwAccessToken.Value) == 0 {
+ accessToken := promptForValue(wski18n.T(wski18n.APIGW_ACCESS_TOKEN))
+ apigwAccessToken = GetPropertyValue(apigwAccessToken, accessToken, SOURCE_INTERACTIVE_INPUT)
+ }
+}
+
+// we are reading openwhisk credentials (apihost, namespace, and auth) in the following precedence order:
+// (1) wskdeploy command line `wskdeploy --apihost --namespace --auth`
+// (2) deployment file
+// (3) manifest file
+// (4) .wskprops
+// (5) prompt for values in interactive mode if any of them are missing
+// we are following the same precedence order for APIGW_ACCESS_TOKEN
+// but as a separate thread as APIGW_ACCESS_TOKEN only needed for APIs
+func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string, isInteractive bool) (*whisk.Config, error) {
+ // reset credential, apiHost, namespace, etc to avoid any conflicts as they initialized globally
+ resetWhiskConfig()
+
+ // initialize APIGW_ACCESS_TOKEN to "DUMMY TOKEN" for Travis builds
+ if strings.ToLower(os.Getenv("TRAVIS")) == "true" {
+ apigwAccessToken.Value = "DUMMY TOKEN"
+ apigwAccessToken.Source = SOURCE_DEFAULT_VALUE
+ }
+
+ // read from command line
+ readFromCLI()
+
+ // TODO() i18n
+ // Print all flags / values if verbose
+ wskprint.PrintlnOpenWhiskVerbose(utils.Flags.Verbose, wski18n.CONFIGURATION+":\n"+utils.Flags.Format())
+
+ // now, read them from deployment file if not found on command line
+ readFromDeploymentFile(deploymentPath)
+
+ // read credentials from manifest file as didn't find them on command line and in deployment file
+ readFromManifestFile(manifestPath)
+
+ // Third, we need to look up the variables in .wskprops file.
+ pi := whisk.PropertiesImp{
+ OsPackage: whisk.OSPackageImp{},
+ }
+
+ readFromWskprops(pi, proppath)
+
+ readFromWhiskProperty(pi)
+
+ // set namespace to default namespace if not yet found
+ if len(apiHost.Value) != 0 && len(credential.Value) != 0 && len(namespace.Value) == 0 {
+ namespace.Value = whisk.DEFAULT_NAMESPACE
+ namespace.Source = SOURCE_DEFAULT_VALUE
+ }
+
+ // If we still can not find the values we need, check if it is interactive mode.
+ // If so, we prompt users for the input.
+ // The namespace is set to a default value at this point if not provided.
+ if isInteractive {
+ readInteractivly()
+ }
+
mode := true
if len(cert.Value) != 0 && len(key.Value) != 0 {
mode = false
}
clientConfig = &whisk.Config{
- AuthToken: credential.Value, //Authtoken
- Namespace: namespace.Value, //Namespace
- Host: apiHost.Value,
- Version: "v1", // TODO() should not be hardcoded, should prompt/warn user of default
- Cert: cert.Value,
- Key: key.Value,
- Insecure: mode, // true if you want to ignore certificate signing
+ AuthToken: credential.Value, //Authtoken
+ Namespace: namespace.Value, //Namespace
+ Host: apiHost.Value,
+ Version: "v1", // TODO() should not be hardcoded, should prompt/warn user of default
+ Cert: cert.Value,
+ Key: key.Value,
+ Insecure: mode, // true if you want to ignore certificate signing
+ ApigwAccessToken: apigwAccessToken.Value,
}
// validate we have credential, apihost and namespace
@@ -288,6 +327,12 @@ func validateClientConfig(credential PropertyValue, apiHost PropertyValue, names
map[string]interface{}{wski18n.KEY_NAMESPACE: namespace.Value, wski18n.KEY_SOURCE: namespace.Source})
wskprint.PrintOpenWhiskInfo(stdout)
+ if len(apigwAccessToken.Value) != 0 {
+ stdout = wski18n.T(wski18n.ID_MSG_CONFIG_INFO_APIGE_ACCESS_TOKEN_X_source_X,
+ map[string]interface{}{wski18n.KEY_SOURCE: apigwAccessToken.Source})
+ wskprint.PrintOpenWhiskInfo(stdout)
+ }
+
return nil
}
diff --git a/parsers/manifest_parser.go b/parsers/manifest_parser.go
index c5eb0c80..87d76b3b 100644
--- a/parsers/manifest_parser.go
+++ b/parsers/manifest_parser.go
@@ -35,6 +35,15 @@ import (
"github.com/apache/incubator-openwhisk-wskdeploy/wskprint"
)
+const (
+ PATH_SEPERATOR = "/"
+ API = "API"
+ HTTPS = "https"
+ HTTP = "http"
+ API_VERSION = "v1"
+ WEB = "web"
+)
+
// Read existing manifest file or create new if none exists
func ReadOrCreateManifest() (*YAML, error) {
maniyaml := YAML{}
@@ -858,12 +867,18 @@ func (dm *YAMLParser) ComposeRules(pkg Package, packageName string) ([]*whisk.Ru
return r1, nil
}
-func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(manifest *YAML) ([]*whisk.ApiCreateRequest, error) {
+func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(client *whisk.Config, manifest *YAML) ([]*whisk.ApiCreateRequest, error) {
var requests []*whisk.ApiCreateRequest = make([]*whisk.ApiCreateRequest, 0)
manifestPackages := make(map[string]Package)
+ // verify APIGW_ACCESS_TOKEN is set before composing APIs
+ // until this point, we dont know whether APIs are specified in manifest or not
+ if len(client.ApigwAccessToken) == 0 {
+ return nil, wskderrors.NewWhiskClientInvalidConfigError(wski18n.ID_MSG_CONFIG_MISSING_APIGW_ACCESS_TOKEN)
+ }
+
if manifest.Package.Packagename != "" {
- return dm.ComposeApiRecords(manifest.Package)
+ return dm.ComposeApiRecords(client, manifest.Package.Packagename, manifest.Package, manifest.Filepath)
} else {
if len(manifest.Packages) != 0 {
manifestPackages = manifest.Packages
@@ -872,8 +887,8 @@ func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(manifest *YAML) ([]*whisk
}
}
- for _, p := range manifestPackages {
- r, err := dm.ComposeApiRecords(p)
+ for packageName, p := range manifestPackages {
+ r, err := dm.ComposeApiRecords(client, packageName, p, manifest.Filepath)
if err == nil {
requests = append(requests, r...)
} else {
@@ -883,14 +898,102 @@ func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(manifest *YAML) ([]*whisk
return requests, nil
}
-func (dm *YAMLParser) ComposeApiRecords(pkg Package) ([]*whisk.ApiCreateRequest, error) {
- var acq []*whisk.ApiCreateRequest = make([]*whisk.ApiCreateRequest, 0)
- apis := pkg.GetApis()
+/*
+ * read API section from manifest file:
+ * apis: # List of APIs
+ * hello-world: #API name
+ * /hello: #gateway base path
+ * /world: #gateway rel path
+ * greeting: get #action name: gateway method
+ *
+ * compose APIDoc structure from the manifest:
+ * {
+ * "apidoc":{
+ * "namespace":<namespace>,
+ * "gatewayBasePath":"/hello",
+ * "gatewayPath":"/world",
+ * "gatewayMethod":"GET",
+ * "action":{
+ * "name":"hello",
+ * "namespace":"guest",
+ * "backendMethod":"GET",
+ * "backendUrl":<url>,
+ * "authkey":<auth>
+ * }
+ * }
+ * }
+ */
+func (dm *YAMLParser) ComposeApiRecords(client *whisk.Config, packageName string, pkg Package, manifestPath string) ([]*whisk.ApiCreateRequest, error) {
+ var requests []*whisk.ApiCreateRequest = make([]*whisk.ApiCreateRequest, 0)
+
+ for apiName, apiDoc := range pkg.Apis {
+ for gatewayBasePath, gatewayBasePathMap := range apiDoc {
+ // append "/" to the gateway base path if its missing
+ if !strings.HasPrefix(gatewayBasePath, PATH_SEPERATOR) {
+ gatewayBasePath = PATH_SEPERATOR + gatewayBasePath
+ }
+ for gatewayRelPath, gatewayRelPathMap := range gatewayBasePathMap {
+ // append "/" to the gateway relative path if its missing
+ if !strings.HasPrefix(gatewayRelPath, PATH_SEPERATOR) {
+ gatewayRelPath = PATH_SEPERATOR + gatewayRelPath
+ }
+ 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 {
+ // verify that the action is defined as web action
+ // web-export set to any of [true, yes, raw]
+ if !utils.IsWebAction(pkg.Actions[actionName].Webexport) {
+ return nil, wskderrors.NewYAMLFileFormatError(manifestPath,
+ wski18n.T(wski18n.ID_ERR_API_MISSING_WEB_ACTION_X_action_X_api_X,
+ map[string]interface{}{
+ wski18n.KEY_ACTION: actionName,
+ wski18n.KEY_API: apiName}))
+ } else {
+ 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)
+ request.ApiDoc.Action.Name = packageName + PATH_SEPERATOR + actionName
+ request.ApiDoc.Action.Namespace = client.Namespace
+ url := []string{HTTPS + ":" + PATH_SEPERATOR, client.Host, strings.ToLower(API),
+ API_VERSION, WEB, client.Namespace, packageName, actionName + "." + HTTP}
+ request.ApiDoc.Action.BackendUrl = strings.Join(url, PATH_SEPERATOR)
+ 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 requests, nil
+}
- for _, api := range apis {
- acr := new(whisk.ApiCreateRequest)
- acr.ApiDoc = api
- acq = append(acq, acr)
+func (dm *YAMLParser) getGatewayMethods() []string {
+ methods := []string{}
+ for k := range whisk.ApiVerbs {
+ methods = append(methods, k)
}
- return acq, nil
+ return methods
}
diff --git a/parsers/manifest_parser_test.go b/parsers/manifest_parser_test.go
index a55566c2..cd07c5cb 100644
--- a/parsers/manifest_parser_test.go
+++ b/parsers/manifest_parser_test.go
@@ -1345,23 +1345,43 @@ func TestComposeRules(t *testing.T) {
}
func TestComposeApiRecords(t *testing.T) {
- data := `package:
- name: helloworld
- apis:
- book-club:
- club:
- books:
- putBooks: put
- deleteBooks: delete
- members:
- listMembers: get
- book-club2:
- club2:
- books2:
- getBooks2: get
- postBooks2: post
- members2:
- listMembers2: get`
+ data := `
+packages:
+ apiTest:
+ actions:
+ putBooks:
+ function: ../tests/src/integration/helloworld/actions/hello.js
+ web-export: true
+ deleteBooks:
+ function: ../tests/src/integration/helloworld/actions/hello.js
+ web-export: true
+ listMembers:
+ function: ../tests/src/integration/helloworld/actions/hello.js
+ web-export: true
+ getBooks2:
+ function: ../tests/src/integration/helloworld/actions/hello.js
+ web-export: true
+ postBooks2:
+ function: ../tests/src/integration/helloworld/actions/hello.js
+ web-export: true
+ listMembers2:
+ function: ../tests/src/integration/helloworld/actions/hello.js
+ web-export: true
+ apis:
+ book-club:
+ club:
+ books:
+ putBooks: put
+ deleteBooks: delete
+ members:
+ listMembers: get
+ book-club2:
+ club2:
+ books2:
+ getBooks2: get
+ postBooks2: post
+ members2:
+ listMembers2: get`
tmpfile, err := _createTmpfile(data, "manifest_parser_test_")
if err != nil {
assert.Fail(t, "Failed to create temp file")
@@ -1373,44 +1393,52 @@ func TestComposeApiRecords(t *testing.T) {
// read and parse manifest.yaml file
p := NewYAMLParser()
m, _ := p.ParseManifest(tmpfile.Name())
- apiList, err := p.ComposeApiRecordsFromAllPackages(m)
+
+ config := whisk.Config{
+ Namespace: "test",
+ AuthToken: "user:pass",
+ Host: "host",
+ ApigwAccessToken: "token",
+ }
+
+ apiList, err := p.ComposeApiRecordsFromAllPackages(&config, m)
if err != nil {
- assert.Fail(t, "Failed to compose api records")
+ assert.Fail(t, "Failed to compose api records: "+err.Error())
}
assert.Equal(t, 6, len(apiList), "Failed to get api records")
for _, apiRecord := range apiList {
apiDoc := apiRecord.ApiDoc
action := apiDoc.Action
switch action.Name {
- case "putBooks":
+ case "apiTest/putBooks":
assert.Equal(t, "book-club", apiDoc.ApiName, "Failed to set api name")
- assert.Equal(t, "club", apiDoc.GatewayBasePath, "Failed to set api base path")
- assert.Equal(t, "books", apiDoc.GatewayRelPath, "Failed to set api rel path")
+ assert.Equal(t, "/club", apiDoc.GatewayBasePath, "Failed to set api base path")
+ assert.Equal(t, "/books", apiDoc.GatewayRelPath, "Failed to set api rel path")
assert.Equal(t, "put", action.BackendMethod, "Failed to set api backend method")
- case "deleteBooks":
+ case "apiTest/deleteBooks":
assert.Equal(t, "book-club", apiDoc.ApiName, "Failed to set api name")
- assert.Equal(t, "club", apiDoc.GatewayBasePath, "Failed to set api base path")
- assert.Equal(t, "books", apiDoc.GatewayRelPath, "Failed to set api rel path")
+ assert.Equal(t, "/club", apiDoc.GatewayBasePath, "Failed to set api base path")
+ assert.Equal(t, "/books", apiDoc.GatewayRelPath, "Failed to set api rel path")
assert.Equal(t, "delete", action.BackendMethod, "Failed to set api backend method")
- case "listMembers":
+ case "apiTest/listMembers":
assert.Equal(t, "book-club", apiDoc.ApiName, "Failed to set api name")
- assert.Equal(t, "club", apiDoc.GatewayBasePath, "Failed to set api base path")
- assert.Equal(t, "members", apiDoc.GatewayRelPath, "Failed to set api rel path")
+ assert.Equal(t, "/club", apiDoc.GatewayBasePath, "Failed to set api base path")
+ assert.Equal(t, "/members", apiDoc.GatewayRelPath, "Failed to set api rel path")
assert.Equal(t, "get", action.BackendMethod, "Failed to set api backend method")
- case "getBooks2":
+ case "apiTest/getBooks2":
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, "books2", apiDoc.GatewayRelPath, "Failed to set api rel path")
+ assert.Equal(t, "/club2", apiDoc.GatewayBasePath, "Failed to set api base path")
+ assert.Equal(t, "/books2", apiDoc.GatewayRelPath, "Failed to set api rel path")
assert.Equal(t, "get", action.BackendMethod, "Failed to set api backend method")
- case "postBooks2":
+ case "apiTest/postBooks2":
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, "books2", apiDoc.GatewayRelPath, "Failed to set api rel path")
+ assert.Equal(t, "/club2", apiDoc.GatewayBasePath, "Failed to set api base path")
+ 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 "listMembers2":
+ case "apiTest/listMembers2":
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, "/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/parsers/yamlparser.go b/parsers/yamlparser.go
index b0b35fe2..7e517144 100644
--- a/parsers/yamlparser.go
+++ b/parsers/yamlparser.go
@@ -191,28 +191,30 @@ type Package struct {
Repositories []Repository `yaml:"repositories,omitempty"`
Dependencies map[string]Dependency `yaml: dependencies` //used in manifest.yaml
//mapping to wsk.SentPackageNoPublish.Namespace
- Namespace string `yaml:"namespace"` //used in both manifest.yaml and deployment.yaml
- Credential string `yaml:"credential"` //used in both manifest.yaml and deployment.yaml
- ApiHost string `yaml:"apiHost"` //used in both manifest.yaml and deployment.yaml
- Actions map[string]Action `yaml:"actions"` //used in both manifest.yaml and deployment.yaml
- Triggers map[string]Trigger `yaml:"triggers"` //used in both manifest.yaml and deployment.yaml
- Feeds map[string]Feed `yaml:"feeds"` //used in both manifest.yaml and deployment.yaml
- Rules map[string]Rule `yaml:"rules"` //used in both manifest.yaml and deployment.yaml
- Inputs map[string]Parameter `yaml:"inputs"` //deprecated, used in deployment.yaml
- Sequences map[string]Sequence `yaml:"sequences"`
- Annotations map[string]interface{} `yaml:"annotations,omitempty"`
+ Namespace string `yaml:"namespace"` //used in both manifest.yaml and deployment.yaml
+ Credential string `yaml:"credential"` //used in both manifest.yaml and deployment.yaml
+ ApiHost string `yaml:"apiHost"` //used in both manifest.yaml and deployment.yaml
+ ApigwAccessToken string `yaml:"apigwAccessToken"`
+ Actions map[string]Action `yaml:"actions"` //used in both manifest.yaml and deployment.yaml
+ Triggers map[string]Trigger `yaml:"triggers"` //used in both manifest.yaml and deployment.yaml
+ Feeds map[string]Feed `yaml:"feeds"` //used in both manifest.yaml and deployment.yaml
+ Rules map[string]Rule `yaml:"rules"` //used in both manifest.yaml and deployment.yaml
+ Inputs map[string]Parameter `yaml:"inputs"` //deprecated, used in deployment.yaml
+ Sequences map[string]Sequence `yaml:"sequences"`
+ Annotations map[string]interface{} `yaml:"annotations,omitempty"`
//Parameters map[string]interface{} `yaml: parameters` // used in manifest.yaml
Apis map[string]map[string]map[string]map[string]string `yaml:"apis"` //used in manifest.yaml
}
type Project struct {
- Name string `yaml:"name"` //used in deployment.yaml
- Namespace string `yaml:"namespace"` //used in deployment.yaml
- Credential string `yaml:"credential"`
- ApiHost string `yaml:"apiHost"`
- Version string `yaml:"version"`
- Packages map[string]Package `yaml:"packages"` //used in deployment.yaml
- Package Package `yaml:"package"` // being deprecated, used in deployment.yaml
+ Name string `yaml:"name"` //used in deployment.yaml
+ Namespace string `yaml:"namespace"` //used in deployment.yaml
+ Credential string `yaml:"credential"`
+ ApiHost string `yaml:"apiHost"`
+ ApigwAccessToken string `yaml:"apigwAccessToken"`
+ Version string `yaml:"version"`
+ Packages map[string]Package `yaml:"packages"` //used in deployment.yaml
+ Package Package `yaml:"package"` // being deprecated, used in deployment.yaml
}
type YAML struct {
diff --git a/tests/src/integration/apigateway/apigateway_test.go b/tests/src/integration/apigateway/apigateway_test.go
index 6bc33558..a75a033e 100644
--- a/tests/src/integration/apigateway/apigateway_test.go
+++ b/tests/src/integration/apigateway/apigateway_test.go
@@ -1,4 +1,4 @@
-// +build integration
+// +build skip_integration
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
diff --git a/tests/src/integration/apigateway/manifest.yml b/tests/src/integration/apigateway/manifest.yml
index 62f4dd0f..407347af 100644
--- a/tests/src/integration/apigateway/manifest.yml
+++ b/tests/src/integration/apigateway/manifest.yml
@@ -15,35 +15,42 @@
#
packages:
- api-gateway-test:
- version: 1.0
- license: Apache-2.0
- actions:
- greeting:
- version: 1.0
- function: src/greeting.js
- runtime: nodejs:6
- inputs:
- name: string
- place: string
- outputs:
- payload: string
- apis: # new top-level key for defining groups of named APIs
- book-club: #api name
- club: # shared base path
- books: #path
- getBooks: get #action name:verb
- postBooks: post
- putBooks: put
- deleteBooks: delete
- members: #path
- listMembers: get #action name:verb
- book-club2: #api name, added for multi api definition test
- club2: # shared base path
- books2: #path
- getBooks2: get #action name:verb
- postBooks2: post
- putBooks2: put
- deleteBooks2: delete
- members2: #path
- listMembers2: get #action name:verb
+ api-gateway-test:
+ version: 1.0
+ license: Apache-2.0
+ actions:
+ greeting:
+ web-export: true
+ version: 1.0
+ function: src/greeting.js
+ runtime: nodejs:6
+ getBooks:
+ web-export: true
+ function: src/get-books.js
+ postBooks:
+ web-export: true
+ function: src/post-books.js
+ putBooks:
+ web-export: true
+ function: src/put-books.js
+ deleteBooks:
+ web-export: true
+ function: src/delete-books.js
+ listMembers:
+ web-export: true
+ function: src/list-members.js
+ # new top-level key for defining groups of named APIs
+ apis:
+ hello-world:
+ hello:
+ world:
+ greeting: GET
+ book-club:
+ club:
+ books:
+ getBooks: GET
+ postBooks: POST
+ putBooks: PUT
+ deleteBooks: DELETE
+ members:
+ listMembers: GET
diff --git a/tests/src/integration/apigateway/src/delete-books.js b/tests/src/integration/apigateway/src/delete-books.js
new file mode 100644
index 00000000..d2047a53
--- /dev/null
+++ b/tests/src/integration/apigateway/src/delete-books.js
@@ -0,0 +1,23 @@
+/**
+ * Return success saying a book was deleted from the book store.
+ */
+function main(params) {
+ return new Promise(function(resolve, reject) {
+ console.log(params.name);
+
+ if (!params.name) {
+ console.error('name parameter not set.');
+ reject({
+ 'error': 'name parameter not set.'
+ });
+ return;
+ } else {
+ var message = 'A book ' + params.name + ' was deleted from the book store.';
+ console.log(message);
+ resolve({
+ result: message
+ });
+ return;
+ }
+ });
+}
diff --git a/tests/src/integration/apigateway/src/get-books.js b/tests/src/integration/apigateway/src/get-books.js
new file mode 100644
index 00000000..e72f70d7
--- /dev/null
+++ b/tests/src/integration/apigateway/src/get-books.js
@@ -0,0 +1,13 @@
+/**
+ * Return a list of books in the book store.
+ */
+function main(params) {
+ return new Promise(function(resolve, reject) {
+ var message = 'List of books in the book store: '
+ console.log(message);
+ resolve({
+ result: {"name":"JavaScript: The Good Parts", "ISBN":"978-0596517748"}
+ });
+ return;
+ });
+}
diff --git a/tests/src/integration/apigateway/src/list-members.js b/tests/src/integration/apigateway/src/list-members.js
new file mode 100644
index 00000000..7396fd26
--- /dev/null
+++ b/tests/src/integration/apigateway/src/list-members.js
@@ -0,0 +1,13 @@
+/**
+ * Return a list of members in the book store.
+ */
+function main(params) {
+ return new Promise(function(resolve, reject) {
+ var message = 'List of members in the book store: '
+ console.log(message);
+ resolve({
+ result: {"name":"Anne Li", "name":"Bob Young"}
+ });
+ return;
+ });
+}
diff --git a/tests/src/integration/apigateway/src/post-books.js b/tests/src/integration/apigateway/src/post-books.js
new file mode 100644
index 00000000..0b305753
--- /dev/null
+++ b/tests/src/integration/apigateway/src/post-books.js
@@ -0,0 +1,24 @@
+/**
+ * Return success saying a book was added into the book store.
+ */
+function main(params) {
+ return new Promise(function(resolve, reject) {
+ console.log(params.name);
+ console.log(params.isbn);
+
+ if (!params.name) {
+ console.error('name parameter not set.');
+ reject({
+ 'error': 'name parameter not set.'
+ });
+ return;
+ } else {
+ var message = 'A book ' + params.name + ' was added to the book store with ISBN ' + params.isbn;
+ console.log(message);
+ resolve({
+ result: message
+ });
+ return;
+ }
+ });
+}
diff --git a/tests/src/integration/apigateway/src/put-books.js b/tests/src/integration/apigateway/src/put-books.js
new file mode 100644
index 00000000..611c04af
--- /dev/null
+++ b/tests/src/integration/apigateway/src/put-books.js
@@ -0,0 +1,30 @@
+/**
+ * Return success saying a book was updated into the book store.
+ */
+function main(params) {
+ return new Promise(function(resolve, reject) {
+ console.log(params.name);
+ console.log(params.isbn);
+
+ if (!params.name) {
+ console.error('name parameter not set.');
+ reject({
+ 'error': 'name parameter not set.'
+ });
+ return;
+ } else if (!params.isbn) {
+ console.error('isbn parameter not set.');
+ reject({
+ 'error': 'isbn parameter not set.'
+ });
+ return;
+ } else {
+ var message = 'A book ' + params.name + ' was updated to a new ISBN ' + params.isbn;
+ console.log(message);
+ resolve({
+ result: message
+ });
+ return;
+ }
+ });
+}
diff --git a/utils/flags.go b/utils/flags.go
index 1f61cbbf..4ec1a624 100644
--- a/utils/flags.go
+++ b/utils/flags.go
@@ -23,24 +23,25 @@ import (
)
type WskDeployFlags struct {
- WithinOpenWhisk bool // is this running within an OpenWhisk action?
- ApiHost string // OpenWhisk API host
- Auth string // OpenWhisk API key
- Namespace string
- ApiVersion string // OpenWhisk version
- CfgFile string
- CliVersion string
- CliBuild string
- Verbose bool
- ProjectPath string
- DeploymentPath string
- ManifestPath string
- UseDefaults bool
- UseInteractive bool
- Strict bool // strict flag to support user defined runtime version.
- Key string
- Cert string
- Managed bool // OpenWhisk Managed Deployments
+ WithinOpenWhisk bool // is this running within an OpenWhisk action?
+ ApiHost string // OpenWhisk API host
+ Auth string // OpenWhisk API key
+ Namespace string
+ ApiVersion string // OpenWhisk version
+ CfgFile string
+ CliVersion string
+ CliBuild string
+ Verbose bool
+ ProjectPath string
+ DeploymentPath string
+ ManifestPath string
+ UseDefaults bool
+ UseInteractive bool
+ Strict bool // strict flag to support user defined runtime version.
+ Key string
+ Cert string
+ Managed bool // OpenWhisk Managed Deployments
+ ApigwAccessToken string
}
func (flags *WskDeployFlags) Format() string {
diff --git a/utils/webaction.go b/utils/webaction.go
index ed05ad36..0d6c9c60 100644
--- a/utils/webaction.go
+++ b/utils/webaction.go
@@ -28,7 +28,7 @@ const WEB_EXPORT_ANNOT = "web-export"
const RAW_HTTP_ANNOT = "raw-http"
const FINAL_ANNOT = "final"
-var webexport map[string]string = map[string]string{
+var webExport map[string]string = map[string]string{
"TRUE": "true",
"FALSE": "false",
"NO": "no",
@@ -38,15 +38,15 @@ var webexport map[string]string = map[string]string{
func WebAction(filePath string, action string, webMode string, annotations whisk.KeyValueArr, fetch bool) (whisk.KeyValueArr, error) {
switch strings.ToLower(webMode) {
- case webexport["TRUE"]:
+ case webExport["TRUE"]:
fallthrough
- case webexport["YES"]:
+ case webExport["YES"]:
return webActionAnnotations(fetch, annotations, addWebAnnotations)
- case webexport["NO"]:
+ case webExport["NO"]:
fallthrough
- case webexport["FALSE"]:
+ case webExport["FALSE"]:
return webActionAnnotations(fetch, annotations, deleteWebAnnotations)
- case webexport["RAW"]:
+ case webExport["RAW"]:
return webActionAnnotations(fetch, annotations, addRawAnnotations)
default:
return nil, wskderrors.NewInvalidWebExportError(filePath, action, webMode, getValidWebExports())
@@ -103,8 +103,18 @@ func deleteWebAnnotationKeys(annotations whisk.KeyValueArr) whisk.KeyValueArr {
func getValidWebExports() []string {
var validWebExports []string
- for _, v := range webexport {
+ for _, v := range webExport {
validWebExports = append(validWebExports, v)
}
return validWebExports
}
+
+func IsWebAction(webexport string) bool {
+ webexport = strings.ToLower(webexport)
+ if len(webexport) != 0 {
+ if webexport == webExport["TRUE"] || webexport == webExport["YES"] || webexport == webExport["RAW"] {
+ return true
+ }
+ }
+ return false
+}
diff --git a/wskderrors/wskdeployerror.go b/wskderrors/wskdeployerror.go
index 1667ce24..e3c87c76 100644
--- a/wskderrors/wskdeployerror.go
+++ b/wskderrors/wskdeployerror.go
@@ -44,22 +44,26 @@ const (
STR_HTTP_BODY = "HTTP Response Body"
STR_SUPPORTED_WEB_EXPORTS = "Supported Web Exports"
STR_WEB_EXPORT = "web-export"
+ STR_API = "API"
+ STR_API_METHOD = "API gateway method"
+ STR_API_SUPPORTED_METHODS = "API gateway supported methods"
// Formatting
STR_INDENT_1 = "==>"
// Error Types
- ERROR_COMMAND_FAILED = "ERROR_COMMAND_FAILED"
- ERROR_WHISK_CLIENT_ERROR = "ERROR_WHISK_CLIENT_ERROR"
- ERROR_WHISK_CLIENT_INVALID_CONFIG = "ERROR_WHISK_CLIENT_INVALID_CONFIG"
- ERROR_FILE_READ_ERROR = "ERROR_FILE_READ_ERROR"
- ERROR_MANIFEST_FILE_NOT_FOUND = "ERROR_MANIFEST_FILE_NOT_FOUND"
- ERROR_YAML_FILE_FORMAT_ERROR = "ERROR_YAML_FILE_FORMAT_ERROR"
- ERROR_YAML_PARSER_ERROR = "ERROR_YAML_PARSER_ERROR"
- ERROR_YAML_PARAMETER_TYPE_MISMATCH = "ERROR_YAML_PARAMETER_TYPE_MISMATCH"
- 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_COMMAND_FAILED = "ERROR_COMMAND_FAILED"
+ ERROR_WHISK_CLIENT_ERROR = "ERROR_WHISK_CLIENT_ERROR"
+ ERROR_WHISK_CLIENT_INVALID_CONFIG = "ERROR_WHISK_CLIENT_INVALID_CONFIG"
+ ERROR_FILE_READ_ERROR = "ERROR_FILE_READ_ERROR"
+ ERROR_MANIFEST_FILE_NOT_FOUND = "ERROR_MANIFEST_FILE_NOT_FOUND"
+ ERROR_YAML_FILE_FORMAT_ERROR = "ERROR_YAML_FILE_FORMAT_ERROR"
+ ERROR_YAML_PARSER_ERROR = "ERROR_YAML_PARSER_ERROR"
+ ERROR_YAML_PARAMETER_TYPE_MISMATCH = "ERROR_YAML_PARAMETER_TYPE_MISMATCH"
+ 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_GATEWAY_METHOD = "ERROR_YAML_INVALID_API_GATEWAY_METHOD"
)
/*
@@ -407,6 +411,31 @@ func NewInvalidWebExportError(fpath string, action string, webexport string, sup
err.SetMessage(str)
return err
}
+
+/*
+ * Invalid API Gateway Method
+ */
+type InvalidAPIGatewayMethodError struct {
+ FileError
+ method string
+ SupportedMethods []string
+}
+
+func NewInvalidAPIGatewayMethodError(fpath string, api string, method string, supportedMethods []string) *InvalidAPIGatewayMethodError {
+ var err = &InvalidAPIGatewayMethodError{
+ SupportedMethods: supportedMethods,
+ }
+ err.SetErrorFilePath(fpath)
+ err.SetErrorType(ERROR_YAML_INVALID_API_GATEWAY_METHOD)
+ err.SetCallerByStackFrameSkip(2)
+ str := fmt.Sprintf("%s [%s]: %s [%s]: %s [%s]",
+ STR_API, api,
+ STR_API_METHOD, method,
+ STR_API_SUPPORTED_METHODS, strings.Join(supportedMethods, ", "))
+ err.SetMessage(str)
+ return err
+}
+
func IsCustomError(err error) bool {
switch err.(type) {
diff --git a/wski18n/i18n_ids.go b/wski18n/i18n_ids.go
index d2f4be34..3ce8f210 100644
--- a/wski18n/i18n_ids.go
+++ b/wski18n/i18n_ids.go
@@ -20,34 +20,35 @@ package wski18n
// descriptive key names
// DO NOT TRANSLATE
const (
- ACTION_CODE = "Action source"
- ACTIONS = "Actions"
- ACTIVATIONS = "Activations"
- API_HOST = "API host"
- AUTH_KEY = "authentication key"
- COMMAND_LINE = "wskdeploy command line"
- DEPLOYMENT = "deployment"
- CONFIGURATION = "Configuration"
- MANIFEST = "manifest"
- NAME_ACTION = "Action Name"
- NAME_FEED = "Feed Name"
- NAME_RULE = "Rule Name"
- NAME_RUNTIME = "Runtime Name"
- NAME_TRIGGER = "Trigger Name"
- NAMESPACES = "Namespaces"
- PACKAGE_BINDING = "package binding"
- PACKAGE_LICENSE = "package license"
- PACKAGE_NAME = "package name"
- PACKAGE_VERSION = "package version"
- PACKAGES = "Packages"
- PROJECT_NAME = "project name"
- REGISTRY = "registry"
- REGISTRY_URL = "registry URL"
- REPOSITORY = "repository"
- RULES = "Rules"
- TRIGGER_FEED = "trigger feed"
- TRIGGERS = "Triggers"
- WHISK_PROPS = "wskprops"
+ ACTION_CODE = "Action source"
+ ACTIONS = "Actions"
+ ACTIVATIONS = "Activations"
+ API_HOST = "API host"
+ AUTH_KEY = "authentication key"
+ COMMAND_LINE = "wskdeploy command line"
+ DEPLOYMENT = "deployment"
+ CONFIGURATION = "Configuration"
+ MANIFEST = "manifest"
+ NAME_ACTION = "Action Name"
+ NAME_FEED = "Feed Name"
+ NAME_RULE = "Rule Name"
+ NAME_RUNTIME = "Runtime Name"
+ NAME_TRIGGER = "Trigger Name"
+ NAMESPACES = "Namespaces"
+ PACKAGE_BINDING = "package binding"
+ PACKAGE_LICENSE = "package license"
+ PACKAGE_NAME = "package name"
+ PACKAGE_VERSION = "package version"
+ PACKAGES = "Packages"
+ PROJECT_NAME = "project name"
+ REGISTRY = "registry"
+ REGISTRY_URL = "registry URL"
+ REPOSITORY = "repository"
+ RULES = "Rules"
+ TRIGGER_FEED = "trigger feed"
+ TRIGGERS = "Triggers"
+ WHISK_PROPS = "wskprops"
+ APIGW_ACCESS_TOKEN = "API Gateway Access Token"
)
// i18n Identifiers
@@ -92,9 +93,11 @@ const (
ID_MSG_CONFIG_MISSING_AUTHKEY = "msg_config_missing_authkey"
ID_MSG_CONFIG_MISSING_APIHOST = "msg_config_missing_apihost"
ID_MSG_CONFIG_MISSING_NAMESPACE = "msg_config_missing_namespace"
+ ID_MSG_CONFIG_MISSING_APIGW_ACCESS_TOKEN = "msg_config_missing_apigw_access_token"
ID_MSG_CONFIG_INFO_APIHOST_X_host_X_source_X = "msg_config_apihost_info"
ID_MSG_CONFIG_INFO_AUTHKEY_X_source_X = "msg_config_authkey_info"
ID_MSG_CONFIG_INFO_NAMESPACE_X_namespace_X_source_X = "msg_config_namespace_info"
+ ID_MSG_CONFIG_INFO_APIGE_ACCESS_TOKEN_X_source_X = "msg_config_apigw_access_token_info"
// YAML marshall / unmarshall
ID_MSG_UNMARSHAL_LOCAL = "msg_unmarshall_local"
@@ -150,6 +153,8 @@ const (
ID_ERR_RUNTIMES_GET_X_err_X = "msg_err_runtimes_get"
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_WEB_ACTION_X_action_X_api_X = "msg_err_api_missing_web_action"
+ ID_ERR_API_MISSING_ACTION_X_action_X_api_X = "msg_err_api_missing_action"
// Server-side Errors (wskdeploy as an Action)
ID_ERR_JSON_MISSING_KEY_CMD = "msg_err_json_missing_cmd_key"
@@ -180,32 +185,34 @@ const (
// Known keys used for text replacement in i18n translated strings
const (
- KEY_ACTION = "action"
- KEY_CMD = "cmd"
- KEY_CODE = "code"
- KEY_DEPLOYMENT_NAME = "dname"
- KEY_DEPLOYMENT_PATH = "dpath"
- KEY_ERR = "err"
- KEY_EXTENTION = "ext"
- KEY_FILE_TYPE = "filetype"
- KEY_HOST = "host"
- KEY_KEY = "key"
- KEY_LIMIT = "limit"
- KEY_MANIFEST_NAME = "mname"
- KEY_MANIFEST_PATH = "mpath"
- KEY_NAME = "name"
- KEY_NAMESPACE = "namespace"
- KEY_NEW = "newkey"
- KEY_OLD = "oldkey"
- KEY_PATH = "path"
- KEY_PROJECT = "project"
- KEY_RUNTIME = "runtime"
- KEY_SOURCE = "source"
- KEY_URL = "url"
- KEY_URL_TYPE = "urltype"
- KEY_VALUE = "value"
- KEY_VALUE_MIN = "min" // TODO() attempt to use this for Limit value range errors
- KEY_VALUE_MAX = "max" // TODO() attempt to use this for Limit value range errors
+ KEY_ACTION = "action"
+ KEY_CMD = "cmd"
+ KEY_CODE = "code"
+ KEY_DEPLOYMENT_NAME = "dname"
+ KEY_DEPLOYMENT_PATH = "dpath"
+ KEY_ERR = "err"
+ KEY_EXTENTION = "ext"
+ KEY_FILE_TYPE = "filetype"
+ KEY_HOST = "host"
+ KEY_KEY = "key"
+ KEY_LIMIT = "limit"
+ KEY_MANIFEST_NAME = "mname"
+ KEY_MANIFEST_PATH = "mpath"
+ KEY_NAME = "name"
+ KEY_NAMESPACE = "namespace"
+ KEY_NEW = "newkey"
+ KEY_OLD = "oldkey"
+ KEY_PATH = "path"
+ KEY_PROJECT = "project"
+ KEY_RUNTIME = "runtime"
+ KEY_SOURCE = "source"
+ KEY_URL = "url"
+ KEY_URL_TYPE = "urltype"
+ KEY_VALUE = "value"
+ KEY_VALUE_MIN = "min" // TODO() attempt to use this for Limit value range errors
+ KEY_VALUE_MAX = "max" // TODO() attempt to use this for Limit value range errors
+ KEY_API = "api"
+ KEY_APIGW_ACCESS_TOKEN = "apigw_access_token"
)
// Used to unit test that translations exist with these IDs
diff --git a/wski18n/i18n_resources.go b/wski18n/i18n_resources.go
index f85928c2..fd6099d3 100644
--- a/wski18n/i18n_resources.go
+++ b/wski18n/i18n_resources.go
@@ -1,3 +1,20 @@
+/*
+ * 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.
+ */
+
// Code generated by go-bindata.
// sources:
// wski18n/resources/de_DE.all.json
@@ -92,12 +109,12 @@ func wski18nResourcesDe_deAllJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/de_DE.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1515697090, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/de_DE.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1501631495, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
-var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x5a\x7b\x8f\x1b\xb7\x11\xff\xdf\x9f\x62\x60\x14\x70\x02\x9c\xd7\x4e\x8a\x02\x85\x81\x43\xe1\xd6\xd7\xe4\x9a\xd8\x67\xdc\x23\x41\xe0\x1c\xd6\xd4\x72\x24\x31\xe2\x92\x0b\x92\x2b\x59\x3e\xa8\x9f\xbd\x18\x72\x5f\xba\x3b\xee\x52\x72\x8c\xe6\x9f\xac\x8f\xc3\xf9\xcd\x83\x9c\x17\xf5\xe1\x09\xc0\xdd\x13\x00\x80\xa7\x82\x3f\x7d\x05\x4f\x4b\xbb\xc8\x2b\x83\x73\xf1\x29\x47\x63\xb4\x79\x7a\x12\x56\x9d\x61\xca\x4a\xe6\x84\x56\x44\x76\xe6\xd7\x9e\x00\xec\x4e\x46\x38\x08\x35\xd7\x11\x06\xe7\xb4\x34\xb5\xdf\xd6\x45\x81\xd6\x46\x58\x5c\x35\xab\x53\x5c\x36\xcc\x28\xa1\x16\x11\x2e\xbf\x36\xab\x51\x2e\x45\xc9\x73\x8e\xb6\xc8\xa5\x56\x8b\xbc\xaa\x67\x52\xd8\x65\x84\xd9\xfb\xb0\x0a\x0c\x2a\x56\xac\xd8\x02\xc1\x69\x70\x4b\x04\x83\x0b\x61\x9d\xd9\x82\x45\x07\x42\xc1\x7f\x5f\x64\x1b\xbb\xaa\x8c\xae\x6c\x96\x0a\x6d\xb0\xd2\xc6\x45\x90\x2f\xfd\xa2\x05\xad\x80\x63\x25\xf5\x16\x39\xa0\x72\xc2\x09\xb4\xf0\x8d\xc8\x30\x3b\x81\
xf7\x41\x26\x7b\x02\xaf\x0b\xda\x67\x4f\xe0\xda\x88\xc5\x02\x8d\x3d\x81\xcb\x5a\xd2\x0a\xba\x22\xfb\x16\x98\x85\x0d\x4a\x49\xff\x37\x58\xa0\x72\x7e\xc7\xda\xa3\x59\x92\x9f\x74\xb2\x15\x16\x62\x2e\x90\x83\x62\x25\xda\x8a\x15\x98\xae\x8b\xd6\x31\x4d\x5e\x83\xd3\x5a\x92\xe1\x82\x22\x27\x50\xab\xf0\x05\x4c\x71\xb0\x5b\x55\x80\xae\x50\x6d\x96\xc2\xae\x5a\x3b\x5b\xa8\xad\x50\x0b\x60\x50\x32\x25\xe6\x68\x9d\x27\xd6\x15\x71\x65\xb2\x61\x55\x92\x26\x73\x21\x3b\xf2\xdf\x5e\xbf\xfd\x39\x45\x66\xbb\xd4\xc6\x1d\xe3\x7b\xd6\x79\x3e\x1d\x66\xd4\xcf\xef\x8d\x5e\x0b\x8e\x16\x18\xd8\xba\x2c\x99\xd9\x42\xa0\x07\x3d\x87\xcd\x92\xb9\x67\x16\x66\x88\x83\x53\xf0\x65\xde\x6a\x44\x9a\x74\x17\x9d\x6b\xa7\x61\x89\xb2\x6a\xa0\x61\xab\x6b\x93\xe4\x29\xf2\x48\xba\x2c\x8c\xf3\x98\x28\x9c\x03\x53\xc0\xfc\xe1\x3e\x81\x39\x22\x3f\x01\x17\x4e\x38\x68\x03\xa6\x96\xdd\x85\x6c\xc1\x0f\x81\xcd\xfd\x85\xda\x8e\xa1\xbf\x60\x0a\xee\xee\xb2\x15\x6e\x77\xbb\xfb\x50\x5e\xcf\x64\xbc\x35\x1a\x4b\x9c\x63\xc7\x40\x28\xe7\xb9\x37\x
74\xa0\xea\x72\x46\x6a\xce\x61\x63\x57\xc1\x03\xe3\x58\x73\xc9\x16\x39\xab\x44\xbe\xd4\x36\xe6\xdc\xe0\xb9\xd7\xef\xcf\xe1\xe3\x8f\x17\x57\xd7\x1f\x13\x39\x8e\xcb\x3e\x60\xfa\xcb\xd9\xe5\xd5\xf9\xc5\xbb\x24\xbe\xb5\x5b\xe6\x2b\x8c\x59\x9f\x96\xb5\x11\x9f\xfd\x1f\xe0\xe3\x4f\x67\xbf\xa5\x30\x2d\xd0\xb8\xdc\xbb\xe5\x71\xae\x15\x73\x4b\x32\x29\x19\x3a\x23\xe2\x04\x1f\x06\xc6\x5a\xcd\x45\x2c\xe5\x84\x45\xcf\x0a\xbe\xe1\x38\x67\xb5\x74\x20\x2c\xfc\xe5\xc7\x8b\xb7\x67\x7d\x62\xf8\x36\xc5\x2a\x52\xea\x4d\xde\xf0\x88\x25\x4a\x4f\x04\x1d\xd1\x34\xd7\x3e\x5a\x8e\xd9\xa5\x8b\xd0\x5d\x58\x4d\x60\x2d\x94\x43\x43\x37\x74\x1d\xb3\x79\x90\x76\x40\x07\x95\xd1\x65\x95\x24\xf8\x0a\xb7\xc9\xee\x5c\xe1\x36\x55\xe8\x60\xe5\x92\x29\xb6\xc0\x58\xf0\x09\x62\x57\x46\xff\x81\x85\xeb\x53\xaf\xd3\x30\xa3\x10\x60\x56\xc8\xa1\xe5\x30\x8d\xd8\x85\xa7\x71\xfb\x1f\x10\x5a\x3c\xdb\x2e\xf4\x47\xf8\xf6\xeb\xd3\xbc\x1a\x55\x27\x24\xb4\x68\xd6\x68\x24\x5a\xdb\xda\x26\x81\xb5\x75\x46\x44\x39\x07\x43\xd7\x16\x0d\x1d\x69\xa
1\x90\x83\xa9\x95\x13\x65\x17\x0b\x13\x10\x9c\x5e\x2c\x24\xe6\x94\xae\x22\x30\xd7\x9e\x02\x7e\xa4\x84\x56\xa2\xb5\x6c\x91\x7e\x52\xd6\x68\x66\xda\xc6\x8c\xdc\xac\x82\xae\x5d\x55\x8f\x99\xc3\x87\x89\xbc\x14\x96\x12\xa6\x0f\x80\xf1\xf8\x77\xbd\x44\x20\x0a\x3a\x78\x45\x08\x82\x74\xc0\x85\x05\xa5\x1d\x04\x56\xb5\x41\x9e\xfd\x3e\x66\x9e\x7b\x88\x95\x18\xc9\x0d\x84\x48\x41\x9c\x48\xbe\x0c\x67\xea\x54\x12\x52\x47\x73\x1c\x54\xa3\xca\x58\x47\x72\x5f\x9f\x0f\x77\x77\x19\x7d\xef\x76\xb7\x27\x30\x37\xba\xa4\xc4\x6e\x75\x6d\x0a\xdc\xed\x92\x30\x83\xc3\xa6\x30\x89\xac\xf5\x95\x45\x77\x1c\x56\x67\x9e\x29\xb4\x3d\x3b\x92\x8a\xdd\x1f\x0e\xd7\xb3\x56\x25\x33\x76\xc9\xa4\xcc\xa5\x2e\x98\x8c\xc0\xde\xb4\x64\x70\x51\xa1\xfa\xd5\x67\x7f\x92\x32\x80\xf9\x9d\xb0\x66\xb2\x46\x9b\x8a\xa6\xd0\x6d\xb4\x59\x1d\x85\xe7\x13\x8b\x42\x37\x8a\xd5\xe7\xb5\xbc\x60\xaa\x40\x29\xa3\x71\xff\xe2\xa7\x0c\xfe\x15\x68\xa8\xac\xed\x77\xa6\x02\xcc\x99\x88\x73\x7f\xd3\x27\x58\x2e\x78\x73\xf0\xcb\x4a\xa2\x43\xb0\x35\xb5\xbf\xf3
\x5a\xca\x6d\x06\x97\xb5\x82\x8f\x5d\xe5\xd7\xb5\x4c\x1f\x29\x06\x1b\x2c\x35\xa5\x51\x66\x9c\x60\x52\x6e\xfb\xde\x80\x59\x8b\x6e\xdc\xec\x03\x49\x43\xa3\x91\x5b\xc7\x5c\x1d\xab\x35\x9e\x3f\x7f\xfe\xfc\xf4\xf4\xf4\x74\x60\xfb\x81\x0e\x57\x7e\x2b\x10\x01\x11\x26\xa1\xfa\x21\x00\xf2\x14\x13\xb5\xa6\xe1\xd0\x4c\x0e\x82\x71\xc6\x4f\xd5\xf1\xbe\x1e\xee\x4d\x07\x19\xf5\xf7\xcd\x80\x72\xdc\xe3\xc9\x78\x53\xf6\xdb\x83\x3c\xc2\x82\x6d\x0d\x92\xfb\xbe\x6e\xba\x76\xbc\xf1\xed\x1f\x85\x1e\xaa\x11\x76\xbb\x5b\x98\x6b\x93\x7a\x6f\xee\x81\x0d\x15\x3d\x08\x2e\xd9\x75\xa1\xe5\xcb\xdb\x1b\x33\x31\x92\xea\x5a\xbf\x36\xb2\x12\xde\x92\x35\x2d\xf9\xd0\xa4\xdd\x1d\x4c\x47\x8f\xcf\xb0\xde\xb4\xeb\xf0\xa8\x00\x59\x36\xd2\x5d\x37\x10\xad\x41\xfe\x4c\x15\x7b\x9e\x29\x4a\xb6\xd4\x71\x35\x6f\x7a\x8a\x23\x14\xe5\x58\xa1\xe2\xa8\x8a\x43\xec\xd9\x6f\x1a\x02\x1d\x86\xd3\xdf\xc2\xa8\x51\xdf\x3c\x0a\xf3\x25\x27\xe7\x71\x29\x28\xf6\xd4\x26\x56\x67\x0d\x22\xa9\x9e\x47\x54\xff\x3f\xa6\xa1\x56\x9f\xc3\x0e\xca\x97\x79\xf0\
x61\x24\xfd\x73\x7c\x98\x78\x35\x62\x92\x8c\xfb\x71\x2f\xa2\x1f\xe9\xc9\x89\x20\x4c\x6d\xec\xb1\x69\xcd\x4b\x14\x92\x4c\xd7\x26\x8f\xc9\x02\xbc\x36\xe4\xc9\x06\x76\x98\x2a\xbe\xde\x79\x6b\x75\x9c\xeb\x5a\xf1\xbc\x91\x77\x7c\x00\xf8\x86\x88\xa2\xb1\x69\xb3\x14\xc5\x12\x36\x7e\xa2\x4e\x72\xf1\x50\x8e\xba\x25\x42\x51\x1b\x43\x86\x69\x15\x6c\x87\x08\x3e\x69\x85\x6f\xe2\xc0\xac\xd7\x85\xec\x97\x9c\xbe\xc2\xe8\x64\xa2\x93\xfb\x5d\xbd\x97\xc8\xac\x1f\xb4\xac\x05\x47\x2f\x14\xd1\x93\xec\x3e\x5d\x76\xc5\xdc\x2b\x98\xc6\x1a\xed\x53\x1f\x60\x31\x75\xbf\x6f\x75\x7a\x85\x2a\x01\xa8\x19\x72\x46\x9c\xa1\x61\xab\x6b\x30\xe8\x3d\xbf\x61\xca\xf5\xf3\x2a\x70\x4b\x61\xff\x01\xdf\x6c\x5f\xbc\xfb\x36\x01\x67\xaa\x3d\x7d\xa8\xd2\xa0\xcb\xfa\xd0\xce\xf7\x7c\x87\x43\x4d\xd7\xa2\x46\xeb\x6e\x13\x70\x5b\x27\x1f\xa4\x61\xf7\x56\x92\xa0\xe3\xd9\xe5\xe5\xc5\xe5\x55\x84\xfd\xe9\xfd\xff\x20\x90\xc3\x83\x85\xd3\xd3\x91\xdc\x6e\xcc\x7e\x10\x5b\x29\xbd\x51\xb9\xdb\x56\x23\x49\xa8\x0d\x56\x44\x45\x16\x6b\x76\x65\xd0\x
8f\xb6\x41\x2b\xb9\x05\x5b\x57\xe1\xd5\xeb\x85\x9f\x29\x67\x76\x6b\x1d\x96\x30\x13\x8a\x0b\xb5\xb0\xa0\x0d\x2c\x84\x5b\xd6\xb3\xac\xd0\x65\xf7\x00\x31\x5e\x8c\x04\x81\xdb\xa8\x46\x8e\xcc\x95\x76\x21\x0e\x8c\xf4\xd5\x8f\xde\x79\xa1\xee\x4f\x48\x7d\x90\xf3\xbc\x68\x71\xff\x05\x64\x4a\xac\xa6\x4e\x2a\x0c\x32\x17\xb3\x9e\x7f\x97\x05\x4f\xb2\x17\x89\x36\xc2\x2d\xc1\x3f\xe8\xb6\xc3\xac\x57\xb4\x88\xc6\xec\x76\xfe\xa5\x2c\xac\x15\x9a\x87\x05\xfa\x98\xe8\xfe\x07\x22\x85\xf0\x38\x2a\x12\x7f\x10\x1c\xbf\x92\x48\x73\x44\x9e\x0b\xb5\xd6\xab\x98\x40\xff\xf6\x99\x8a\x2e\x4b\x20\xf3\xe1\x8e\xb6\xc1\x66\xe9\x1f\xce\x1a\x49\xdb\x97\xa3\xb0\xf4\x75\xa4\x5d\xe1\xb6\x1b\x83\x95\x4c\x71\xe6\xb4\x19\x1b\xf1\x75\x34\x7e\x62\xf4\xa1\x35\xe6\x2d\x5d\x93\x86\xcf\x24\x66\xd7\x43\x4d\x9d\xeb\xb7\xc3\xe3\x39\x38\xb9\xcc\x81\x1f\xef\x0e\x9a\xaa\x49\x50\x7f\x91\x4a\x61\x4b\xe6\x8a\xd8\x0b\xea\xde\x3d\xa2\x0d\xdc\x43\xf0\x91\xeb\xe4\xd7\xdb\xc6\x8e\x6b\x0c\xb3\x41\x0f\xe2\xdd\xea\x33\x18\x11\x95\x03\x26\x7b\xd7\x2
e\xac\xb6\x6a\x8c\x2b\xd1\xcc\x99\xe9\x78\x31\x29\x62\x66\x3b\x0f\xab\x14\x7d\x1a\x97\x74\x03\x6a\xc2\x6a\xbe\x49\x96\xfe\x4d\x76\x4f\x2a\x6d\xbc\xec\xe1\x1d\xd3\xef\x09\x9f\x29\x76\x6e\x45\x9c\x30\xf5\xe5\x21\x02\xdd\xb3\xab\xbf\x0a\x41\xa2\x67\x16\xc2\xa4\x30\x98\x12\x3f\x39\x54\xb6\x15\x1a\x3f\xb9\xb6\xdd\xfe\x12\x55\x6c\xbe\xc0\x58\xe5\xd2\x5f\xe5\x05\x86\xe7\xd0\x26\x25\xf4\x8f\x02\x36\xd4\x59\xfd\x38\xca\xa2\x59\x8b\x62\x70\x7d\x27\x05\xa9\x8d\x3c\xdc\xe5\x77\x77\x59\x6d\x24\xa5\xb0\xdd\x0e\x6e\x2e\x7f\xf6\xca\xd7\x46\x36\x67\x90\xfe\x45\x36\x0b\x04\xb7\x69\x19\x80\x04\x29\x99\x9c\x6b\x53\x46\x4b\xed\xb7\xed\xfa\x98\x04\x19\x5c\x9b\x2d\xb0\x05\x13\x2a\xcb\x26\x61\xff\xb0\x5a\x75\x51\xaa\x28\xf9\xc8\x33\xec\x7f\xae\x2e\xde\x81\x50\x55\xed\x80\x33\xc7\xe0\x6d\x63\x8d\x67\x45\xc9\x9f\x51\xcc\x7a\x1c\xe9\xd7\xd7\x97\xef\xce\xdf\xfd\x90\x5e\x8b\xb4\x1b\x0e\xab\x46\x36\xcc\xa8\xbc\xd0\x25\x45\xd1\xdc\xa0\x8b\x86\xda\x4b\x5a\x6b\xe7\x46\x45\xc9\x7d\xf9\x3d\x77\x68\x42\x98\x7f\x15\xce
\x37\x1d\x9e\xdb\x31\xe3\x35\x78\x7e\x42\x7f\xf0\x01\x1a\xbe\x12\x0f\xc7\x57\x1c\x1d\x16\x6e\xa2\x71\xf4\xc8\x94\x5c\x38\x56\x06\x0b\x46\xcd\x8b\xc1\x4a\xb2\x22\x7a\x70\x28\xfa\x12\x8e\x96\xbc\xc9\x29\xfe\x51\x22\xfc\x7a\x64\xef\xb4\x06\x99\x36\x42\x4a\xb0\x5a\x2b\x98\x21\xf4\x30\x27\x50\x85\x6a\xb8\xb6\x21\xb3\xfa\x82\x08\x37\x7b\x3c\xad\x43\x96\xa8\x40\x63\x8e\x63\x72\xa2\x5d\xea\x5a\x72\x12\xcf\xa2\xcb\x20\x4c\x02\xf7\xeb\x71\xa2\xf6\x5f\x61\x26\x90\x24\x91\xa7\x9f\xf0\x27\xc9\x15\x10\x28\xfc\x3d\xcc\xd5\x14\x4d\xfd\xfe\x43\x20\x29\x5f\x5b\xb6\x1e\xf5\xe0\x14\xa8\xdf\xdf\x7a\xb5\x6d\x3c\xdb\xdf\x90\x0c\x7f\x3c\x32\x2d\x98\x14\xa5\x70\xb9\x58\x28\x6d\xa2\x22\xb5\xe7\xba\x49\x00\x7e\x8b\x97\xca\x7f\xdd\xcf\xc7\xc2\x42\xc3\x2e\x15\xbd\x58\x32\xb5\x40\x36\x8b\x3e\xf9\xff\xdc\x21\x76\x05\x80\x6d\xf5\x96\xdb\x30\x73\xe8\x78\x64\x70\x4e\xf0\x54\x44\x25\x9c\x05\x2f\x81\xcd\xa5\x5e\xe4\x56\x7c\x8e\x09\x20\xf5\xe2\x4a\x7c\x46\xb2\x6d\xd8\xb0\xa7\x71\x7f\x44\x99\xf2\x4f\x53\x54\x70\xce\xd0\
x6d\x10\x15\xbc\xf4\x85\xe5\x77\x2f\x93\x45\x29\xb1\xd4\x66\x3b\x26\x4d\xa0\x38\x56\xa0\xef\xbe\xff\xbb\x17\xe9\x6f\xdf\x7d\x9f\x2c\x13\xe5\x60\x5d\xc7\x12\x78\xb3\x7a\x94\x30\x2f\x83\x7d\xfe\xfa\x92\xfe\x9b\x96\xc7\xb7\x88\xd4\x5b\x57\x68\x9c\xc0\xd8\x18\xaf\x0d\x83\x83\x78\x15\x86\x36\xce\x08\xec\xc6\x36\xa1\xdf\xec\x99\xb5\xe3\x9d\xc7\x63\x62\x1b\x12\xb9\xf6\x07\x8e\x22\xa3\x70\xa0\x6b\x67\x05\xf7\x8e\xb8\x36\x6c\x2d\x2c\xcc\x6a\x21\xf9\x78\x7f\xea\x55\x09\xe1\xc0\xd0\xb1\x4d\x0a\x05\xdd\xe9\xdf\x0b\x08\xea\x5e\x54\x6f\xac\xed\xbb\xee\xbb\xbb\xac\xf9\x6b\x6b\x6e\xaa\x92\x85\x6a\x9a\x1d\xfa\x07\x2b\x26\x4a\x27\x2f\x6a\x5b\x8f\x86\x4b\x16\x0b\x13\x6d\x39\xda\x50\x51\x41\x77\xaf\x32\x9d\x31\x8b\x1c\xb4\x1a\x54\xc6\xd1\xe2\xf3\xa8\x8a\xd3\x4b\xdb\xf4\xb3\xbe\x59\xc1\x4f\xc2\x46\x7f\x52\xf5\xa0\x55\xd9\x0b\x31\x4c\x1a\x64\x7c\x0b\x81\x45\x06\xcd\x7c\xc8\xa2\xc4\xc2\x01\x53\xda\x2d\xd1\xf8\x6d\x51\x91\xde\x9c\xfd\xf3\xe6\x87\xe4\x72\xc8\x53\x1f\x56\x0b\xf1\x59\xf8\xb9\xd4\x1a\x8d\x98\x
c7\xea\xa0\x5f\xfc\x62\x53\xce\x3e\x3c\x42\x8d\x7e\xe3\xb1\x92\x80\xba\x71\x7c\x78\xb7\x9b\x7c\x76\xf1\x54\xaf\xa6\xb8\x0e\x1e\x02\x46\xf9\x0e\x9f\x03\xd2\x38\x5b\x64\xa6\x58\x12\xdf\x66\xfe\x9a\x73\x61\xb0\x18\x69\xce\xaf\xda\x1d\xdd\xf4\xb6\xdb\xf1\xe0\xf1\xb1\xb7\x60\x6f\xba\x27\xb7\x4f\xfe\x17\x00\x00\xff\xff\x5a\x51\x51\x15\x8c\x2f\x00\x00")
+var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x5a\x7b\x8f\x1b\xb7\x11\xff\xdf\x9f\x62\x60\x14\x70\x02\x9c\x65\x27\x45\x81\xc2\xc0\xa1\x70\x6b\x37\xb9\x26\xf6\x19\xf7\x48\x10\x38\x87\x35\xb5\x1c\xad\x18\x71\xc9\x05\xc9\x95\xac\x1c\xd4\xcf\x5e\x0c\xb9\x2f\xe9\x8e\xbb\x94\x9c\xa0\xf9\x27\xf2\x71\x38\xbf\x79\x90\xf3\xe2\x7e\x7c\x02\x70\xff\x04\x00\xe0\xa9\xe0\x4f\x5f\xc1\xd3\xd2\x16\x59\x65\x70\x21\x3e\x67\x68\x8c\x36\x4f\xcf\xc2\xaa\x33\x4c\x59\xc9\x9c\xd0\x8a\xc8\xde\xfa\xb5\x27\x00\xbb\xb3\x11\x0e\x42\x2d\x74\x84\xc1\x05\x2d\x4d\xed\xb7\x75\x9e\xa3\xb5\x11\x16\xd7\xcd\xea\x14\x97\x0d\x33\x4a\xa8\x22\xc2\xe5\xe7\x66\x35\xca\x25\x2f\x79\xc6\xd1\xe6\x99\xd4\xaa\xc8\xaa\x7a\x2e\x85\x5d\x46\x98\x7d\x08\xab\xc0\xa0\x62\xf9\x8a\x15\x08\x4e\x83\x5b\x22\x18\x2c\x84\x75\x66\x0b\x16\x1d\x08\x05\xff\x7d\x31\xdb\xd8\x55\x65\x74\x65\x67\xa9\xd0\x06\x2b\x6d\x5c\x04\xf9\xca\x2f\x5a\xd0\x0a\x38\x56\x52\x6f\x91\x03\x2a\x27\x9c\x40\x0b\x5f\x89\x19\xce\xce\xe0\
x43\x90\xc9\x9e\xc1\xeb\x9c\xf6\xd9\x33\xb8\x31\xa2\x28\xd0\xd8\x33\xb8\xaa\x25\xad\xa0\xcb\x67\x5f\x03\xb3\xb0\x41\x29\xe9\xff\x06\x73\x54\xce\xef\x58\x7b\x34\x4b\xf2\x93\x4e\xb6\xc2\x5c\x2c\x04\x72\x50\xac\x44\x5b\xb1\x1c\xd3\x75\xd1\x3a\xa6\xc9\x6b\x70\x5a\x4b\x32\x5c\x50\xe4\x0c\x6a\x15\x7e\x01\x53\x1c\xec\x56\xe5\xa0\x2b\x54\x9b\xa5\xb0\xab\xd6\xce\x16\x6a\x2b\x54\x01\x0c\x4a\xa6\xc4\x02\xad\xf3\xc4\xba\x22\xae\x4c\x36\xac\x4a\xd2\x64\x21\x64\x47\xfe\xcb\xeb\x77\x3f\xa6\xc8\x6c\x97\xda\xb8\x53\x7c\xcf\x3a\xcf\xa7\xc3\x8c\xfa\xf9\x83\xd1\x6b\xc1\xd1\x02\x03\x5b\x97\x25\x33\x5b\x08\xf4\xa0\x17\xb0\x59\x32\xf7\xcc\xc2\x1c\x71\x70\x0a\xbe\xcc\x5b\x8d\x48\x93\xee\xa2\x73\xed\x34\x2c\x51\x56\x0d\x34\x6c\x75\x6d\x92\x3c\x45\x1e\x49\x97\x85\x71\x1e\x13\x85\x73\x60\x0a\x98\x3f\xdc\x67\xb0\x40\xe4\x67\xe0\xc2\x09\x07\x6d\xc0\xd4\xb2\xbb\x90\x2d\xf8\x31\xb0\x99\xbf\x50\xdb\x31\xf4\x17\x4c\xc1\xfd\xfd\x6c\x85\xdb\xdd\xee\x10\xca\xeb\x99\x8c\xb7\x46\x63\x89\x73\xec\x18\x08\xe5\x3c\xf7\x86\x
0e\x54\x5d\xce\x49\xcd\x05\x6c\xec\x2a\x78\x60\x1c\x6b\x21\x59\x91\xb1\x4a\x64\x4b\x6d\x63\xce\x0d\x9e\x7b\xfd\xe1\x02\x3e\x7d\x7f\x79\x7d\xf3\x29\x91\xe3\xb8\xec\x03\xa6\x3f\xbd\xbd\xba\xbe\xb8\x7c\x9f\xc4\xb7\x76\xcb\x6c\x85\x31\xeb\xd3\xb2\x36\xe2\x77\xff\x07\xf8\xf4\xc3\xdb\x5f\x52\x98\xe6\x68\x5c\xe6\xdd\xf2\x38\xd7\x8a\xb9\x25\x99\x94\x0c\x3d\x23\xe2\x04\x1f\x06\xc6\x5a\x2d\x44\x2c\xe5\x84\x45\xcf\x0a\xbe\xe2\xb8\x60\xb5\x74\x20\x2c\xfc\xe5\xfb\xcb\x77\x6f\xfb\xc4\xf0\x75\x8a\x55\xa4\xd4\x9b\xac\xe1\x11\x4b\x94\x9e\x08\x3a\xa2\x69\xae\x7d\xb4\x1c\xb3\x4b\x17\xa1\xbb\xb0\x9a\xc0\x5a\x28\x87\x86\x6e\xe8\x3a\x66\xf3\x20\xed\x80\x0e\x2a\xa3\xcb\x2a\x49\xf0\x15\x6e\x93\xdd\xb9\xc2\x6d\xaa\xd0\xc1\xca\x25\x53\xac\xc0\x58\xf0\x09\x62\x57\x46\xff\x86\xb9\xeb\x53\xaf\xd3\x30\xa7\x10\x60\x56\xc8\xa1\xe5\x30\x8d\xd8\x85\xa7\x71\xfb\x1f\x11\x5a\x3c\xdb\x2e\xf4\x47\xf8\xf6\xeb\xd3\xbc\x1a\x55\x27\x24\xb4\x68\xd6\x68\x24\x5a\xdb\xda\x26\x81\xb5\x75\x46\x44\x39\x07\x43\xd7\x16\x0d\x1d\x69\xa
1\x90\x83\xa9\x95\x13\x65\x17\x0b\x13\x10\x9c\x2e\x0a\x89\x19\xa5\xab\x08\xcc\x8d\xa7\x80\xef\x29\xa1\x95\x68\x2d\x2b\xd2\x4f\xca\x1a\xcd\x5c\xdb\x98\x91\x9b\x55\xd0\xb5\xab\xea\x31\x73\xf8\x30\x91\x95\xc2\x52\xc2\xf4\x01\x30\x1e\xff\x6e\x96\x08\x44\x41\x07\x2f\x0f\x41\x90\x0e\xb8\xb0\xa0\xb4\x83\xc0\xaa\x36\xc8\x67\xbf\x8e\x99\xe7\x00\xb1\x12\x23\xb9\x81\x10\x29\x88\x13\xc9\x97\xe1\x4c\x9d\x4a\x42\xea\x68\x4e\x83\x6a\x54\x19\xeb\x48\x0e\xf5\xf9\x78\x7f\x3f\xa3\xdf\xbb\xdd\xdd\x19\x2c\x8c\x2e\x29\xb1\x5b\x5d\x9b\x1c\x77\xbb\x24\xcc\xe0\xb0\x29\x4c\x22\x6b\x7d\x65\xd1\x9d\x86\xd5\x99\x67\x0a\x6d\xcf\x8e\xa4\x62\xf7\x87\xd3\xf5\xac\x44\xb1\xc9\x98\x6f\xc6\x32\xa7\x57\xa8\x26\x55\xa6\x1d\x10\x76\x80\xdf\x71\x9a\xf2\xb5\x2a\x99\xb1\x4b\x26\x65\x26\x75\xce\x64\x04\xf2\xb6\x25\x83\xcb\x0a\xd5\xcf\xbe\xfc\x20\x09\x03\x98\xdf\x09\x6b\x26\x6b\xb4\xa9\x68\x0a\xdd\x46\x9b\xd5\x49\x78\x3e\xb3\x29\x74\xa3\x58\x7d\x62\xcd\x72\xa6\x72\x94\x32\x9a\x78\x2e\x7f\x98\xc1\xbf\x02\x0d\xd5\xd5\xfd\xce\x54
\x80\x05\x13\x71\xee\x6f\xfa\x0c\xcf\x05\x6f\x6e\x5e\x59\x49\x74\x08\xb6\x26\x07\x2e\x6a\x29\xb7\x33\xb8\xaa\x15\x7c\xea\x4a\xcf\xae\x67\xfb\x44\x49\xc0\x60\xa9\x29\x8f\x33\xe3\x04\x93\x72\xdb\x37\x27\xcc\x5a\x74\xe3\x66\x1f\x48\x1a\x3a\x9d\xcc\x3a\xe6\xea\x58\xb1\xf3\xfc\xf9\xf3\xe7\xe7\xe7\xe7\xe7\x03\xdb\x0f\x74\xb8\xf6\x5b\x81\x08\x88\x30\x09\xd5\x4f\x21\x90\xa7\x98\xa8\x35\x0d\x87\x66\x74\x11\x8c\x33\x7e\xaa\x4e\xf7\xf5\x70\x6f\x3a\xc8\xa8\xbf\x6f\x07\x94\xe3\x1e\x4f\xc6\x9b\xb2\xdf\x1e\xe4\x09\x16\x6c\x8b\xa0\xcc\x37\x96\xd3\xc5\xeb\xad\xef\x3f\x29\xf6\x51\x91\xb2\xdb\xdd\xc1\x42\x9b\xd4\x7b\x73\x00\x36\x54\xf4\x28\xb8\x64\xd7\x85\x9e\x33\x6b\x6f\xcc\xc4\x4c\xac\xeb\x3d\xdb\xd0\x4e\x78\x4b\xd6\xcc\x04\x86\x26\xed\xee\x60\x3a\x7a\x7c\x88\xf6\xa6\x5d\x87\x47\x05\x98\xcd\x46\xda\xfb\x06\xa2\x35\xc8\x1f\xa9\x62\xcf\x33\x45\xc9\x96\x3a\xae\xe6\x6d\x4f\x71\x82\xa2\x1c\x2b\x54\x1c\x55\x7e\x8c\x3d\xfb\x4d\x43\xa0\xe3\x70\xfa\x5b\x18\x35\xea\x9b\x47\x61\xbe\xe4\xe4\x3c\x2e\x05\xc5\x9e\
xda\xc4\x0a\xbd\x41\x24\xd5\x8b\x88\xea\xff\xc7\x34\xd4\xea\x73\xdc\x41\xf9\x32\x0f\x3e\x8c\xa4\x7f\x8c\x0f\x13\xaf\x46\x4c\x92\x71\x3f\xee\x45\xf4\x13\x3d\x39\x11\x84\xa9\x8f\x3e\x35\xad\x79\x89\x42\x92\xe9\xfa\xf4\x31\x59\x80\xd7\x86\x3c\xd9\xc0\x0e\x53\xc5\x9f\x77\xde\x5a\x1d\x17\xba\x56\x3c\x6b\xe4\x1d\x9f\x40\xbe\x21\xa2\x68\x6c\xda\x2c\x45\xbe\x84\x8d\x1f\xe9\x93\x5c\x3c\x94\xa3\x6e\x89\x90\xd7\xc6\x90\x61\x5a\x05\xdb\x29\x86\x4f\x5a\xe1\x37\x71\x60\xd6\xeb\x42\xf6\x4b\x4e\x5f\x61\x76\x33\xd1\x4a\xfe\xaa\x3e\x48\x64\xd6\x4f\x7a\xd6\x82\xa3\x17\x8a\xe8\x49\x76\x9f\x2e\xbb\x62\xee\x15\x4c\x63\x8d\x36\xca\x0f\xb0\x98\x3a\x6c\x9c\x7d\x47\x92\x00\xd4\x4c\x59\x23\xce\xd0\xb0\xd5\x35\x18\xf4\x9e\xdf\x30\xe5\xfa\x81\x19\xb8\xa5\xb0\xff\x80\xaf\xb6\x2f\xde\x7f\x9d\x80\x33\xd5\x1f\x3f\x54\x69\xd0\xe6\x7d\x6c\x07\x8c\xbe\xc3\xa1\x3e\xab\xa8\xd1\xba\xbb\x04\xdc\xd6\xc9\x47\x69\xd8\x3d\xd6\x24\xe8\xf8\xf6\xea\xea\xf2\xea\x3a\xc2\xfe\xfc\xf0\x3f\x08\xe4\xf0\x60\xe1\xfc\x7c\x24\xb7\x1b\xb3\x
1f\xc4\x56\x4a\x6f\x54\xe6\xb6\xd5\x48\x12\x6a\x83\x15\x51\x91\xc5\x9a\x5d\x33\xe8\x67\xeb\xa0\x95\xdc\x82\xad\xab\xf0\xec\xf6\xc2\x0f\xb5\x67\x76\x6b\x1d\x96\x30\x17\x8a\x0b\x55\x58\xd0\x06\x0a\xe1\x96\xf5\x7c\x96\xeb\xb2\x7b\x01\x19\x2f\x46\x82\xc0\x6d\x54\x23\x47\x66\x4a\xbb\x10\x07\x46\x7a\xea\x47\xef\xbc\x50\x87\x23\x5a\x1f\xe4\x3c\x2f\x5a\xdc\x7f\x82\x99\x12\xab\xa9\x93\x72\x83\xcc\xc5\xac\xe7\x1f\x86\xc1\x93\xec\x45\xa2\x8d\x70\x4b\xf0\x2f\xca\xed\x34\xed\x15\x2d\xa2\x31\xbb\x9d\x7f\xaa\x0b\x6b\xb9\xe6\x61\x81\x7e\x4c\x74\xff\x03\x91\x42\x78\x1c\x15\x89\x3f\x08\x8e\x7f\x92\x48\x0b\x44\x9e\x09\xb5\xd6\xab\x98\x40\xff\xf6\x99\x8a\x2e\x4b\x20\xf3\xe1\x8e\xb6\xc1\x66\xe9\x5f\xee\x1a\x49\xdb\xa7\xab\xb0\xf4\xe7\x48\xbb\xc2\x6d\x37\x87\x2b\x99\xe2\xcc\x69\x33\x36\x63\xec\x68\xfc\xc8\xea\x63\x6b\xcc\x3b\xba\x26\x0d\x9f\x49\xcc\xae\x87\x9a\x3a\xd7\xef\x86\xc7\x73\x70\x72\x99\x03\x3f\x5f\x1e\x34\x55\x93\xa0\xfe\x22\x95\xc2\x96\xcc\xe5\xb1\x27\xdc\xbd\x7b\x44\x1b\xb8\x87\xe0\x23\xd7\xc
9\xaf\xb7\x8d\x1d\xd7\x18\x86\x93\x1e\xc4\xbb\xd5\x67\x30\x22\x2a\x07\x4c\xf6\xae\x5d\x58\x6d\xd5\x18\x57\xa2\x19\x74\xd3\xf1\x62\x52\xc4\xcc\x76\x11\x56\x29\xfa\x34\x2e\xe9\x26\xe4\x84\xd5\xfc\x26\x59\xfa\x47\xe1\x3d\xa9\xb4\xf1\xb2\x87\x87\x54\xbf\x27\xfc\x4c\xb1\x73\x2b\xe2\x84\xa9\xaf\x8e\x11\xe8\xc0\xae\xfe\x2a\x04\x89\x9e\x59\x08\x93\xc2\x60\x4a\xfc\xec\x50\xd9\x56\x68\xfc\xec\xda\x76\xfb\x4b\x54\xb1\x59\x81\xb1\xca\xa5\xbf\xca\x05\x86\xf7\xd8\x26\x25\xf4\xaf\x12\x36\xd4\x59\xfd\x38\xca\xa2\x59\x8b\x7c\x70\x7d\x27\x05\xa9\x8d\x3c\xde\xe5\xf7\xf7\xb3\xda\x48\x4a\x61\xbb\x1d\xdc\x5e\xfd\xe8\x95\xaf\x8d\x6c\xce\x20\xfd\x8b\x6c\x16\x08\xee\xd2\x32\x00\x09\x52\x32\xb9\xd0\xa6\x8c\x96\xda\xef\xda\xf5\x31\x09\x66\x70\x63\xb6\xc0\x0a\x26\xd4\x6c\x36\x09\xfb\x9b\xd5\xaa\x8b\x52\x79\xc9\x47\xde\x81\xff\x73\x7d\xf9\x1e\x84\xaa\x6a\x07\x9c\x39\x06\xef\x1a\x6b\x3c\xcb\x4b\xfe\x8c\x62\xd6\x38\x12\xab\x44\x07\xb4\xc1\x79\x16\x0e\x4b\xec\xc5\xff\x91\x43\xd5\x3e\x4f\x30\xd8\xe0\xbc\xfb\x14\xe1
\xf5\x87\x8b\x40\x56\x09\xa2\xc9\x99\x0a\xf5\xc3\x1c\x43\xaa\x44\xde\x7c\x15\xd1\x6f\x9a\x41\x53\xd4\xd5\x15\x67\xee\xe0\x2b\x02\x3a\x70\xb9\x56\x6b\x34\xee\x00\xde\xe9\x21\x8f\x29\xc3\x0e\xd5\x3d\x49\xd5\xf6\xb0\xf9\x23\xbe\x27\x62\x92\xd2\x73\x66\x91\x83\x56\xc3\x70\xf3\x90\xd5\xa4\x29\x84\xca\x65\xcd\xf1\x40\x3c\x66\xf7\xbc\x10\x35\xc6\xcf\xaf\xaf\xde\x5f\xbc\xff\x2e\xbd\x0e\x6d\x37\x1c\x57\x89\x6e\x98\x51\x59\xae\x4b\xca\xa0\x99\x41\x17\x4d\xb3\x57\xb4\xd6\xce\x0c\xf3\x92\x7b\x5d\x16\x0e\x4d\x48\xf1\xaf\x42\x6c\xa3\xc0\x71\x37\xe6\xdf\x06\xcf\x3f\xd1\x1c\x1d\x3c\x86\x9f\x28\x0c\x47\x97\x1c\x1d\xe6\x6e\x62\x68\xe0\x91\xa9\xb0\xe0\x58\x19\xcc\xc9\xd3\x99\xc1\x4a\xb2\x3c\x1a\x34\x28\xf3\x12\x8e\x96\xbc\xa9\x27\xfc\x8b\x58\x38\x18\x7b\x91\x2a\xc8\xb4\x11\x52\x82\xd5\x5a\xd1\x69\xea\x61\xce\xa0\x6a\x4e\x8a\x0d\x55\x95\x2f\x86\x71\xb3\xc7\xd3\x3a\x64\x89\x0a\x34\xe6\x38\xa5\x1e\xb2\x4b\x5d\x4b\x4e\xe2\x59\x74\x33\x08\x53\xe0\xfd\x5e\x8c\xa8\xfd\xaf\x30\x0f\x4a\x92\xc8\xd3\x4f\xf8\x93\
xe4\x0a\x08\x94\xfa\x1e\xd6\x69\x14\x9f\xfc\xfe\x63\x20\xa9\x56\xb3\x6c\x3d\xea\xc1\x29\x50\xbf\xbf\xf5\x6a\x3b\x74\x68\x3f\x60\x1a\x7e\xb9\x34\x2d\x98\x14\xa5\x70\x99\x28\x94\x36\x51\x91\xda\x73\xdd\x04\x16\xbf\xc5\x4b\xe5\x7f\x1d\xd6\x62\xc2\x42\xc3\x2e\x15\x3d\x5f\x32\x55\x20\x9b\x47\xbf\x37\xf9\xb1\x43\xec\x8a\x3f\xdb\xea\x2d\xb7\x61\xde\xd4\xf1\x98\xc1\x05\xc1\x53\x01\x9d\x70\x16\xbc\x04\x36\x93\xba\xc8\xac\xf8\x3d\x26\x80\xd4\xc5\xb5\xf8\x1d\xc9\xb6\x61\xc3\x9e\xc6\xfd\x11\x65\xca\x3f\x4b\x52\xb3\x31\x47\xb7\x41\x54\xf0\xd2\x37\x15\xdf\xbc\x4c\x16\xa5\xc4\x52\x9b\xed\x98\x34\x81\xe2\x54\x81\xbe\xf9\xf6\xef\x5e\xa4\xbf\x7d\xf3\x6d\xb2\x4c\x54\x7f\xe9\x3a\x56\xbc\x35\xab\x27\x09\xf3\x32\xd8\xe7\xaf\x2f\xe9\xbf\x69\x79\xfc\x78\x20\xab\x8c\xae\xd0\x38\x81\xb1\x11\x6e\x1b\x06\x07\xf1\x2a\x0c\xec\x9c\x11\xd8\x8d\xec\xc2\xac\xa1\x67\xd6\x8e\xf6\x1e\x8f\x89\x6d\x48\xe4\xda\x1f\x38\x8a\x8c\xc2\x81\xae\x9d\x15\xdc\x3b\xe2\xc6\xb0\xb5\xb0\x30\xaf\x85\xe4\xe3\xb3\x09\xaf\x4a\x08\x07\x86\x
8e\x6d\x52\x28\xe8\x4e\xff\x5e\x40\x50\x07\x51\xbd\xb1\xb6\x9f\xb8\xdc\xdf\xcf\x9a\xbf\xb6\xe6\xa6\x0e\x49\xa8\xa6\xd1\xa5\x7f\xb0\x7c\xa2\x6c\xf6\xa2\xb6\xbd\x48\xb8\x64\xb1\x30\xd1\xb6\x22\x0d\x15\x15\x14\x07\x5d\xc9\x23\x65\x4a\xb4\xf1\x38\xa9\xdb\xf0\xd2\x36\xb3\x0c\xdf\xa8\xe2\x67\x61\xa3\xdf\xf3\x3d\x68\x53\xf7\x42\x0c\x93\x06\x19\xdf\x42\x60\xd1\xd5\x4e\x16\x25\xe6\x0e\x98\xd2\x6e\x89\xc6\x6f\x8b\x8a\xf4\xe6\xed\x3f\x6f\xbf\x4b\x2e\x87\x3c\xf5\x71\xb5\x10\x9f\x87\x6f\xf5\xd6\x68\xc4\x22\x56\x07\xfd\xe4\x17\x9b\x56\xe6\xe1\x11\x6a\xf4\x1b\x8f\x95\x04\xd4\x3d\xc5\x84\x37\xdb\xc9\x27\x37\x4f\xf5\x6a\x8a\xeb\xe0\x11\x68\x94\xef\xf0\x29\x28\x8d\xb3\x45\x66\xf2\x25\xf1\x6d\x66\xef\x19\x17\x06\xf3\x91\xc1\xcc\x75\xbb\xa3\x9b\xdc\x77\x3b\x1e\x3c\x3c\xf7\x16\xec\x4d\xf7\xe4\xee\xc9\xff\x02\x00\x00\xff\xff\x3d\xdc\x82\x73\x09\x32\x00\x00")
func wski18nResourcesEn_usAllJsonBytes() ([]byte, error) {
return bindataRead(
@@ -112,7 +129,7 @@ func wski18nResourcesEn_usAllJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 12172, mode: os.FileMode(420), modTime: time.Unix(1516809631, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 12809, mode: os.FileMode(420), modTime: time.Unix(1518160471, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -132,7 +149,7 @@ func wski18nResourcesEs_esAllJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/es_ES.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1515697090, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/es_ES.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1501631495, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -152,7 +169,7 @@ func wski18nResourcesFr_frAllJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/fr_FR.all.json", size: 101, mode: os.FileMode(420), modTime: time.Unix(1515697090, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/fr_FR.all.json", size: 101, mode: os.FileMode(420), modTime: time.Unix(1501631495, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -172,7 +189,7 @@ func wski18nResourcesIt_itAllJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/it_IT.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1515697090, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/it_IT.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1501631495, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -192,7 +209,7 @@ func wski18nResourcesJa_jaAllJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/ja_JA.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1515697090, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/ja_JA.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1501631495, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -212,7 +229,7 @@ func wski18nResourcesKo_krAllJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/ko_KR.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1515697090, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/ko_KR.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1501631495, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -232,7 +249,7 @@ func wski18nResourcesPt_brAllJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/pt_BR.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1515697090, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/pt_BR.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1501631495, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -252,7 +269,7 @@ func wski18nResourcesZh_hansAllJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/zh_Hans.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1515697090, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/zh_Hans.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1501631495, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -272,7 +289,7 @@ func wski18nResourcesZh_hantAllJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/zh_Hant.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1515697090, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/zh_Hant.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1501631495, 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 99aede82..d6b81b49 100644
--- a/wski18n/resources/en_US.all.json
+++ b/wski18n/resources/en_US.all.json
@@ -139,6 +139,10 @@
"id": "msg_config_namespace_info",
"translation": "The namespace is [{{.namespace}}], from {{.source}}.\n"
},
+ {
+ "id": "msg_config_apigw_access_token_info",
+ "translation": "The apigw access token is set, from {{.source}}.\n"
+ },
{
"id": "msg_unmarshall_local",
"translation": "Unmarshal OpenWhisk info from local values.\n"
@@ -311,6 +315,14 @@
"id": "msg_err_json_missing_cmd_key",
"translation": "JSON input data Missing 'cmd' key"
},
+ {
+ "id": "msg_err_api_missing_web_action",
+ "translation": "Action [{{.action}}] is not a web action, API [{{.api}}] can only be created using web action. Please update manifest file to convert [{{.action}}] to web action.\n"
+ },
+ {
+ "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": "WARNINGS",
"translation": "================= WARNINGS ==================="
----------------------------------------------------------------
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