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

[incubator-openwhisk-cli] 01/04: Allow docker actions with zip files. (#2112)

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

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

commit 6c534d1c71166a03def3fff39f690d3731858b39
Author: rodric rabbah <ro...@gmail.com>
AuthorDate: Sat Jun 17 11:54:29 2017 -0400

    Allow docker actions with zip files.  (#2112)
    
    * Allow docker actions with zip files.
    Add native action for binary injection.
    Add note about breaking change for --docker option.
    
    * Separate dep fetching from rest of build to avoid repeated fetches when none changed.
---
 commands/action.go               | 89 +++++++++++++++++++++++++---------------
 commands/flags.go                | 41 ++++++++++--------
 wski18n/resources/en_US.all.json | 20 ++++-----
 3 files changed, 88 insertions(+), 62 deletions(-)

diff --git a/commands/action.go b/commands/action.go
index 2d8103f..8ba3633 100644
--- a/commands/action.go
+++ b/commands/action.go
@@ -58,10 +58,10 @@ var actionCreateCmd = &cobra.Command{
 
         if whiskErr := checkArgs(
             args,
-            2,
+            1,
             2,
             "Action create",
-            wski18n.T("An action name and action are required.")); whiskErr != nil {
+            wski18n.T("An action name and code artifact are required.")); whiskErr != nil {
                 return whiskErr
         }
 
@@ -94,11 +94,11 @@ var actionUpdateCmd = &cobra.Command{
             1,
             2,
             "Action update",
-            wski18n.T("An action name is required. An action is optional.")); whiskErr != nil {
+            wski18n.T("An action name is required. A code artifact is optional.")); whiskErr != nil {
                 return whiskErr
         }
 
-        if action, err = parseAction(cmd, args, false); err != nil {
+        if action, err = parseAction(cmd, args, true); err != nil {
             return actionParseError(cmd, args, err)
         }
 
@@ -321,7 +321,6 @@ var actionListCmd = &cobra.Command{
 
 func parseAction(cmd *cobra.Command, args []string, update bool) (*whisk.Action, error) {
     var err error
-    var artifact string
     var existingAction *whisk.Action
     var paramArgs []string
     var annotArgs []string
@@ -334,10 +333,6 @@ func parseAction(cmd *cobra.Command, args []string, update bool) (*whisk.Action,
         return nil, parseQualifiedNameError(args[0], err)
     }
 
-    if len(args) == 2 {
-        artifact = args[1]
-    }
-
     client.Namespace = qualifiedName.namespace
     action := new(whisk.Action)
     action.Name = qualifiedName.entityName
@@ -387,11 +382,20 @@ func parseAction(cmd *cobra.Command, args []string, update bool) (*whisk.Action,
         action.Parameters = append(action.Parameters, existingAction.Parameters...)
         action.Annotations = append(action.Annotations, existingAction.Annotations...)
     } else if Flags.action.sequence {
-        action.Exec = new(whisk.Exec)
-        action.Exec.Kind = "sequence"
-        action.Exec.Components = csvToQualifiedActions(artifact)
-    } else if len(artifact) > 0 {
-        action.Exec, err = getExec(args[1], Flags.action.kind, Flags.action.docker, Flags.action.main)
+        if len(args) == 2 {
+            action.Exec = new(whisk.Exec)
+            action.Exec.Kind = "sequence"
+            action.Exec.Components = csvToQualifiedActions(args[1])
+        } else {
+            return nil, noArtifactError()
+        }
+    } else if len(args) > 1 || len(Flags.action.docker) > 0 {
+        action.Exec, err = getExec(args, Flags.action)
+        if err != nil {
+            return nil, err
+        }
+    } else if !update {
+        return nil, noArtifactError()
     }
 
     if cmd.LocalFlags().Changed(WEB_FLAG) {
@@ -403,39 +407,48 @@ func parseAction(cmd *cobra.Command, args []string, update bool) (*whisk.Action,
     return action, err
 }
 
-func getExec(artifact string, kind string, isDocker bool, mainEntry string) (*whisk.Exec, error) {
+func getExec(args []string, params ActionFlags) (*whisk.Exec, error) {
     var err error
     var code string
     var exec *whisk.Exec
 
-    ext := filepath.Ext(artifact)
     exec = new(whisk.Exec)
+    kind := params.kind
+    isNative := params.native
+    docker := params.docker
+    mainEntry := params.main
+    ext := ""
 
-    if !isDocker || ext == ".zip" {
+    if len(args) == 2 {
+        artifact := args[1]
+        ext = filepath.Ext(artifact)
         code, err = ReadFile(artifact)
 
+        if err != nil {
+            whisk.Debug(whisk.DbgError, "ReadFile(%s) error: %s\n", artifact, err)
+            return nil, err
+        }
+
         if ext == ".zip" || ext == ".jar" {
             // Base64 encode the file
             code = base64.StdEncoding.EncodeToString([]byte(code))
-            exec.Code = &code
-        } else {
-            exec.Code = &code
         }
 
-        if err != nil {
-            whisk.Debug(whisk.DbgError, "readFile(%s) error: %s\n", artifact, err)
-            return nil, err
-        }
+        exec.Code = &code
+    } else if len(args) == 1 && len(docker) == 0 {
+        return nil, noArtifactError()
+    } else if len(args) > 1 {
+        return nil, noArtifactError()
     }
 
     if len(kind) > 0 {
         exec.Kind = kind
-    } else if isDocker {
+    } else if len(docker) > 0 || isNative {
         exec.Kind = "blackbox"
-        if ext != ".zip" {
-            exec.Image = artifact
-        } else {
+        if isNative {
             exec.Image = "openwhisk/dockerskeleton"
+        } else {
+            exec.Image = docker
         }
     } else if ext == ".swift" {
         exec.Kind = "swift:default"
@@ -574,7 +587,7 @@ func nestedError(errorMessage string, err error) (error) {
 func nonNestedError(errorMessage string) (error) {
     return whisk.MakeWskError(
         errors.New(errorMessage),
-        whisk.EXITCODE_ERR_GENERAL,
+        whisk.EXITCODE_ERR_USAGE,
         whisk.DISPLAY_MSG,
         whisk.DISPLAY_USAGE)
 }
@@ -583,9 +596,9 @@ func actionParseError(cmd *cobra.Command, args []string, err error) (error) {
     whisk.Debug(whisk.DbgError, "parseAction(%s, %s) error: %s\n", cmd, args, err)
 
     errMsg := wski18n.T(
-        "Unable to parse action command arguments: {{.err}}",
+        "Invalid argument(s). {{.required}}",
         map[string]interface{}{
-            "err": err,
+            "required": err,
         })
 
     return nestedError(errMsg, err)
@@ -726,6 +739,12 @@ func zipKindError() (error) {
     return nonNestedError(errMsg)
 }
 
+func noArtifactError() (error) {
+    errMsg := wski18n.T("An action name and code artifact are required.")
+
+    return nonNestedError(errMsg)
+}
+
 func extensionError(extension string) (error) {
     errMsg := wski18n.T(
         "'{{.name}}' is not a supported action runtime",
@@ -875,21 +894,23 @@ func isWebAction(client *whisk.Client, qname QualifiedName) error {
 }
 
 func init() {
-    actionCreateCmd.Flags().BoolVar(&Flags.action.docker, "docker", false, wski18n.T("treat ACTION as docker image path on dockerhub"))
+    actionCreateCmd.Flags().BoolVar(&Flags.action.native, "native", false, wski18n.T("treat ACTION as native action (zip file provides a compatible executable to run)"))
+    actionCreateCmd.Flags().StringVar(&Flags.action.docker, "docker", "", wski18n.T("use provided docker image (a path on DockerHub) to run the action"))
     actionCreateCmd.Flags().BoolVar(&Flags.action.copy, "copy", false, wski18n.T("treat ACTION as the name of an existing action"))
     actionCreateCmd.Flags().BoolVar(&Flags.action.sequence, "sequence", false, wski18n.T("treat ACTION as comma separated sequence of actions to invoke"))
     actionCreateCmd.Flags().StringVar(&Flags.action.kind, "kind", "", wski18n.T("the `KIND` of the action runtime (example: swift:default, nodejs:default)"))
     actionCreateCmd.Flags().StringVar(&Flags.action.main, "main", "", wski18n.T("the name of the action entry point (function or fully-qualified method name when applicable)"))
     actionCreateCmd.Flags().IntVarP(&Flags.action.timeout, "timeout", "t", TIMEOUT_LIMIT, wski18n.T("the timeout `LIMIT` in milliseconds after which the action is terminated"))
     actionCreateCmd.Flags().IntVarP(&Flags.action.memory, "memory", "m", MEMORY_LIMIT, wski18n.T("the maximum memory `LIMIT` in MB for the action"))
-    actionCreateCmd.Flags().IntVarP(&Flags.action.logsize, "logsize", "l", LOGSIZE_LIMIT, wski18n.T("the maximum log size `LIMIT` in MB for the action"))
+    actionCreateCmd.Flags().IntVarP(&flags.action.logsize, "logsize", "l", LOGSIZE_LIMIT, wski18n.T("the maximum log size `LIMIT` in MB for the action"))
     actionCreateCmd.Flags().StringSliceVarP(&Flags.common.annotation, "annotation", "a", nil, wski18n.T("annotation values in `KEY VALUE` format"))
     actionCreateCmd.Flags().StringVarP(&Flags.common.annotFile, "annotation-file", "A", "", wski18n.T("`FILE` containing annotation values in JSON format"))
     actionCreateCmd.Flags().StringSliceVarP(&Flags.common.param, "param", "p", nil, wski18n.T("parameter values in `KEY VALUE` format"))
     actionCreateCmd.Flags().StringVarP(&Flags.common.paramFile, "param-file", "P", "", wski18n.T("`FILE` containing parameter values in JSON format"))
     actionCreateCmd.Flags().StringVar(&Flags.action.web, "web", "", wski18n.T("treat ACTION as a web action, a raw HTTP web action, or as a standard action; yes | true = web action, raw = raw HTTP web action, no | false = standard action"))
 
-    actionUpdateCmd.Flags().BoolVar(&Flags.action.docker, "docker", false, wski18n.T("treat ACTION as docker image path on dockerhub"))
+    actionUpdateCmd.Flags().BoolVar(&Flags.action.native, "native", false, wski18n.T("treat ACTION as native action (zip file provides a compatible executable to run)"))
+    actionUpdateCmd.Flags().StringVar(&Flags.action.docker, "docker", "", wski18n.T("use provided docker image (a path on DockerHub) to run the action"))
     actionUpdateCmd.Flags().BoolVar(&Flags.action.copy, "copy", false, wski18n.T("treat ACTION as the name of an existing action"))
     actionUpdateCmd.Flags().BoolVar(&Flags.action.sequence, "sequence", false, wski18n.T("treat ACTION as comma separated sequence of actions to invoke"))
     actionUpdateCmd.Flags().StringVar(&Flags.action.kind, "kind", "", wski18n.T("the `KIND` of the action runtime (example: swift:default, nodejs:default)"))
diff --git a/commands/flags.go b/commands/flags.go
index d40e2aa..5695be8 100644
--- a/commands/flags.go
+++ b/commands/flags.go
@@ -32,7 +32,9 @@ const WEB_FLAG      = "web"
 
 var cliDebug = os.Getenv("WSK_CLI_DEBUG")  // Useful for tracing init() code
 
-var Flags struct {
+var Flags FlagsStruct
+
+type FlagsStruct struct {
 
     Global struct {
         Verbose    bool
@@ -49,10 +51,10 @@ var Flags struct {
         annotFile   string
         param       []string
         paramFile   string
-        shared      string // AKA "public" or "publish"
-        skip        int  // skip first N records
-        limit       int  // return max N records
-        full        bool // return full records (docs=true for client request)
+        shared      string  // AKA "public" or "publish"
+        skip        int     // skip first N records
+        limit       int     // return max N records
+        full        bool    // return full records (docs=true for client request)
         summary     bool
         feed        string  // name of feed
         detail      bool
@@ -74,19 +76,7 @@ var Flags struct {
         namespaceSet    string
     }
 
-    action struct {
-        docker      bool
-        copy        bool
-        pipe        bool
-        web         string
-        sequence    bool
-        timeout     int
-        memory      int
-        logsize     int
-        result      bool
-        kind        string
-        main        string
-    }
+    action ActionFlags
 
     activation struct {
         action          string // retrieve results for this action
@@ -123,6 +113,21 @@ var Flags struct {
     }
 }
 
+
+type ActionFlags struct {
+    docker      string
+    native      bool
+    copy        bool
+    web         string
+    sequence    bool
+    timeout     int
+    memory      int
+    logsize     int
+    result      bool
+    kind        string
+    main        string
+}
+
 func IsVerbose() bool {
     return Flags.Global.Verbose || IsDebug()
 }
diff --git a/wski18n/resources/en_US.all.json b/wski18n/resources/en_US.all.json
index e173b42..7a9b778 100644
--- a/wski18n/resources/en_US.all.json
+++ b/wski18n/resources/en_US.all.json
@@ -688,10 +688,6 @@
     "translation": "Arguments must be comma separated, and must be quoted if they contain spaces."
   },
   {
-    "id": "Invalid arguments: {{.err}}",
-    "translation": "Invalid arguments: {{.err}}"
-  },
-  {
     "id": "The argument `{{.arg}}` is invalid: {{.err}}",
     "translation": "The argument `{{.arg}}` is invalid: {{.err}}"
   },
@@ -872,8 +868,12 @@
     "translation": "Java actions require --main to specify the fully-qualified name of the main class"
   },
   {
-    "id": "treat ACTION as docker image path on dockerhub",
-    "translation": "treat ACTION as docker image path on dockerhub"
+    "id": "treat ACTION as native action (zip file provides a compatible executable to run)",
+    "translation": "treat ACTION as native action (zip file provides a compatible executable to run)"
+  },
+  {
+    "id": "use provided docker image (a path on DockerHub) to run the action",
+    "translation": "use provided docker image (a path on DockerHub) to run the action"
   },
   {
     "id": "treat ACTION as the name of an existing action",
@@ -1048,16 +1048,16 @@
     "translation": "The annotation arguments are invalid: {{.err}}"
   },
   {
-    "id": "An action name and action are required.",
-    "translation": "An action name and action are required."
+    "id": "An action name and code artifact are required.",
+    "translation": "An action name and code artifact are required."
   },
   {
     "id": "An action name is required.",
     "translation": "An action name is required."
   },
   {
-    "id": "An action name is required. An action is optional.",
-    "translation": "An action name is required. An action is optional."
+    "id": "An action name is required. A code artifact is optional.",
+    "translation": "An action name is required. A code artifact is optional."
   },
   {
     "id": "An activation ID is required.",

-- 
To stop receiving notification emails like this one, please contact
"commits@openwhisk.apache.org" <co...@openwhisk.apache.org>.