Merge pull request #4817 from mqliang/time-out

etcdctlv3: add timeout support
This commit is contained in:
Xiang Li 2016-03-25 07:30:48 -07:00
commit 5449edc025
12 changed files with 57 additions and 26 deletions

View File

@ -18,7 +18,6 @@ import (
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context"
) )
// NewAuthCommand returns the cobra command for "auth". // 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.")) 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 { if err != nil {
ExitWithError(ExitError, err) ExitWithError(ExitError, err)
} }

View File

@ -19,7 +19,6 @@ import (
"strconv" "strconv"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context"
) )
// NewCompactionCommand returns the cobra command for "compaction". // NewCompactionCommand returns the cobra command for "compaction".
@ -43,7 +42,10 @@ func compactionCommandFunc(cmd *cobra.Command, args []string) {
} }
c := mustClientFromCmd(cmd) 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) ExitWithError(ExitError, cerr)
return return
} }

View File

@ -19,7 +19,6 @@ import (
"os" "os"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context"
) )
// NewDefragCommand returns the cobra command for "Defrag". // NewDefragCommand returns the cobra command for "Defrag".
@ -34,7 +33,9 @@ func NewDefragCommand() *cobra.Command {
func defragCommandFunc(cmd *cobra.Command, args []string) { func defragCommandFunc(cmd *cobra.Command, args []string) {
c := mustClientFromCmd(cmd) c := mustClientFromCmd(cmd)
for _, ep := range c.Endpoints() { for _, ep := range c.Endpoints() {
_, err := c.Defragment(context.TODO(), ep) ctx, cancel := commandCtx(cmd)
_, err := c.Defragment(ctx, ep)
cancel()
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Failed to defragment etcd member[%s] (%v)\n", ep, err) fmt.Fprintf(os.Stderr, "Failed to defragment etcd member[%s] (%v)\n", ep, err)
} else { } else {

View File

@ -19,7 +19,6 @@ import (
"github.com/coreos/etcd/clientv3" "github.com/coreos/etcd/clientv3"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context"
) )
// NewDelCommand returns the cobra command for "del". // NewDelCommand returns the cobra command for "del".
@ -34,7 +33,9 @@ func NewDelCommand() *cobra.Command {
// delCommandFunc executes the "del" command. // delCommandFunc executes the "del" command.
func delCommandFunc(cmd *cobra.Command, args []string) { func delCommandFunc(cmd *cobra.Command, args []string) {
key, opts := getDelOp(cmd, args) 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 { if err != nil {
ExitWithError(ExitError, err) ExitWithError(ExitError, err)
} }

View File

@ -21,7 +21,6 @@ import (
"github.com/coreos/etcd/clientv3" "github.com/coreos/etcd/clientv3"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context"
) )
// NewEpHealthCommand returns the cobra command for "endpoint-health". // NewEpHealthCommand returns the cobra command for "endpoint-health".
@ -67,7 +66,9 @@ func epHealthCommandFunc(cmd *cobra.Command, args []string) {
st := time.Now() st := time.Now()
// get a random key. As long as we can get the response without an error, the // get a random key. As long as we can get the response without an error, the
// endpoint is health. // endpoint is health.
_, err = cli.Get(context.TODO(), "health") ctx, cancel := commandCtx(cmd)
_, err = cli.Get(ctx, "health")
cancel()
if err != nil { if err != nil {
fmt.Printf("%s is unhealthy: failed to commit proposal: %v\n", ep, err) fmt.Printf("%s is unhealthy: failed to commit proposal: %v\n", ep, err)
} else { } else {

View File

@ -20,7 +20,6 @@ import (
"github.com/coreos/etcd/clientv3" "github.com/coreos/etcd/clientv3"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context"
) )
var ( var (
@ -52,7 +51,9 @@ func NewGetCommand() *cobra.Command {
// getCommandFunc executes the "get" command. // getCommandFunc executes the "get" command.
func getCommandFunc(cmd *cobra.Command, args []string) { func getCommandFunc(cmd *cobra.Command, args []string) {
key, opts := getGetOp(cmd, args) 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 { if err != nil {
ExitWithError(ExitError, err) ExitWithError(ExitError, err)
} }

View File

@ -29,9 +29,10 @@ import (
// GlobalFlags are flags that defined globally // GlobalFlags are flags that defined globally
// and are inherited to all sub-commands. // and are inherited to all sub-commands.
type GlobalFlags struct { type GlobalFlags struct {
Insecure bool Insecure bool
Endpoints []string Endpoints []string
DialTimeout time.Duration DialTimeout time.Duration
CommandTimeOut time.Duration
TLS transport.TLSInfo TLS transport.TLSInfo

View File

@ -61,7 +61,9 @@ func leaseCreateCommandFunc(cmd *cobra.Command, args []string) {
ExitWithError(ExitBadArgs, fmt.Errorf("bad TTL (%v)", err)) 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 { if err != nil {
fmt.Fprintf(os.Stderr, "failed to create lease (%v)\n", err) fmt.Fprintf(os.Stderr, "failed to create lease (%v)\n", err)
return 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)) 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 { if err != nil {
fmt.Fprintf(os.Stderr, "failed to revoke lease (%v)\n", err) fmt.Fprintf(os.Stderr, "failed to revoke lease (%v)\n", err)
return return

View File

@ -20,7 +20,6 @@ import (
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context"
) )
var ( var (
@ -106,8 +105,9 @@ func memberAddCommandFunc(cmd *cobra.Command, args []string) {
} }
urls := strings.Split(memberPeerURLs, ",") urls := strings.Split(memberPeerURLs, ",")
ctx, cancel := commandCtx(cmd)
resp, err := mustClientFromCmd(cmd).MemberAdd(context.TODO(), urls) resp, err := mustClientFromCmd(cmd).MemberAdd(ctx, urls)
cancel()
if err != nil { if err != nil {
ExitWithError(ExitError, err) 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)) 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 { if err != nil {
ExitWithError(ExitError, err) ExitWithError(ExitError, err)
} }
@ -151,7 +153,9 @@ func memberUpdateCommandFunc(cmd *cobra.Command, args []string) {
urls := strings.Split(memberPeerURLs, ",") 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 { if err != nil {
ExitWithError(ExitError, err) ExitWithError(ExitError, err)
} }
@ -161,7 +165,9 @@ func memberUpdateCommandFunc(cmd *cobra.Command, args []string) {
// memberListCommandFunc executes the "member list" command. // memberListCommandFunc executes the "member list" command.
func memberListCommandFunc(cmd *cobra.Command, args []string) { 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 { if err != nil {
ExitWithError(ExitError, err) ExitWithError(ExitError, err)
} }

View File

@ -21,7 +21,6 @@ import (
"github.com/coreos/etcd/clientv3" "github.com/coreos/etcd/clientv3"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context"
) )
var ( var (
@ -57,7 +56,9 @@ will store the content of the file to <key>.
func putCommandFunc(cmd *cobra.Command, args []string) { func putCommandFunc(cmd *cobra.Command, args []string) {
key, value, opts := getPutOp(cmd, args) 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 { if err != nil {
ExitWithError(ExitError, err) ExitWithError(ExitError, err)
} }

View File

@ -20,6 +20,8 @@ import (
"regexp" "regexp"
pb "github.com/coreos/etcd/storage/storagepb" pb "github.com/coreos/etcd/storage/storagepb"
"github.com/spf13/cobra"
"golang.org/x/net/context"
) )
func printKV(isHex bool, kv *pb.KeyValue) { func printKV(isHex bool, kv *pb.KeyValue) {
@ -47,3 +49,11 @@ func argify(s string) []string {
r := regexp.MustCompile("'.+'|\".+\"|\\S+") r := regexp.MustCompile("'.+'|\".+\"|\\S+")
return r.FindAllString(s, -1) 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)
}

View File

@ -27,7 +27,8 @@ const (
cliName = "etcdctlv3" cliName = "etcdctlv3"
cliDescription = "A simple command line client for etcd3." cliDescription = "A simple command line client for etcd3."
defaultDialTimeout = 2 * time.Second defaultDialTimeout = 2 * time.Second
defaultCommandTimeOut = 5 * time.Second
) )
var ( var (
@ -50,6 +51,7 @@ func init() {
rootCmd.PersistentFlags().BoolVar(&globalFlags.IsHex, "hex", false, "print byte strings as hex encoded strings") 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.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. // 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") rootCmd.PersistentFlags().BoolVar(&globalFlags.Insecure, "insecure-transport", true, "disable transport security for client connections")