You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by mr...@apache.org on 2017/09/29 15:37:46 UTC
[incubator-openwhisk-wskdeploy] branch master updated: Add the
support of certificate checking for secure mode (#571)
This is an automated email from the ASF dual-hosted git repository.
mrutkowski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk-wskdeploy.git
The following commit(s) were added to refs/heads/master by this push:
new ab623d4 Add the support of certificate checking for secure mode (#571)
ab623d4 is described below
commit ab623d40936738b8e206cdfb4eff88d39af74401
Author: Vincent <sh...@us.ibm.com>
AuthorDate: Fri Sep 29 11:37:43 2017 -0400
Add the support of certificate checking for secure mode (#571)
Closes #560
Closes #565
---
Godeps/Godeps.json | 4 +-
cmd/root.go | 6 +-
deployers/whiskclient.go | 23 ++++++--
deployers/whiskclient_test.go | 91 +++++++++++++++++++++----------
tests/dat/wskprops | 2 +
tests/dat/{wskprops => wskpropsnokeycert} | 0
utils/flags.go | 2 +
wski18n/i18n_resources.go | 4 +-
wski18n/resources/en_US.all.json | 32 +++++++----
9 files changed, 112 insertions(+), 52 deletions(-)
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index 4fad9ca..0608803 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -105,11 +105,11 @@
},
{
"ImportPath": "github.com/apache/incubator-openwhisk-client-go/whisk",
- "Rev": "c6e512b136e8c27bb144c0f8b625e833fbae878a"
+ "Rev": "cef179c81f07f86413c720623995c17bd1bddd7d"
},
{
"ImportPath": "github.com/apache/incubator-openwhisk-client-go/wski18n",
- "Rev": "c6e512b136e8c27bb144c0f8b625e833fbae878a"
+ "Rev": "cef179c81f07f86413c720623995c17bd1bddd7d"
},
{
"ImportPath": "github.com/pelletier/go-buffruneio",
diff --git a/cmd/root.go b/cmd/root.go
index 400f6f8..acdfbf7 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -37,6 +37,8 @@ var stderr = ""
var stdout = ""
var RootCmd = &cobra.Command{
Use: "wskdeploy",
+ SilenceErrors: true,
+ SilenceUsage: true,
Short: "A tool set to help deploy your openwhisk packages in batch.",
Long: `A tool to deploy openwhisk packages with a manifest and/or deployment yaml file.
@@ -49,8 +51,6 @@ wskdeploy without any commands or flags deploys openwhisk package in the current
}
func RootCmdImp(cmd *cobra.Command, args []string) error {
- cmd.SilenceErrors = true
- cmd.SilenceUsage = true
return Deploy()
}
@@ -119,6 +119,8 @@ func init() {
RootCmd.PersistentFlags().StringVarP(&utils.Flags.Namespace, "namespace", "n", "", wski18n.T("namespace"))
RootCmd.PersistentFlags().StringVarP(&utils.Flags.Auth, "auth", "u", "", wski18n.T("authorization `KEY`"))
RootCmd.PersistentFlags().StringVar(&utils.Flags.ApiVersion, "apiversion", "", wski18n.T("whisk API `VERSION`"))
+ RootCmd.PersistentFlags().StringVarP(&utils.Flags.Key, "key", "k", "", wski18n.T("path of the .key file"))
+ RootCmd.PersistentFlags().StringVarP(&utils.Flags.Cert, "cert", "c", "", wski18n.T("path of the .cert file"))
}
// initConfig reads in config file and ENV variables if set.
diff --git a/deployers/whiskclient.go b/deployers/whiskclient.go
index fece4f7..f0d874b 100644
--- a/deployers/whiskclient.go
+++ b/deployers/whiskclient.go
@@ -60,8 +60,8 @@ var GetWskPropFromWhiskProperty = func(pi whisk.Properties) (*whisk.Wskprops, er
return whisk.GetWskPropFromWhiskProperty(pi)
}
-var GetCommandLineFlags = func() (string, string, string) {
- return utils.Flags.ApiHost, utils.Flags.Auth, utils.Flags.Namespace
+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 CreateNewClient = func (config_input *whisk.Config) (*whisk.Client, error) {
@@ -82,12 +82,16 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
credential := PropertyValue{}
namespace := PropertyValue{}
apiHost := PropertyValue{}
+ key := PropertyValue{}
+ cert := PropertyValue{}
// read credentials from command line
- apihost, auth, ns := GetCommandLineFlags()
+ apihost, auth, ns, keyfile, certfile := GetCommandLineFlags()
credential = GetPropertyValue(credential, auth, COMMANDLINE)
namespace = GetPropertyValue(namespace, ns, COMMANDLINE)
apiHost = GetPropertyValue(apiHost, apihost, COMMANDLINE)
+ key = GetPropertyValue(key, keyfile, COMMANDLINE)
+ cert = GetPropertyValue(cert, certfile, COMMANDLINE)
// now, read them from deployment file if not found on command line
if len(credential.Value) == 0 || len(namespace.Value) == 0 || len(apiHost.Value) == 0 {
@@ -131,6 +135,8 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
credential = GetPropertyValue(credential, wskprops.AuthKey, WSKPROPS)
namespace = GetPropertyValue(namespace, wskprops.Namespace, WSKPROPS)
apiHost = GetPropertyValue(apiHost, wskprops.APIHost, WSKPROPS)
+ key = GetPropertyValue(key, wskprops.Key, WSKPROPS)
+ cert = GetPropertyValue(cert, wskprops.Cert, WSKPROPS)
// 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
@@ -189,12 +195,19 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
}
}
- clientConfig = &whisk.Config{
+ 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",
- Insecure: true, // true if you want to ignore certificate signing
+ Cert: cert.Value,
+ Key: key.Value,
+ Insecure: mode, // true if you want to ignore certificate signing
}
if len(credential.Value) == 0 || len(apiHost.Value) == 0 || len(namespace.Value) == 0 {
diff --git a/deployers/whiskclient_test.go b/deployers/whiskclient_test.go
index 0c5798b..fca9429 100644
--- a/deployers/whiskclient_test.go
+++ b/deployers/whiskclient_test.go
@@ -42,8 +42,19 @@ const (
WSKPROPS_HOST = "openwhisk.ng.bluemix.net"
WSKPROPS_AUTH = "a4f8c502:123zO3xZCLrMN6v2BKK"
WSKPROPS_NAMESPACE = "guest"
+
+ WSKPROPS_KEY = "test_key_file"
+ WSKPROPS_CERT = "test_cert_file"
)
+func initializeFlags() {
+ utils.Flags.Auth = ""
+ utils.Flags.Namespace = ""
+ utils.Flags.ApiHost = ""
+ utils.Flags.Key = ""
+ utils.Flags.Cert = ""
+}
+
func TestNewWhiskConfig(t *testing.T) {
propPath := ""
manifestPath := ""
@@ -74,13 +85,23 @@ func TestNewWhiskConfigCommandLine(t *testing.T) {
config, err := NewWhiskConfig(propPath, deploymentPath, manifestPath, false)
assert.Nil(t, err, "Failed to read credentials from wskdeploy command line")
- assert.Equal(t, config.Host, CLI_HOST, "Failed to get host name from wskdeploy command line")
- assert.Equal(t, config.AuthToken, CLI_AUTH, "Failed to get auth token from wskdeploy command line")
- assert.Equal(t, config.Namespace, CLI_NAMESPACE, "Failed to get namespace from wskdeploy command line")
-
- utils.Flags.Auth = ""
- utils.Flags.Namespace = ""
- utils.Flags.ApiHost = ""
+ assert.Equal(t, CLI_HOST, config.Host, "Failed to get host name from wskdeploy command line")
+ assert.Equal(t, CLI_AUTH, config.AuthToken, "Failed to get auth token from wskdeploy command line")
+ assert.Equal(t, CLI_NAMESPACE, config.Namespace, "Failed to get namespace from wskdeploy command line")
+ assert.True(t, config.Insecure, "Config should set insecure to true")
+
+ utils.Flags.Key = WSKPROPS_KEY
+ utils.Flags.Cert = WSKPROPS_CERT
+ config, err = NewWhiskConfig(propPath, deploymentPath, manifestPath, false)
+ assert.Nil(t, err, "Failed to read credentials from wskdeploy command line")
+ assert.Equal(t, CLI_HOST, config.Host, "Failed to get host name from wskdeploy command line")
+ assert.Equal(t, CLI_AUTH, config.AuthToken, "Failed to get auth token from wskdeploy command line")
+ assert.Equal(t, CLI_NAMESPACE, config.Namespace, "Failed to get namespace from wskdeploy command line")
+ assert.Equal(t, WSKPROPS_KEY, config.Key, "Failed to get key file from wskdeploy command line")
+ assert.Equal(t, WSKPROPS_CERT, config.Cert, "Failed to get cert file from wskdeploy command line")
+ assert.False(t, config.Insecure, "Config should set insecure to false")
+
+ initializeFlags()
}
func TestNewWhiskConfigDeploymentFile(t *testing.T) {
@@ -89,9 +110,10 @@ func TestNewWhiskConfigDeploymentFile(t *testing.T) {
deploymentPath := "../tests/dat/deployment_validate_credentials.yaml"
config, err := NewWhiskConfig(propPath, deploymentPath, manifestPath, false)
assert.Nil(t, err, "Failed to read credentials from deployment file")
- assert.Equal(t, config.Host, DEPLOYMENT_HOST, "Failed to get host name from deployment file")
- assert.Equal(t, config.AuthToken, DEPLOYMENT_AUTH, "Failed to get auth token from deployment file")
- assert.Equal(t, config.Namespace, DEPLOYMENT_NAMESPACE, "Failed to get namespace from deployment file")
+ assert.Equal(t, DEPLOYMENT_HOST, config.Host, "Failed to get host name from deployment file")
+ assert.Equal(t, DEPLOYMENT_AUTH, config.AuthToken, "Failed to get auth token from deployment file")
+ assert.Equal(t, DEPLOYMENT_NAMESPACE, config.Namespace, "Failed to get namespace from deployment file")
+ assert.True(t, config.Insecure, "Config should set insecure to true")
}
func TestNewWhiskConfigManifestFile(t *testing.T) {
@@ -100,9 +122,10 @@ func TestNewWhiskConfigManifestFile(t *testing.T) {
deploymentPath := ""
config, err := NewWhiskConfig(propPath, deploymentPath, manifestPath, false)
assert.Nil(t, err, "Failed to read credentials from manifest file")
- assert.Equal(t, config.Host, MANIFEST_HOST, "Failed to get host name from manifest file")
- assert.Equal(t, config.AuthToken, MANIFEST_AUTH, "Failed to get auth token from manifest file")
- assert.Equal(t, config.Namespace, MANIFEST_NAMESPACE, "Failed to get namespace from manifest file")
+ assert.Equal(t, MANIFEST_HOST, config.Host, "Failed to get host name from manifest file")
+ assert.Equal(t, MANIFEST_AUTH, config.AuthToken, "Failed to get auth token from manifest file")
+ assert.Equal(t, MANIFEST_NAMESPACE, config.Namespace, "Failed to get namespace from manifest file")
+ assert.True(t, config.Insecure, "Config should set insecure to true")
}
@@ -112,9 +135,22 @@ func TestNewWhiskConfigWithWskProps(t *testing.T) {
deploymentPath := ""
config, err := NewWhiskConfig(propPath, deploymentPath, manifestPath, false)
assert.Nil(t, err, "Failed to read credentials from wskprops")
- assert.Equal(t, config.Host, WSKPROPS_HOST, "Failed to get host name from wskprops")
- assert.Equal(t, config.AuthToken, WSKPROPS_AUTH, "Failed to get auth token from wskprops")
- assert.Equal(t, config.Namespace, WSKPROPS_NAMESPACE, "Failed to get namespace from wskprops")
+ assert.Equal(t, WSKPROPS_HOST, config.Host, "Failed to get host name from wskprops")
+ assert.Equal(t, WSKPROPS_AUTH, config.AuthToken, "Failed to get auth token from wskprops")
+ assert.Equal(t, WSKPROPS_NAMESPACE, config.Namespace, "Failed to get namespace from wskprops")
+ assert.Equal(t, WSKPROPS_KEY, config.Key, "Failed to get key file from wskprops")
+ assert.Equal(t, WSKPROPS_CERT, config.Cert, "Failed to get cert file from wskprops")
+ assert.False(t, config.Insecure, "Config should set insecure to false")
+
+ propPath = "../tests/dat/wskpropsnokeycert"
+ config, err = NewWhiskConfig(propPath, deploymentPath, manifestPath, false)
+ assert.Nil(t, err, "Failed to read credentials from wskprops")
+ assert.Equal(t, WSKPROPS_HOST, config.Host, "Failed to get host name from wskprops")
+ assert.Equal(t, WSKPROPS_AUTH, config.AuthToken, "Failed to get auth token from wskprops")
+ assert.Equal(t, WSKPROPS_NAMESPACE, config.Namespace, "Failed to get namespace from wskprops")
+ assert.Empty(t, config.Key, "Failed to get key file from wskprops")
+ assert.Empty(t, config.Cert, "Failed to get cert file from wskprops")
+ assert.True(t, config.Insecure, "Config should set insecure to true")
}
// (TODO) add the following test
@@ -140,10 +176,9 @@ func TestNewWhiskConfigWithCLIDeploymentAndManifestFile(t *testing.T) {
assert.Equal(t, config.Host, CLI_HOST, "Failed to get host name from wskdeploy CLI")
assert.Equal(t, config.AuthToken, CLI_AUTH, "Failed to get auth token from wskdeploy CLI")
assert.Equal(t, config.Namespace, CLI_NAMESPACE, "Failed to get namespace from wskdeploy CLI")
+ assert.True(t, config.Insecure, "Config should set insecure to true")
- utils.Flags.Auth = ""
- utils.Flags.Namespace = ""
- utils.Flags.ApiHost = ""
+ initializeFlags()
}
@@ -161,10 +196,9 @@ func TestNewWhiskConfigWithCLIAndDeployment(t *testing.T) {
assert.Equal(t, config.Host, CLI_HOST, "Failed to get host name from wskdeploy CLI")
assert.Equal(t, config.AuthToken, CLI_AUTH, "Failed to get auth token from wskdeploy CLI")
assert.Equal(t, config.Namespace, CLI_NAMESPACE, "Failed to get namespace from wskdeploy CLI")
+ assert.True(t, config.Insecure, "Config should set insecure to true")
- utils.Flags.Auth = ""
- utils.Flags.Namespace = ""
- utils.Flags.ApiHost = ""
+ initializeFlags()
}
func TestNewWhiskConfigWithCLIAndManifest(t *testing.T) {
@@ -181,14 +215,13 @@ func TestNewWhiskConfigWithCLIAndManifest(t *testing.T) {
assert.Equal(t, config.Host, CLI_HOST, "Failed to get host name from wskdeploy CLI")
assert.Equal(t, config.AuthToken, CLI_AUTH, "Failed to get auth token from wskdeploy CLI")
assert.Equal(t, config.Namespace, CLI_NAMESPACE, "Failed to get namespace from wskdeploy CLI")
+ assert.True(t, config.Insecure, "Config should set insecure to true")
- utils.Flags.Auth = ""
- utils.Flags.Namespace = ""
- utils.Flags.ApiHost = ""
+ initializeFlags()
}
func TestNewWhiskConfigWithCLIAndWskProps(t *testing.T) {
- propPath := "../tests/dat/wskprops"
+ propPath := "../tests/dat/wskpropsnokeycert"
manifestPath := ""
deploymentPath := ""
@@ -200,10 +233,9 @@ func TestNewWhiskConfigWithCLIAndWskProps(t *testing.T) {
assert.Equal(t, config.Host, CLI_HOST, "Failed to get host name from wskdeploy command line")
assert.Equal(t, config.AuthToken, CLI_AUTH, "Failed to get auth token from wskdeploy command line")
assert.Equal(t, config.Namespace, CLI_NAMESPACE, "Failed to get namespace from wskdeploy command line")
+ assert.True(t, config.Insecure, "Config should set insecure to true")
- utils.Flags.Auth = ""
- utils.Flags.Namespace = ""
- utils.Flags.ApiHost = ""
+ initializeFlags()
}
func TestNewWhiskConfigWithDeploymentAndManifestFile(t *testing.T) {
@@ -215,4 +247,5 @@ func TestNewWhiskConfigWithDeploymentAndManifestFile(t *testing.T) {
assert.Equal(t, config.Host, DEPLOYMENT_HOST, "Failed to get host name from deployment file")
assert.Equal(t, config.AuthToken, DEPLOYMENT_AUTH, "Failed to get auth token from deployment file")
assert.Equal(t, config.Namespace, DEPLOYMENT_NAMESPACE, "Failed to get namespace from deployment file")
+ assert.True(t, config.Insecure, "Config should set insecure to true")
}
diff --git a/tests/dat/wskprops b/tests/dat/wskprops
index 2a7e6ec..1e09438 100644
--- a/tests/dat/wskprops
+++ b/tests/dat/wskprops
@@ -1,3 +1,5 @@
AUTH=a4f8c502:123zO3xZCLrMN6v2BKK
APIHOST=openwhisk.ng.bluemix.net
NAMESPACE=guest
+CERT=test_cert_file
+KEY=test_key_file
diff --git a/tests/dat/wskprops b/tests/dat/wskpropsnokeycert
similarity index 100%
copy from tests/dat/wskprops
copy to tests/dat/wskpropsnokeycert
diff --git a/utils/flags.go b/utils/flags.go
index 59ffce0..03390ad 100644
--- a/utils/flags.go
+++ b/utils/flags.go
@@ -33,6 +33,8 @@ var Flags struct {
UseDefaults bool
UseInteractive bool
Strict bool // strict flag to support user defined runtime version.
+ Key string
+ Cert string
//action flag definition
//from go cli
diff --git a/wski18n/i18n_resources.go b/wski18n/i18n_resources.go
index ad153c6..63fef18 100644
--- a/wski18n/i18n_resources.go
+++ b/wski18n/i18n_resources.go
@@ -114,7 +114,7 @@ func wski18nResourcesDe_deAllJson() (*asset, error) {
return a, nil
}
-var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x59\x4d\x6f\xdb\x38\x13\xbe\xfb\x57\x0c\x72\xf1\x25\xd0\x7b\xef\x2d\xe8\xdb\x6d\x83\x6e\xd3\x20\xcd\x6e\x51\x74\x0b\x84\x11\x47\x16\x6b\x8a\x14\x48\xca\x85\x57\xf0\x7f\x5f\x50\x1f\xb6\x93\x90\x14\x25\x7f\xb4\x0b\xec\xcd\xb6\x38\xcf\xf3\x0c\x87\x9c\x0f\xf9\xeb\x0c\xa0\x9e\x01\x00\x5c\x30\x7a\xf1\x0a\x2e\xde\x21\xe7\xf2\xe2\xb2\xfd\xc9\x28\x22\x34\x27\x86\x49\x61\x9f\x5d\x09\xb8\xba\xbd\x86\x5c\x6a\x03 [...]
+var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x41\x6f\xdb\x3c\x12\xbd\xe7\x57\x0c\x72\xf1\x25\xd0\xb6\xdf\x62\x81\x45\x6f\x41\xdb\x6d\x83\xb6\x69\x90\x64\x5b\x14\xdd\x02\x61\xa4\x91\xc5\x9a\x22\x05\x92\x72\xe0\x0a\xfe\xef\x0b\x8a\x92\xed\x24\x14\x45\xc9\xb2\xdb\x05\x36\x27\xc7\xe6\xbc\xf7\x66\x48\x0e\x67\x24\x7e\x3f\x01\xa8\x4e\x00\x00\x4e\x69\x72\xfa\x0a\x4e\xdf\x23\x63\xe2\xf4\xcc\x7e\xa5\x25\xe1\x8a\x11\x4d\x05\x37\xbf\x9d\x73\x38\xbf\xba [...]
func wski18nResourcesEn_usAllJsonBytes() ([]byte, error) {
return bindataRead(
@@ -129,7 +129,7 @@ func wski18nResourcesEn_usAllJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 10738, mode: os.FileMode(420), modTime: time.Unix(1506012886, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 13255, mode: os.FileMode(420), modTime: time.Unix(1506693936, 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 2f6012a..c911a15 100644
--- a/wski18n/resources/en_US.all.json
+++ b/wski18n/resources/en_US.all.json
@@ -274,53 +274,61 @@
{
"id": "Failed to invoke the feed when deleting trigger feed with error message: {{.err}} and error code: {{.code}}.\n",
"translation": "Failed to invoke the feed when deleting trigger feed with error message: {{.err}} and error code: {{.code}}.\n"
- }
+ },
{
"id": "WARNING: Mandatory field Package Version must be set.\n",
"translation": "WARNING: Mandatory field Package Version must be set.\n"
- }
+ },
{
"id": "WARNING: Package Version is not saved in the current wskdeploy version.\n",
"translation": "WARNING: Package Version is not saved in the current wskdeploy version.\n"
- }
+ },
{
"id": "WARNING: Mandatory field Package License must be set.\n",
"translation": "WARNING: Mandatory field Package License must be set.\n"
- }
+ },
{
"id": "WARNING: Package License is not saved in the current wskdeploy version.\n",
"translation": "WARNING: Package License is not saved in the current wskdeploy version.\n"
- }
+ },
{
"id": "WARNING: License {{.licenseID}} is not a valid one.\n",
"translation": "WARNING: License {{.licenseID}} is not a valid one.\n"
- }
+ },
{
"id": "memorySize of limits in manifest should be an integer between 128 and 512.\n",
"translation": "memorySize of limits in manifest should be an integer between 128 and 512.\n"
- }
+ },
{
"id": "timeout of limits in manifest should be an integer between 100 and 300000.\n",
"translation": "timeout of limits in manifest should be an integer between 100 and 300000.\n"
- }
+ },
{
"id": "logSize of limits in manifest should be an integer between 0 and 10.\n",
"translation": "logSize of limits in manifest should be an integer between 0 and 10.\n"
- }
+ },
{
"id": "WARNING: Invalid limitation 'timeout' of action in manifest is ignored. Please check errors.\n",
"translation": "WARNING: Invalid limitation 'timeout' of action in manifest is ignored. Please check errors.\n"
- }
+ },
{
"id": "WARNING: Invalid limitation 'memorySize' of action in manifest is ignored. Please check errors.\n",
"translation": "WARNING: Invalid limitation 'memorySize' of action in manifest is ignored. Please check errors.\n"
- }
+ },
{
"id": "WARNING: Invalid limitation 'logSize' of action in manifest is ignored. Please check errors.\n",
"translation": "WARNING: Invalid limitation 'logSize' of action in manifest is ignored. Please check errors.\n"
- }
+ },
{
"id": "WARNING: Limits {{.limitname}} is not changable as to now, which will be ignored.\n",
"translation": "WARNING: Limits {{.limitname}} is not changable as to now, which will be ignored.\n"
+ },
+ {
+ "id": "path of the .key file",
+ "translation": "path of the .key file"
+ },
+ {
+ "id": "path of the .cert file",
+ "translation": "path of the .cert file"
}
]
--
To stop receiving notification emails like this one, please contact
['"commits@openwhisk.apache.org" <co...@openwhisk.apache.org>'].