diff --git a/etcdctl/ctlv3/command/ep_command.go b/etcdctl/ctlv3/command/ep_command.go index 4fac7e44d95..a1534b4df68 100644 --- a/etcdctl/ctlv3/command/ep_command.go +++ b/etcdctl/ctlv3/command/ep_command.go @@ -82,10 +82,12 @@ func epHealthCommandFunc(cmd *cobra.Command, args []string) { sec := secureCfgFromCmd(cmd) dt := dialTimeoutFromCmd(cmd) + ka := keepAliveTimeFromCmd(cmd) + kat := keepAliveTimeoutFromCmd(cmd) auth := authCfgFromCmd(cmd) cfgs := []*v3.Config{} for _, ep := range endpointsFromCluster(cmd) { - cfg, err := newClientCfg([]string{ep}, dt, sec, auth) + cfg, err := newClientCfg([]string{ep}, dt, ka, kat, sec, auth) if err != nil { ExitWithError(ExitBadArgs, err) } diff --git a/etcdctl/ctlv3/command/global.go b/etcdctl/ctlv3/command/global.go index 7af63615a4c..825e2839117 100644 --- a/etcdctl/ctlv3/command/global.go +++ b/etcdctl/ctlv3/command/global.go @@ -43,6 +43,8 @@ type GlobalFlags struct { Endpoints []string DialTimeout time.Duration CommandTimeOut time.Duration + KeepAliveTime time.Duration + KeepAliveTimeout time.Duration TLS transport.TLSInfo @@ -109,17 +111,21 @@ func mustClientFromCmd(cmd *cobra.Command) *clientv3.Client { if err != nil { ExitWithError(ExitError, err) } + dialTimeout := dialTimeoutFromCmd(cmd) + keepAliveTime := keepAliveTimeFromCmd(cmd) + keepAliveTimeout := keepAliveTimeoutFromCmd(cmd) + sec := secureCfgFromCmd(cmd) auth := authCfgFromCmd(cmd) initDisplayFromCmd(cmd) - return mustClient(endpoints, dialTimeout, sec, auth) + return mustClient(endpoints, dialTimeout, keepAliveTime, keepAliveTimeout, sec, auth) } -func mustClient(endpoints []string, dialTimeout time.Duration, scfg *secureCfg, acfg *authCfg) *clientv3.Client { - cfg, err := newClientCfg(endpoints, dialTimeout, scfg, acfg) +func mustClient(endpoints []string, dialTimeout, keepAliveTime, keepAliveTimeout time.Duration, scfg *secureCfg, acfg *authCfg) *clientv3.Client { + cfg, err := newClientCfg(endpoints, dialTimeout, keepAliveTime, keepAliveTimeout, scfg, acfg) if err != nil { ExitWithError(ExitBadArgs, err) } @@ -132,7 +138,7 @@ func mustClient(endpoints []string, dialTimeout time.Duration, scfg *secureCfg, return client } -func newClientCfg(endpoints []string, dialTimeout time.Duration, scfg *secureCfg, acfg *authCfg) (*clientv3.Config, error) { +func newClientCfg(endpoints []string, dialTimeout, keepAliveTime, keepAliveTimeout time.Duration, scfg *secureCfg, acfg *authCfg) (*clientv3.Config, error) { // set tls if any one tls option set var cfgtls *transport.TLSInfo tlsinfo := transport.TLSInfo{} @@ -157,9 +163,12 @@ func newClientCfg(endpoints []string, dialTimeout time.Duration, scfg *secureCfg } cfg := &clientv3.Config{ - Endpoints: endpoints, - DialTimeout: dialTimeout, + Endpoints: endpoints, + DialTimeout: dialTimeout, + DialKeepAliveTime: keepAliveTime, + DialKeepAliveTimeout: keepAliveTimeout, } + if cfgtls != nil { clientTLS, err := cfgtls.ClientConfig() if err != nil { @@ -167,6 +176,7 @@ func newClientCfg(endpoints []string, dialTimeout time.Duration, scfg *secureCfg } cfg.TLS = clientTLS } + // if key/cert is not given but user wants secure connection, we // should still setup an empty tls configuration for gRPC to setup // secure connection. @@ -207,6 +217,22 @@ func dialTimeoutFromCmd(cmd *cobra.Command) time.Duration { return dialTimeout } +func keepAliveTimeFromCmd(cmd *cobra.Command) time.Duration { + keepAliveTime, err := cmd.Flags().GetDuration("keepalive-time") + if err != nil { + ExitWithError(ExitError, err) + } + return keepAliveTime +} + +func keepAliveTimeoutFromCmd(cmd *cobra.Command) time.Duration { + keepAliveTimeout, err := cmd.Flags().GetDuration("keepalive-timeout") + if err != nil { + ExitWithError(ExitError, err) + } + return keepAliveTimeout +} + func secureCfgFromCmd(cmd *cobra.Command) *secureCfg { cert, key, cacert := keyAndCertFromCmd(cmd) insecureTr := insecureTransportFromCmd(cmd) diff --git a/etcdctl/ctlv3/command/make_mirror_command.go b/etcdctl/ctlv3/command/make_mirror_command.go index 502406441f4..1f9ae94580e 100644 --- a/etcdctl/ctlv3/command/make_mirror_command.go +++ b/etcdctl/ctlv3/command/make_mirror_command.go @@ -66,6 +66,8 @@ func makeMirrorCommandFunc(cmd *cobra.Command, args []string) { } dialTimeout := dialTimeoutFromCmd(cmd) + keepAliveTime := keepAliveTimeFromCmd(cmd) + keepAliveTimeout := keepAliveTimeoutFromCmd(cmd) sec := &secureCfg{ cert: mmcert, key: mmkey, @@ -73,7 +75,7 @@ func makeMirrorCommandFunc(cmd *cobra.Command, args []string) { insecureTransport: mminsecureTr, } - dc := mustClient([]string{args[0]}, dialTimeout, sec, nil) + dc := mustClient([]string{args[0]}, dialTimeout, keepAliveTime, keepAliveTimeout, sec, nil) c := mustClientFromCmd(cmd) err := makeMirror(context.TODO(), c, dc) diff --git a/etcdctl/ctlv3/ctl.go b/etcdctl/ctlv3/ctl.go index a24a51480e9..8692084cfcd 100644 --- a/etcdctl/ctlv3/ctl.go +++ b/etcdctl/ctlv3/ctl.go @@ -26,8 +26,10 @@ const ( cliName = "etcdctl" cliDescription = "A simple command line client for etcd3." - defaultDialTimeout = 2 * time.Second - defaultCommandTimeOut = 5 * time.Second + defaultDialTimeout = 2 * time.Second + defaultCommandTimeOut = 5 * time.Second + defaultKeepAliveTime = 2 * time.Second + defaultKeepAliveTimeOut = 6 * time.Second ) var ( @@ -51,6 +53,8 @@ func init() { 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)") + rootCmd.PersistentFlags().DurationVar(&globalFlags.KeepAliveTime, "keepalive-time", defaultKeepAliveTime, "keepalive time for client connections") + rootCmd.PersistentFlags().DurationVar(&globalFlags.KeepAliveTimeout, "keepalive-timeout", defaultKeepAliveTimeOut, "keepalive timeout for client connections") // 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")