From 9b470ef4c05345020f3d7ec1ab21bf222ab55302 Mon Sep 17 00:00:00 2001 From: Gyu-Ho Lee Date: Tue, 1 Nov 2016 19:52:42 -0700 Subject: [PATCH] etcdctl/ctlv2: error handling with JSON --- etcdctl/ctlv2/command/cluster_health.go | 4 ++-- etcdctl/ctlv2/command/error.go | 15 ++++++++++++++- etcdctl/ctlv2/command/exec_watch_command.go | 4 ++-- etcdctl/ctlv2/command/get_command.go | 4 ++-- etcdctl/ctlv2/command/ls_command.go | 2 +- etcdctl/ctlv2/command/mk_command.go | 6 +++--- etcdctl/ctlv2/command/mkdir_command.go | 4 ++-- etcdctl/ctlv2/command/rm_command.go | 4 ++-- etcdctl/ctlv2/command/rmdir_command.go | 4 ++-- etcdctl/ctlv2/command/set_command.go | 6 +++--- etcdctl/ctlv2/command/update_command.go | 6 +++--- etcdctl/ctlv2/command/update_dir_command.go | 4 ++-- etcdctl/ctlv2/command/util.go | 4 ++-- etcdctl/ctlv2/command/watch_command.go | 4 ++-- 14 files changed, 42 insertions(+), 29 deletions(-) diff --git a/etcdctl/ctlv2/command/cluster_health.go b/etcdctl/ctlv2/command/cluster_health.go index 2ba347e7d..95101785d 100644 --- a/etcdctl/ctlv2/command/cluster_health.go +++ b/etcdctl/ctlv2/command/cluster_health.go @@ -54,7 +54,7 @@ func handleClusterHealth(c *cli.Context) error { tr, err := getTransport(c) if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } hc := http.Client{ @@ -66,7 +66,7 @@ func handleClusterHealth(c *cli.Context) error { ms, err := mi.List(context.TODO()) if err != nil { fmt.Println("cluster may be unhealthy: failed to list members") - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } for { diff --git a/etcdctl/ctlv2/command/error.go b/etcdctl/ctlv2/command/error.go index daa2bc275..e673fa39c 100644 --- a/etcdctl/ctlv2/command/error.go +++ b/etcdctl/ctlv2/command/error.go @@ -15,10 +15,12 @@ package command import ( + "encoding/json" "fmt" "os" "github.com/coreos/etcd/client" + "github.com/urfave/cli" ) const ( @@ -30,7 +32,18 @@ const ( ExitClusterNotHealthy ) -func handleError(code int, err error) { +func handleError(c *cli.Context, code int, err error) { + if c.GlobalString("output") == "json" { + if err, ok := err.(*client.Error); ok { + b, err := json.Marshal(err) + if err != nil { + panic(err) + } + fmt.Fprintln(os.Stderr, string(b)) + os.Exit(code) + } + } + fmt.Fprintln(os.Stderr, "Error: ", err) if cerr, ok := err.(*client.ClusterError); ok { fmt.Fprintln(os.Stderr, cerr.Detail()) diff --git a/etcdctl/ctlv2/command/exec_watch_command.go b/etcdctl/ctlv2/command/exec_watch_command.go index 7ed32a68a..5ae245245 100644 --- a/etcdctl/ctlv2/command/exec_watch_command.go +++ b/etcdctl/ctlv2/command/exec_watch_command.go @@ -49,7 +49,7 @@ func execWatchCommandFunc(c *cli.Context, ki client.KeysAPI) { argslen := len(args) if argslen < 2 { - handleError(ExitBadArgs, errors.New("key and command to exec required")) + handleError(c, ExitBadArgs, errors.New("key and command to exec required")) } var ( @@ -95,7 +95,7 @@ func execWatchCommandFunc(c *cli.Context, ki client.KeysAPI) { for { resp, err := w.Next(context.TODO()) if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } if resp.Node.Dir { fmt.Fprintf(os.Stderr, "Ignored dir %s change\n", resp.Node.Key) diff --git a/etcdctl/ctlv2/command/get_command.go b/etcdctl/ctlv2/command/get_command.go index 9f99c8fcb..7f1fc4db1 100644 --- a/etcdctl/ctlv2/command/get_command.go +++ b/etcdctl/ctlv2/command/get_command.go @@ -43,7 +43,7 @@ func NewGetCommand() cli.Command { // getCommandFunc executes the "get" command. func getCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { - handleError(ExitBadArgs, errors.New("key required")) + handleError(c, ExitBadArgs, errors.New("key required")) } key := c.Args()[0] @@ -54,7 +54,7 @@ func getCommandFunc(c *cli.Context, ki client.KeysAPI) { resp, err := ki.Get(ctx, key, &client.GetOptions{Sort: sorted, Quorum: quorum}) cancel() if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } if resp.Node.Dir { diff --git a/etcdctl/ctlv2/command/ls_command.go b/etcdctl/ctlv2/command/ls_command.go index d5a8ede02..b2e94fb93 100644 --- a/etcdctl/ctlv2/command/ls_command.go +++ b/etcdctl/ctlv2/command/ls_command.go @@ -54,7 +54,7 @@ func lsCommandFunc(c *cli.Context, ki client.KeysAPI) { resp, err := ki.Get(ctx, key, &client.GetOptions{Sort: sort, Recursive: recursive, Quorum: quorum}) cancel() if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } printLs(c, resp) diff --git a/etcdctl/ctlv2/command/mk_command.go b/etcdctl/ctlv2/command/mk_command.go index 73dad0bf5..f62415350 100644 --- a/etcdctl/ctlv2/command/mk_command.go +++ b/etcdctl/ctlv2/command/mk_command.go @@ -43,12 +43,12 @@ func NewMakeCommand() cli.Command { // mkCommandFunc executes the "mk" command. func mkCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { - handleError(ExitBadArgs, errors.New("key required")) + handleError(c, ExitBadArgs, errors.New("key required")) } key := c.Args()[0] value, err := argOrStdin(c.Args(), os.Stdin, 1) if err != nil { - handleError(ExitBadArgs, errors.New("value required")) + handleError(c, ExitBadArgs, errors.New("value required")) } ttl := c.Int("ttl") @@ -69,7 +69,7 @@ func mkCommandFunc(c *cli.Context, ki client.KeysAPI) { } cancel() if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } printResponseKey(resp, c.GlobalString("output")) diff --git a/etcdctl/ctlv2/command/mkdir_command.go b/etcdctl/ctlv2/command/mkdir_command.go index a3babb9ae..1d17b7b91 100644 --- a/etcdctl/ctlv2/command/mkdir_command.go +++ b/etcdctl/ctlv2/command/mkdir_command.go @@ -41,7 +41,7 @@ func NewMakeDirCommand() cli.Command { // mkdirCommandFunc executes the "mkdir" command. func mkdirCommandFunc(c *cli.Context, ki client.KeysAPI, prevExist client.PrevExistType) { if len(c.Args()) == 0 { - handleError(ExitBadArgs, errors.New("key required")) + handleError(c, ExitBadArgs, errors.New("key required")) } key := c.Args()[0] @@ -51,7 +51,7 @@ func mkdirCommandFunc(c *cli.Context, ki client.KeysAPI, prevExist client.PrevEx resp, err := ki.Set(ctx, key, "", &client.SetOptions{TTL: time.Duration(ttl) * time.Second, Dir: true, PrevExist: prevExist}) cancel() if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } if c.GlobalString("output") != "simple" { printResponseKey(resp, c.GlobalString("output")) diff --git a/etcdctl/ctlv2/command/rm_command.go b/etcdctl/ctlv2/command/rm_command.go index 6c2104480..c6f173be7 100644 --- a/etcdctl/ctlv2/command/rm_command.go +++ b/etcdctl/ctlv2/command/rm_command.go @@ -43,7 +43,7 @@ func NewRemoveCommand() cli.Command { // rmCommandFunc executes the "rm" command. func rmCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { - handleError(ExitBadArgs, errors.New("key required")) + handleError(c, ExitBadArgs, errors.New("key required")) } key := c.Args()[0] recursive := c.Bool("recursive") @@ -55,7 +55,7 @@ func rmCommandFunc(c *cli.Context, ki client.KeysAPI) { resp, err := ki.Delete(ctx, key, &client.DeleteOptions{PrevIndex: uint64(prevIndex), PrevValue: prevValue, Dir: dir, Recursive: recursive}) cancel() if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } if !resp.Node.Dir || c.GlobalString("output") != "simple" { printResponseKey(resp, c.GlobalString("output")) diff --git a/etcdctl/ctlv2/command/rmdir_command.go b/etcdctl/ctlv2/command/rmdir_command.go index 9a685118d..cb3089548 100644 --- a/etcdctl/ctlv2/command/rmdir_command.go +++ b/etcdctl/ctlv2/command/rmdir_command.go @@ -37,7 +37,7 @@ func NewRemoveDirCommand() cli.Command { // rmdirCommandFunc executes the "rmdir" command. func rmdirCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { - handleError(ExitBadArgs, errors.New("key required")) + handleError(c, ExitBadArgs, errors.New("key required")) } key := c.Args()[0] @@ -45,7 +45,7 @@ func rmdirCommandFunc(c *cli.Context, ki client.KeysAPI) { resp, err := ki.Delete(ctx, key, &client.DeleteOptions{Dir: true}) cancel() if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } if !resp.Node.Dir || c.GlobalString("output") != "simple" { diff --git a/etcdctl/ctlv2/command/set_command.go b/etcdctl/ctlv2/command/set_command.go index 130a6c13a..f7bb6bd53 100644 --- a/etcdctl/ctlv2/command/set_command.go +++ b/etcdctl/ctlv2/command/set_command.go @@ -50,12 +50,12 @@ func NewSetCommand() cli.Command { // setCommandFunc executes the "set" command. func setCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { - handleError(ExitBadArgs, errors.New("key required")) + handleError(c, ExitBadArgs, errors.New("key required")) } key := c.Args()[0] value, err := argOrStdin(c.Args(), os.Stdin, 1) if err != nil { - handleError(ExitBadArgs, errors.New("value required")) + handleError(c, ExitBadArgs, errors.New("value required")) } ttl := c.Int("ttl") @@ -66,7 +66,7 @@ func setCommandFunc(c *cli.Context, ki client.KeysAPI) { resp, err := ki.Set(ctx, key, value, &client.SetOptions{TTL: time.Duration(ttl) * time.Second, PrevIndex: uint64(prevIndex), PrevValue: prevValue}) cancel() if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } printResponseKey(resp, c.GlobalString("output")) diff --git a/etcdctl/ctlv2/command/update_command.go b/etcdctl/ctlv2/command/update_command.go index 8ab9fb4af..ed4224892 100644 --- a/etcdctl/ctlv2/command/update_command.go +++ b/etcdctl/ctlv2/command/update_command.go @@ -42,12 +42,12 @@ func NewUpdateCommand() cli.Command { // updateCommandFunc executes the "update" command. func updateCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { - handleError(ExitBadArgs, errors.New("key required")) + handleError(c, ExitBadArgs, errors.New("key required")) } key := c.Args()[0] value, err := argOrStdin(c.Args(), os.Stdin, 1) if err != nil { - handleError(ExitBadArgs, errors.New("value required")) + handleError(c, ExitBadArgs, errors.New("value required")) } ttl := c.Int("ttl") @@ -56,7 +56,7 @@ func updateCommandFunc(c *cli.Context, ki client.KeysAPI) { resp, err := ki.Set(ctx, key, value, &client.SetOptions{TTL: time.Duration(ttl) * time.Second, PrevExist: client.PrevExist}) cancel() if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } printResponseKey(resp, c.GlobalString("output")) diff --git a/etcdctl/ctlv2/command/update_dir_command.go b/etcdctl/ctlv2/command/update_dir_command.go index 1cc4e087c..72411dfba 100644 --- a/etcdctl/ctlv2/command/update_dir_command.go +++ b/etcdctl/ctlv2/command/update_dir_command.go @@ -41,7 +41,7 @@ func NewUpdateDirCommand() cli.Command { // updatedirCommandFunc executes the "updatedir" command. func updatedirCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { - handleError(ExitBadArgs, errors.New("key required")) + handleError(c, ExitBadArgs, errors.New("key required")) } key := c.Args()[0] ttl := c.Int("ttl") @@ -49,7 +49,7 @@ func updatedirCommandFunc(c *cli.Context, ki client.KeysAPI) { resp, err := ki.Set(ctx, key, "", &client.SetOptions{TTL: time.Duration(ttl) * time.Second, Dir: true, PrevExist: client.PrevExist}) cancel() if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } if c.GlobalString("output") != "simple" { printResponseKey(resp, c.GlobalString("output")) diff --git a/etcdctl/ctlv2/command/util.go b/etcdctl/ctlv2/command/util.go index 376aebd53..d6a58145c 100644 --- a/etcdctl/ctlv2/command/util.go +++ b/etcdctl/ctlv2/command/util.go @@ -237,10 +237,10 @@ func mustNewClient(c *cli.Context) client.Client { if err == client.ErrNoEndpoints { fmt.Fprintf(os.Stderr, "etcd cluster has no published client endpoints.\n") fmt.Fprintf(os.Stderr, "Try '--no-sync' if you want to access non-published client endpoints(%s).\n", strings.Join(hc.Endpoints(), ",")) - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } if isConnectionError(err) { - handleError(ExitBadConnection, err) + handleError(c, ExitBadConnection, err) } } if debug { diff --git a/etcdctl/ctlv2/command/watch_command.go b/etcdctl/ctlv2/command/watch_command.go index 93fcf6714..71f4c014c 100644 --- a/etcdctl/ctlv2/command/watch_command.go +++ b/etcdctl/ctlv2/command/watch_command.go @@ -46,7 +46,7 @@ func NewWatchCommand() cli.Command { // watchCommandFunc executes the "watch" command. func watchCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { - handleError(ExitBadArgs, errors.New("key required")) + handleError(c, ExitBadArgs, errors.New("key required")) } key := c.Args()[0] recursive := c.Bool("recursive") @@ -67,7 +67,7 @@ func watchCommandFunc(c *cli.Context, ki client.KeysAPI) { for !stop { resp, err := w.Next(context.TODO()) if err != nil { - handleError(ExitServerError, err) + handleError(c, ExitServerError, err) } if resp.Node.Dir { continue