From f165f8b44e2e134b5217693b70d00739792554c6 Mon Sep 17 00:00:00 2001 From: mqliang Date: Thu, 24 Mar 2016 17:00:26 +0800 Subject: [PATCH] etcdctlv3: add timeout support add timeout setting support for etcdctlv3 --- etcdctlv3/command/auth_command.go | 5 +++-- etcdctlv3/command/compaction_command.go | 6 ++++-- etcdctlv3/command/defrag_command.go | 5 +++-- etcdctlv3/command/del_command.go | 5 +++-- etcdctlv3/command/ep_health_command.go | 5 +++-- etcdctlv3/command/get_command.go | 5 +++-- etcdctlv3/command/global.go | 7 ++++--- etcdctlv3/command/lease_command.go | 8 ++++++-- etcdctlv3/command/member_command.go | 18 ++++++++++++------ etcdctlv3/command/put_command.go | 5 +++-- etcdctlv3/command/util.go | 10 ++++++++++ etcdctlv3/main.go | 4 +++- 12 files changed, 57 insertions(+), 26 deletions(-) diff --git a/etcdctlv3/command/auth_command.go b/etcdctlv3/command/auth_command.go index eb1387beb..cf7d21f1b 100644 --- a/etcdctlv3/command/auth_command.go +++ b/etcdctlv3/command/auth_command.go @@ -18,7 +18,6 @@ import ( "fmt" "github.com/spf13/cobra" - "golang.org/x/net/context" ) // NewAuthCommand returns the cobra command for "auth". @@ -47,7 +46,9 @@ func authEnableCommandFunc(cmd *cobra.Command, args []string) { ExitWithError(ExitBadArgs, fmt.Errorf("auth enable command does not accept argument.")) } - _, err := mustClientFromCmd(cmd).Auth.AuthEnable(context.TODO()) + ctx, cancel := commandCtx(cmd) + _, err := mustClientFromCmd(cmd).Auth.AuthEnable(ctx) + cancel() if err != nil { ExitWithError(ExitError, err) } diff --git a/etcdctlv3/command/compaction_command.go b/etcdctlv3/command/compaction_command.go index ce2889618..366e3e259 100644 --- a/etcdctlv3/command/compaction_command.go +++ b/etcdctlv3/command/compaction_command.go @@ -19,7 +19,6 @@ import ( "strconv" "github.com/spf13/cobra" - "golang.org/x/net/context" ) // NewCompactionCommand returns the cobra command for "compaction". @@ -43,7 +42,10 @@ func compactionCommandFunc(cmd *cobra.Command, args []string) { } c := mustClientFromCmd(cmd) - if cerr := c.Compact(context.TODO(), rev); cerr != nil { + ctx, cancel := commandCtx(cmd) + cerr := c.Compact(ctx, rev) + cancel() + if cerr != nil { ExitWithError(ExitError, cerr) return } diff --git a/etcdctlv3/command/defrag_command.go b/etcdctlv3/command/defrag_command.go index bba7643f0..3a8e40df8 100644 --- a/etcdctlv3/command/defrag_command.go +++ b/etcdctlv3/command/defrag_command.go @@ -19,7 +19,6 @@ import ( "os" "github.com/spf13/cobra" - "golang.org/x/net/context" ) // NewDefragCommand returns the cobra command for "Defrag". @@ -34,7 +33,9 @@ func NewDefragCommand() *cobra.Command { func defragCommandFunc(cmd *cobra.Command, args []string) { c := mustClientFromCmd(cmd) for _, ep := range c.Endpoints() { - _, err := c.Defragment(context.TODO(), ep) + ctx, cancel := commandCtx(cmd) + _, err := c.Defragment(ctx, ep) + cancel() if err != nil { fmt.Fprintf(os.Stderr, "Failed to defragment etcd member[%s] (%v)\n", ep, err) } else { diff --git a/etcdctlv3/command/del_command.go b/etcdctlv3/command/del_command.go index d206c2daf..607666787 100644 --- a/etcdctlv3/command/del_command.go +++ b/etcdctlv3/command/del_command.go @@ -19,7 +19,6 @@ import ( "github.com/coreos/etcd/clientv3" "github.com/spf13/cobra" - "golang.org/x/net/context" ) // NewDelCommand returns the cobra command for "del". @@ -34,7 +33,9 @@ func NewDelCommand() *cobra.Command { // delCommandFunc executes the "del" command. func delCommandFunc(cmd *cobra.Command, args []string) { key, opts := getDelOp(cmd, args) - resp, err := mustClientFromCmd(cmd).Delete(context.TODO(), key, opts...) + ctx, cancel := commandCtx(cmd) + resp, err := mustClientFromCmd(cmd).Delete(ctx, key, opts...) + cancel() if err != nil { ExitWithError(ExitError, err) } diff --git a/etcdctlv3/command/ep_health_command.go b/etcdctlv3/command/ep_health_command.go index 2627f0c5c..9194cc967 100644 --- a/etcdctlv3/command/ep_health_command.go +++ b/etcdctlv3/command/ep_health_command.go @@ -21,7 +21,6 @@ import ( "github.com/coreos/etcd/clientv3" "github.com/spf13/cobra" - "golang.org/x/net/context" ) // NewEpHealthCommand returns the cobra command for "endpoint-health". @@ -67,7 +66,9 @@ func epHealthCommandFunc(cmd *cobra.Command, args []string) { st := time.Now() // get a random key. As long as we can get the response without an error, the // endpoint is health. - _, err = cli.Get(context.TODO(), "health") + ctx, cancel := commandCtx(cmd) + _, err = cli.Get(ctx, "health") + cancel() if err != nil { fmt.Printf("%s is unhealthy: failed to commit proposal: %v\n", ep, err) } else { diff --git a/etcdctlv3/command/get_command.go b/etcdctlv3/command/get_command.go index 6107aba21..42405cb21 100644 --- a/etcdctlv3/command/get_command.go +++ b/etcdctlv3/command/get_command.go @@ -20,7 +20,6 @@ import ( "github.com/coreos/etcd/clientv3" "github.com/spf13/cobra" - "golang.org/x/net/context" ) var ( @@ -52,7 +51,9 @@ func NewGetCommand() *cobra.Command { // getCommandFunc executes the "get" command. func getCommandFunc(cmd *cobra.Command, args []string) { key, opts := getGetOp(cmd, args) - resp, err := mustClientFromCmd(cmd).Get(context.TODO(), key, opts...) + ctx, cancel := commandCtx(cmd) + resp, err := mustClientFromCmd(cmd).Get(ctx, key, opts...) + cancel() if err != nil { ExitWithError(ExitError, err) } diff --git a/etcdctlv3/command/global.go b/etcdctlv3/command/global.go index 46d2b6b4d..1764d59da 100644 --- a/etcdctlv3/command/global.go +++ b/etcdctlv3/command/global.go @@ -29,9 +29,10 @@ import ( // GlobalFlags are flags that defined globally // and are inherited to all sub-commands. type GlobalFlags struct { - Insecure bool - Endpoints []string - DialTimeout time.Duration + Insecure bool + Endpoints []string + DialTimeout time.Duration + CommandTimeOut time.Duration TLS transport.TLSInfo diff --git a/etcdctlv3/command/lease_command.go b/etcdctlv3/command/lease_command.go index 48985c6fa..ede7b3398 100644 --- a/etcdctlv3/command/lease_command.go +++ b/etcdctlv3/command/lease_command.go @@ -61,7 +61,9 @@ func leaseCreateCommandFunc(cmd *cobra.Command, args []string) { ExitWithError(ExitBadArgs, fmt.Errorf("bad TTL (%v)", err)) } - resp, err := mustClientFromCmd(cmd).Create(context.TODO(), ttl) + ctx, cancel := commandCtx(cmd) + resp, err := mustClientFromCmd(cmd).Create(ctx, ttl) + cancel() if err != nil { fmt.Fprintf(os.Stderr, "failed to create lease (%v)\n", err) return @@ -92,7 +94,9 @@ func leaseRevokeCommandFunc(cmd *cobra.Command, args []string) { ExitWithError(ExitBadArgs, fmt.Errorf("bad lease ID arg (%v), expecting ID in Hex", err)) } - _, err = mustClientFromCmd(cmd).Revoke(context.TODO(), v3.LeaseID(id)) + ctx, cancel := commandCtx(cmd) + _, err = mustClientFromCmd(cmd).Revoke(ctx, v3.LeaseID(id)) + cancel() if err != nil { fmt.Fprintf(os.Stderr, "failed to revoke lease (%v)\n", err) return diff --git a/etcdctlv3/command/member_command.go b/etcdctlv3/command/member_command.go index 73e4564b3..8a2b97712 100644 --- a/etcdctlv3/command/member_command.go +++ b/etcdctlv3/command/member_command.go @@ -20,7 +20,6 @@ import ( "strings" "github.com/spf13/cobra" - "golang.org/x/net/context" ) var ( @@ -106,8 +105,9 @@ func memberAddCommandFunc(cmd *cobra.Command, args []string) { } urls := strings.Split(memberPeerURLs, ",") - - resp, err := mustClientFromCmd(cmd).MemberAdd(context.TODO(), urls) + ctx, cancel := commandCtx(cmd) + resp, err := mustClientFromCmd(cmd).MemberAdd(ctx, urls) + cancel() if err != nil { ExitWithError(ExitError, err) } @@ -126,7 +126,9 @@ func memberRemoveCommandFunc(cmd *cobra.Command, args []string) { ExitWithError(ExitBadArgs, fmt.Errorf("bad member ID arg (%v), expecting ID in Hex", err)) } - resp, err := mustClientFromCmd(cmd).MemberRemove(context.TODO(), id) + ctx, cancel := commandCtx(cmd) + resp, err := mustClientFromCmd(cmd).MemberRemove(ctx, id) + cancel() if err != nil { ExitWithError(ExitError, err) } @@ -151,7 +153,9 @@ func memberUpdateCommandFunc(cmd *cobra.Command, args []string) { urls := strings.Split(memberPeerURLs, ",") - resp, err := mustClientFromCmd(cmd).MemberUpdate(context.TODO(), id, urls) + ctx, cancel := commandCtx(cmd) + resp, err := mustClientFromCmd(cmd).MemberUpdate(ctx, id, urls) + cancel() if err != nil { ExitWithError(ExitError, err) } @@ -161,7 +165,9 @@ func memberUpdateCommandFunc(cmd *cobra.Command, args []string) { // memberListCommandFunc executes the "member list" command. func memberListCommandFunc(cmd *cobra.Command, args []string) { - resp, err := mustClientFromCmd(cmd).MemberList(context.TODO()) + ctx, cancel := commandCtx(cmd) + resp, err := mustClientFromCmd(cmd).MemberList(ctx) + cancel() if err != nil { ExitWithError(ExitError, err) } diff --git a/etcdctlv3/command/put_command.go b/etcdctlv3/command/put_command.go index 511ba8131..d596b7066 100644 --- a/etcdctlv3/command/put_command.go +++ b/etcdctlv3/command/put_command.go @@ -21,7 +21,6 @@ import ( "github.com/coreos/etcd/clientv3" "github.com/spf13/cobra" - "golang.org/x/net/context" ) var ( @@ -57,7 +56,9 @@ will store the content of the file to . func putCommandFunc(cmd *cobra.Command, args []string) { key, value, opts := getPutOp(cmd, args) - resp, err := mustClientFromCmd(cmd).Put(context.TODO(), key, value, opts...) + ctx, cancel := commandCtx(cmd) + resp, err := mustClientFromCmd(cmd).Put(ctx, key, value, opts...) + cancel() if err != nil { ExitWithError(ExitError, err) } diff --git a/etcdctlv3/command/util.go b/etcdctlv3/command/util.go index c74bbe02d..1d4e0ae72 100644 --- a/etcdctlv3/command/util.go +++ b/etcdctlv3/command/util.go @@ -20,6 +20,8 @@ import ( "regexp" pb "github.com/coreos/etcd/storage/storagepb" + "github.com/spf13/cobra" + "golang.org/x/net/context" ) func printKV(isHex bool, kv *pb.KeyValue) { @@ -47,3 +49,11 @@ func argify(s string) []string { r := regexp.MustCompile("'.+'|\".+\"|\\S+") return r.FindAllString(s, -1) } + +func commandCtx(cmd *cobra.Command) (context.Context, context.CancelFunc) { + timeOut, err := cmd.Flags().GetDuration("command-timeout") + if err != nil { + ExitWithError(ExitError, err) + } + return context.WithTimeout(context.Background(), timeOut) +} diff --git a/etcdctlv3/main.go b/etcdctlv3/main.go index 5f73f60e7..135510bc8 100644 --- a/etcdctlv3/main.go +++ b/etcdctlv3/main.go @@ -27,7 +27,8 @@ const ( cliName = "etcdctlv3" cliDescription = "A simple command line client for etcd3." - defaultDialTimeout = 2 * time.Second + defaultDialTimeout = 2 * time.Second + defaultCommandTimeOut = 5 * time.Second ) var ( @@ -50,6 +51,7 @@ func init() { rootCmd.PersistentFlags().BoolVar(&globalFlags.IsHex, "hex", false, "print byte strings as hex encoded strings") rootCmd.PersistentFlags().DurationVar(&globalFlags.DialTimeout, "dial-timeout", defaultDialTimeout, "dial timeout for client connections") + rootCmd.PersistentFlags().DurationVar(&globalFlags.CommandTimeOut, "command-timeout", defaultCommandTimeOut, "timeout for short running command (excluding dial timeout)") // TODO: secure by default when etcd enables secure gRPC by default. rootCmd.PersistentFlags().BoolVar(&globalFlags.Insecure, "insecure-transport", true, "disable transport security for client connections")