diff --git a/client/v3/config.go b/client/v3/config.go index 335a288732b..29726160852 100644 --- a/client/v3/config.go +++ b/client/v3/config.go @@ -90,3 +90,31 @@ type Config struct { // TODO: support custom balancer picker } + +// ConfigSpec is the configuration from users, which comes from command-line flags, +// environment variables or config file. It is a fully declarative configuration, +// and can be serialized & deserialized to/from JSON. +type ConfigSpec struct { + Endpoints []string `json:"endpoints"` + RequestTimeout time.Duration `json:"request-timeout"` + DialTimeout time.Duration `json:"dial-timeout"` + KeepAliveTime time.Duration `json:"keepalive-time"` + KeepAliveTimeout time.Duration `json:"keepalive-timeout"` + Secure *SecureConfig `json:"secure"` + Auth *AuthConfig `json:"auth"` +} + +type SecureConfig struct { + Cert string `json:"cert"` + Key string `json:"key"` + Cacert string `json:"cacert"` + ServerName string `json:"server-name"` + + InsecureTransport bool `json:"insecure-transport"` + InsecureSkipVerify bool `json:"insecure-skip-tls-verify"` +} + +type AuthConfig struct { + Username string `json:"username"` + Password string `json:"password"` +} diff --git a/etcdctl/ctlv3/command/check.go b/etcdctl/ctlv3/command/check.go index 50d6d3bbd73..7227b14cdba 100644 --- a/etcdctl/ctlv3/command/check.go +++ b/etcdctl/ctlv3/command/check.go @@ -158,7 +158,7 @@ func newCheckPerfCommand(cmd *cobra.Command, args []string) { cc := clientConfigFromCmd(cmd) clients := make([]*v3.Client, cfg.clients) for i := 0; i < cfg.clients; i++ { - clients[i] = cc.mustClient() + clients[i] = mustClient(cc) } ctx, cancel := context.WithTimeout(context.Background(), time.Duration(cfg.duration)*time.Second) @@ -331,7 +331,7 @@ func newCheckDatascaleCommand(cmd *cobra.Command, args []string) { cc := clientConfigFromCmd(cmd) clients := make([]*v3.Client, cfg.clients) for i := 0; i < cfg.clients; i++ { - clients[i] = cc.mustClient() + clients[i] = mustClient(cc) } // get endpoints diff --git a/etcdctl/ctlv3/command/global.go b/etcdctl/ctlv3/command/global.go index 9097419d3e3..57adae28f00 100644 --- a/etcdctl/ctlv3/command/global.go +++ b/etcdctl/ctlv3/command/global.go @@ -60,21 +60,6 @@ type GlobalFlags struct { Debug bool } -type secureCfg struct { - cert string - key string - cacert string - serverName string - - insecureTransport bool - insecureSkipVerify bool -} - -type authCfg struct { - username string - password string -} - type discoveryCfg struct { domain string insecure bool @@ -97,22 +82,13 @@ func initDisplayFromCmd(cmd *cobra.Command) { } } -type clientConfig struct { - endpoints []string - dialTimeout time.Duration - keepAliveTime time.Duration - keepAliveTimeout time.Duration - scfg *secureCfg - acfg *authCfg -} - type discardValue struct{} func (*discardValue) String() string { return "" } func (*discardValue) Set(string) error { return nil } func (*discardValue) Type() string { return "" } -func clientConfigFromCmd(cmd *cobra.Command) *clientConfig { +func clientConfigFromCmd(cmd *cobra.Command) *clientv3.ConfigSpec { lg, err := zap.NewProduction() if err != nil { cobrautl.ExitWithError(cobrautl.ExitError, err) @@ -143,18 +119,18 @@ func clientConfigFromCmd(cmd *cobra.Command) *clientConfig { grpclog.SetLoggerV2(grpclog.NewLoggerV2(io.Discard, io.Discard, os.Stderr)) } - cfg := &clientConfig{} - cfg.endpoints, err = endpointsFromCmd(cmd) + cfg := &clientv3.ConfigSpec{} + cfg.Endpoints, err = endpointsFromCmd(cmd) if err != nil { cobrautl.ExitWithError(cobrautl.ExitError, err) } - cfg.dialTimeout = dialTimeoutFromCmd(cmd) - cfg.keepAliveTime = keepAliveTimeFromCmd(cmd) - cfg.keepAliveTimeout = keepAliveTimeoutFromCmd(cmd) + cfg.DialTimeout = dialTimeoutFromCmd(cmd) + cfg.KeepAliveTime = keepAliveTimeFromCmd(cmd) + cfg.KeepAliveTimeout = keepAliveTimeoutFromCmd(cmd) - cfg.scfg = secureCfgFromCmd(cmd) - cfg.acfg = authCfgFromCmd(cmd) + cfg.Secure = secureCfgFromCmd(cmd) + cfg.Auth = authCfgFromCmd(cmd) initDisplayFromCmd(cmd) return cfg @@ -162,7 +138,7 @@ func clientConfigFromCmd(cmd *cobra.Command) *clientConfig { func mustClientCfgFromCmd(cmd *cobra.Command) *clientv3.Config { cc := clientConfigFromCmd(cmd) - cfg, err := newClientCfg(cc.endpoints, cc.dialTimeout, cc.keepAliveTime, cc.keepAliveTimeout, cc.scfg, cc.acfg) + cfg, err := newClientCfg(cc.Endpoints, cc.DialTimeout, cc.KeepAliveTime, cc.KeepAliveTimeout, cc.Secure, cc.Auth) if err != nil { cobrautl.ExitWithError(cobrautl.ExitBadArgs, err) } @@ -171,11 +147,11 @@ func mustClientCfgFromCmd(cmd *cobra.Command) *clientv3.Config { func mustClientFromCmd(cmd *cobra.Command) *clientv3.Client { cfg := clientConfigFromCmd(cmd) - return cfg.mustClient() + return mustClient(cfg) } -func (cc *clientConfig) mustClient() *clientv3.Client { - cfg, err := newClientCfg(cc.endpoints, cc.dialTimeout, cc.keepAliveTime, cc.keepAliveTimeout, cc.scfg, cc.acfg) +func mustClient(cc *clientv3.ConfigSpec) *clientv3.Client { + cfg, err := newClientCfg(cc.Endpoints, cc.DialTimeout, cc.KeepAliveTime, cc.KeepAliveTimeout, cc.Secure, cc.Auth) if err != nil { cobrautl.ExitWithError(cobrautl.ExitBadArgs, err) } @@ -188,28 +164,28 @@ func (cc *clientConfig) mustClient() *clientv3.Client { return client } -func newClientCfg(endpoints []string, dialTimeout, keepAliveTime, keepAliveTimeout time.Duration, scfg *secureCfg, acfg *authCfg) (*clientv3.Config, error) { +func newClientCfg(endpoints []string, dialTimeout, keepAliveTime, keepAliveTimeout time.Duration, scfg *clientv3.SecureConfig, acfg *clientv3.AuthConfig) (*clientv3.Config, error) { // set tls if any one tls option set var cfgtls *transport.TLSInfo tlsinfo := transport.TLSInfo{} tlsinfo.Logger, _ = zap.NewProduction() - if scfg.cert != "" { - tlsinfo.CertFile = scfg.cert + if scfg.Cert != "" { + tlsinfo.CertFile = scfg.Cert cfgtls = &tlsinfo } - if scfg.key != "" { - tlsinfo.KeyFile = scfg.key + if scfg.Key != "" { + tlsinfo.KeyFile = scfg.Key cfgtls = &tlsinfo } - if scfg.cacert != "" { - tlsinfo.TrustedCAFile = scfg.cacert + if scfg.Cacert != "" { + tlsinfo.TrustedCAFile = scfg.Cacert cfgtls = &tlsinfo } - if scfg.serverName != "" { - tlsinfo.ServerName = scfg.serverName + if scfg.ServerName != "" { + tlsinfo.ServerName = scfg.ServerName cfgtls = &tlsinfo } @@ -231,19 +207,19 @@ func newClientCfg(endpoints []string, dialTimeout, keepAliveTime, keepAliveTimeo // 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. - if cfg.TLS == nil && !scfg.insecureTransport { + if cfg.TLS == nil && !scfg.InsecureTransport { cfg.TLS = &tls.Config{} } // If the user wants to skip TLS verification then we should set // the InsecureSkipVerify flag in tls configuration. - if scfg.insecureSkipVerify && cfg.TLS != nil { + if scfg.InsecureSkipVerify && cfg.TLS != nil { cfg.TLS.InsecureSkipVerify = true } if acfg != nil { - cfg.Username = acfg.username - cfg.Password = acfg.password + cfg.Username = acfg.Username + cfg.Password = acfg.Password } return cfg, nil @@ -284,7 +260,7 @@ func keepAliveTimeoutFromCmd(cmd *cobra.Command) time.Duration { return keepAliveTimeout } -func secureCfgFromCmd(cmd *cobra.Command) *secureCfg { +func secureCfgFromCmd(cmd *cobra.Command) *clientv3.SecureConfig { cert, key, cacert := keyAndCertFromCmd(cmd) insecureTr := insecureTransportFromCmd(cmd) skipVerify := insecureSkipVerifyFromCmd(cmd) @@ -294,14 +270,14 @@ func secureCfgFromCmd(cmd *cobra.Command) *secureCfg { discoveryCfg.domain = "" } - return &secureCfg{ - cert: cert, - key: key, - cacert: cacert, - serverName: discoveryCfg.domain, + return &clientv3.SecureConfig{ + Cert: cert, + Key: key, + Cacert: cacert, + ServerName: discoveryCfg.domain, - insecureTransport: insecureTr, - insecureSkipVerify: skipVerify, + InsecureTransport: insecureTr, + InsecureSkipVerify: skipVerify, } } @@ -344,7 +320,7 @@ func keyAndCertFromCmd(cmd *cobra.Command) (cert, key, cacert string) { return cert, key, cacert } -func authCfgFromCmd(cmd *cobra.Command) *authCfg { +func authCfgFromCmd(cmd *cobra.Command) *clientv3.AuthConfig { userFlag, err := cmd.Flags().GetString("user") if err != nil { cobrautl.ExitWithError(cobrautl.ExitBadArgs, err) @@ -358,23 +334,23 @@ func authCfgFromCmd(cmd *cobra.Command) *authCfg { return nil } - var cfg authCfg + var cfg clientv3.AuthConfig if passwordFlag == "" { splitted := strings.SplitN(userFlag, ":", 2) if len(splitted) < 2 { - cfg.username = userFlag - cfg.password, err = speakeasy.Ask("Password: ") + cfg.Username = userFlag + cfg.Password, err = speakeasy.Ask("Password: ") if err != nil { cobrautl.ExitWithError(cobrautl.ExitError, err) } } else { - cfg.username = splitted[0] - cfg.password = splitted[1] + cfg.Username = splitted[0] + cfg.Password = splitted[1] } } else { - cfg.username = userFlag - cfg.password = passwordFlag + cfg.Username = userFlag + cfg.Password = passwordFlag } return &cfg diff --git a/etcdctl/ctlv3/command/make_mirror_command.go b/etcdctl/ctlv3/command/make_mirror_command.go index 3d8b869d0c8..e93e108ea1d 100644 --- a/etcdctl/ctlv3/command/make_mirror_command.go +++ b/etcdctl/ctlv3/command/make_mirror_command.go @@ -69,29 +69,29 @@ func NewMakeMirrorCommand() *cobra.Command { return c } -func authDestCfg() *authCfg { +func authDestCfg() *clientv3.AuthConfig { if mmuser == "" { return nil } - var cfg authCfg + var cfg clientv3.AuthConfig if mmpassword == "" { splitted := strings.SplitN(mmuser, ":", 2) if len(splitted) < 2 { var err error - cfg.username = mmuser - cfg.password, err = speakeasy.Ask("Destination Password: ") + cfg.Username = mmuser + cfg.Password, err = speakeasy.Ask("Destination Password: ") if err != nil { cobrautl.ExitWithError(cobrautl.ExitError, err) } } else { - cfg.username = splitted[0] - cfg.password = splitted[1] + cfg.Username = splitted[0] + cfg.Password = splitted[1] } } else { - cfg.username = mmuser - cfg.password = mmpassword + cfg.Username = mmuser + cfg.Password = mmpassword } return &cfg @@ -105,24 +105,24 @@ func makeMirrorCommandFunc(cmd *cobra.Command, args []string) { dialTimeout := dialTimeoutFromCmd(cmd) keepAliveTime := keepAliveTimeFromCmd(cmd) keepAliveTimeout := keepAliveTimeoutFromCmd(cmd) - sec := &secureCfg{ - cert: mmcert, - key: mmkey, - cacert: mmcacert, - insecureTransport: mminsecureTr, + sec := &clientv3.SecureConfig{ + Cert: mmcert, + Key: mmkey, + Cacert: mmcacert, + InsecureTransport: mminsecureTr, } auth := authDestCfg() - cc := &clientConfig{ - endpoints: []string{args[0]}, - dialTimeout: dialTimeout, - keepAliveTime: keepAliveTime, - keepAliveTimeout: keepAliveTimeout, - scfg: sec, - acfg: auth, + cc := &clientv3.ConfigSpec{ + Endpoints: []string{args[0]}, + DialTimeout: dialTimeout, + KeepAliveTime: keepAliveTime, + KeepAliveTimeout: keepAliveTimeout, + Secure: sec, + Auth: auth, } - dc := cc.mustClient() + dc := mustClient(cc) c := mustClientFromCmd(cmd) err := makeMirror(context.TODO(), c, dc) diff --git a/etcdctl/ctlv3/command/move_leader_command.go b/etcdctl/ctlv3/command/move_leader_command.go index 098c897cd7a..76b1736d541 100644 --- a/etcdctl/ctlv3/command/move_leader_command.go +++ b/etcdctl/ctlv3/command/move_leader_command.go @@ -54,8 +54,8 @@ func transferLeadershipCommandFunc(cmd *cobra.Command, args []string) { var leaderID uint64 for _, ep := range eps { cfg := clientConfigFromCmd(cmd) - cfg.endpoints = []string{ep} - cli := cfg.mustClient() + cfg.Endpoints = []string{ep} + cli := mustClient(cfg) resp, serr := cli.Status(ctx, ep) if serr != nil { cobrautl.ExitWithError(cobrautl.ExitError, serr) diff --git a/etcdctl/ctlv3/command/util.go b/etcdctl/ctlv3/command/util.go index 27f1e51e9b1..86f83be36de 100644 --- a/etcdctl/ctlv3/command/util.go +++ b/etcdctl/ctlv3/command/util.go @@ -27,7 +27,7 @@ import ( "time" pb "go.etcd.io/etcd/api/v3/mvccpb" - v3 "go.etcd.io/etcd/client/v3" + "go.etcd.io/etcd/client/v3" "go.etcd.io/etcd/pkg/v3/cobrautl" "github.com/spf13/cobra" @@ -93,7 +93,7 @@ func isCommandTimeoutFlagSet(cmd *cobra.Command) bool { } // get the process_resident_memory_bytes from /metrics -func endpointMemoryMetrics(host string, scfg *secureCfg) float64 { +func endpointMemoryMetrics(host string, scfg *clientv3.SecureConfig) float64 { residentMemoryKey := "process_resident_memory_bytes" var residentMemoryValue string if !strings.HasPrefix(host, "http://") && !strings.HasPrefix(host, "https://") { @@ -102,14 +102,14 @@ func endpointMemoryMetrics(host string, scfg *secureCfg) float64 { url := host + "/metrics" if strings.HasPrefix(host, "https://") { // load client certificate - cert, err := tls.LoadX509KeyPair(scfg.cert, scfg.key) + cert, err := tls.LoadX509KeyPair(scfg.Cert, scfg.Key) if err != nil { fmt.Println(fmt.Sprintf("client certificate error: %v", err)) return 0.0 } http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{ Certificates: []tls.Certificate{cert}, - InsecureSkipVerify: scfg.insecureSkipVerify, + InsecureSkipVerify: scfg.InsecureSkipVerify, } } resp, err := http.Get(url) @@ -144,10 +144,10 @@ func endpointMemoryMetrics(host string, scfg *secureCfg) float64 { } // compact keyspace history to a provided revision -func compact(c *v3.Client, rev int64) { +func compact(c *clientv3.Client, rev int64) { fmt.Printf("Compacting with revision %d\n", rev) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - _, err := c.Compact(ctx, rev, v3.WithCompactPhysical()) + _, err := c.Compact(ctx, rev, clientv3.WithCompactPhysical()) cancel() if err != nil { cobrautl.ExitWithError(cobrautl.ExitError, err) @@ -156,7 +156,7 @@ func compact(c *v3.Client, rev int64) { } // defrag a given endpoint -func defrag(c *v3.Client, ep string) { +func defrag(c *clientv3.Client, ep string) { fmt.Printf("Defragmenting %q\n", ep) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) _, err := c.Defragment(ctx, ep) diff --git a/server/embed/config.go b/server/embed/config.go index e6f9e3a3234..21218e66e1c 100644 --- a/server/embed/config.go +++ b/server/embed/config.go @@ -31,6 +31,7 @@ import ( "go.etcd.io/etcd/client/pkg/v3/tlsutil" "go.etcd.io/etcd/client/pkg/v3/transport" "go.etcd.io/etcd/client/pkg/v3/types" + "go.etcd.io/etcd/client/v3" "go.etcd.io/etcd/pkg/v3/flags" "go.etcd.io/etcd/pkg/v3/netutil" "go.etcd.io/etcd/server/v3/config" @@ -516,10 +517,15 @@ func NewConfig() *Config { V2Deprecation: config.V2_DEPR_DEFAULT, DiscoveryCfg: v3discovery.DiscoveryConfig{ - DialTimeout: DefaultDiscoveryDialTimeout, - RequestTimeOut: DefaultDiscoveryRequestTimeOut, - KeepAliveTime: DefaultDiscoveryKeepAliveTime, - KeepAliveTimeout: DefaultDiscoveryKeepAliveTimeOut, + ConfigSpec: clientv3.ConfigSpec{ + DialTimeout: DefaultDiscoveryDialTimeout, + RequestTimeout: DefaultDiscoveryRequestTimeOut, + KeepAliveTime: DefaultDiscoveryKeepAliveTime, + KeepAliveTimeout: DefaultDiscoveryKeepAliveTimeOut, + + Secure: &clientv3.SecureConfig{}, + Auth: &clientv3.AuthConfig{}, + }, }, } cfg.InitialCluster = cfg.InitialClusterFromName(cfg.Name) @@ -688,11 +694,11 @@ func (cfg *Config) Validate() error { v2discoveryFlagsExist := cfg.Dproxy != "" v3discoveryFlagsExist := len(cfg.DiscoveryCfg.Endpoints) > 0 || cfg.DiscoveryCfg.Token != "" || - cfg.DiscoveryCfg.CertFile != "" || - cfg.DiscoveryCfg.KeyFile != "" || - cfg.DiscoveryCfg.TrustedCAFile != "" || - cfg.DiscoveryCfg.User != "" || - cfg.DiscoveryCfg.Password != "" + cfg.DiscoveryCfg.Secure.Cert != "" || + cfg.DiscoveryCfg.Secure.Key != "" || + cfg.DiscoveryCfg.Secure.Cacert != "" || + cfg.DiscoveryCfg.Auth.Username != "" || + cfg.DiscoveryCfg.Auth.Password != "" if v2discoveryFlagsExist && v3discoveryFlagsExist { return errors.New("both v2 discovery settings (discovery, discovery-proxy) " + diff --git a/server/embed/etcd.go b/server/embed/etcd.go index aa59cc84452..e955efd925b 100644 --- a/server/embed/etcd.go +++ b/server/embed/etcd.go @@ -349,15 +349,15 @@ func print(lg *zap.Logger, ec Config, sc config.ServerConfig, memberInitialized zap.String("discovery-token", sc.DiscoveryCfg.Token), zap.String("discovery-endpoints", strings.Join(sc.DiscoveryCfg.Endpoints, ",")), zap.String("discovery-dial-timeout", sc.DiscoveryCfg.DialTimeout.String()), - zap.String("discovery-request-timeout", sc.DiscoveryCfg.RequestTimeOut.String()), + zap.String("discovery-request-timeout", sc.DiscoveryCfg.RequestTimeout.String()), zap.String("discovery-keepalive-time", sc.DiscoveryCfg.KeepAliveTime.String()), zap.String("discovery-keepalive-timeout", sc.DiscoveryCfg.KeepAliveTimeout.String()), - zap.Bool("discovery-insecure-transport", sc.DiscoveryCfg.InsecureTransport), - zap.Bool("discovery-insecure-skip-tls-verify", sc.DiscoveryCfg.InsecureSkipVerify), - zap.String("discovery-cert", sc.DiscoveryCfg.CertFile), - zap.String("discovery-key", sc.DiscoveryCfg.KeyFile), - zap.String("discovery-cacert", sc.DiscoveryCfg.TrustedCAFile), - zap.String("discovery-user", sc.DiscoveryCfg.User), + zap.Bool("discovery-insecure-transport", sc.DiscoveryCfg.Secure.InsecureTransport), + zap.Bool("discovery-insecure-skip-tls-verify", sc.DiscoveryCfg.Secure.InsecureSkipVerify), + zap.String("discovery-cert", sc.DiscoveryCfg.Secure.Cert), + zap.String("discovery-key", sc.DiscoveryCfg.Secure.Key), + zap.String("discovery-cacert", sc.DiscoveryCfg.Secure.Cacert), + zap.String("discovery-user", sc.DiscoveryCfg.Auth.Username), zap.String("downgrade-check-interval", sc.DowngradeCheckTime.String()), zap.Int("max-learners", sc.ExperimentalMaxLearners), diff --git a/server/etcdmain/config.go b/server/etcdmain/config.go index dc78e1d532b..71a776373e7 100644 --- a/server/etcdmain/config.go +++ b/server/etcdmain/config.go @@ -196,16 +196,16 @@ func newConfig() *config { ) fs.StringVar(&cfg.ec.DiscoveryCfg.Token, "discovery-token", "", "V3 discovery: discovery token for the etcd cluster to be bootstrapped.") fs.DurationVar(&cfg.ec.DiscoveryCfg.DialTimeout, "discovery-dial-timeout", cfg.ec.DiscoveryCfg.DialTimeout, "V3 discovery: dial timeout for client connections.") - fs.DurationVar(&cfg.ec.DiscoveryCfg.RequestTimeOut, "discovery-request-timeout", cfg.ec.DiscoveryCfg.RequestTimeOut, "V3 discovery: timeout for discovery requests (excluding dial timeout).") + fs.DurationVar(&cfg.ec.DiscoveryCfg.RequestTimeout, "discovery-request-timeout", cfg.ec.DiscoveryCfg.RequestTimeout, "V3 discovery: timeout for discovery requests (excluding dial timeout).") fs.DurationVar(&cfg.ec.DiscoveryCfg.KeepAliveTime, "discovery-keepalive-time", cfg.ec.DiscoveryCfg.KeepAliveTime, "V3 discovery: keepalive time for client connections.") fs.DurationVar(&cfg.ec.DiscoveryCfg.KeepAliveTimeout, "discovery-keepalive-timeout", cfg.ec.DiscoveryCfg.KeepAliveTimeout, "V3 discovery: keepalive timeout for client connections.") - fs.BoolVar(&cfg.ec.DiscoveryCfg.InsecureTransport, "discovery-insecure-transport", true, "V3 discovery: disable transport security for client connections.") - fs.BoolVar(&cfg.ec.DiscoveryCfg.InsecureSkipVerify, "discovery-insecure-skip-tls-verify", false, "V3 discovery: skip server certificate verification (CAUTION: this option should be enabled only for testing purposes).") - fs.StringVar(&cfg.ec.DiscoveryCfg.CertFile, "discovery-cert", "", "V3 discovery: identify secure client using this TLS certificate file.") - fs.StringVar(&cfg.ec.DiscoveryCfg.KeyFile, "discovery-key", "", "V3 discovery: identify secure client using this TLS key file.") - fs.StringVar(&cfg.ec.DiscoveryCfg.TrustedCAFile, "discovery-cacert", "", "V3 discovery: verify certificates of TLS-enabled secure servers using this CA bundle.") - fs.StringVar(&cfg.ec.DiscoveryCfg.User, "discovery-user", "", "V3 discovery: username[:password] for authentication (prompt if password is not supplied).") - fs.StringVar(&cfg.ec.DiscoveryCfg.Password, "discovery-password", "", "V3 discovery: password for authentication (if this option is used, --user option shouldn't include password).") + fs.BoolVar(&cfg.ec.DiscoveryCfg.Secure.InsecureTransport, "discovery-insecure-transport", true, "V3 discovery: disable transport security for client connections.") + fs.BoolVar(&cfg.ec.DiscoveryCfg.Secure.InsecureSkipVerify, "discovery-insecure-skip-tls-verify", false, "V3 discovery: skip server certificate verification (CAUTION: this option should be enabled only for testing purposes).") + fs.StringVar(&cfg.ec.DiscoveryCfg.Secure.Cert, "discovery-cert", "", "V3 discovery: identify secure client using this TLS certificate file.") + fs.StringVar(&cfg.ec.DiscoveryCfg.Secure.Key, "discovery-key", "", "V3 discovery: identify secure client using this TLS key file.") + fs.StringVar(&cfg.ec.DiscoveryCfg.Secure.Cacert, "discovery-cacert", "", "V3 discovery: verify certificates of TLS-enabled secure servers using this CA bundle.") + fs.StringVar(&cfg.ec.DiscoveryCfg.Auth.Username, "discovery-user", "", "V3 discovery: username[:password] for authentication (prompt if password is not supplied).") + fs.StringVar(&cfg.ec.DiscoveryCfg.Auth.Password, "discovery-password", "", "V3 discovery: password for authentication (if this option is used, --user option shouldn't include password).") fs.StringVar(&cfg.ec.Dproxy, "discovery-proxy", cfg.ec.Dproxy, "HTTP proxy to use for traffic to discovery service. Will be deprecated in v3.7, and be decommissioned in v3.8.") fs.StringVar(&cfg.ec.DNSCluster, "discovery-srv", cfg.ec.DNSCluster, "DNS domain used to bootstrap initial cluster.") diff --git a/server/etcdserver/api/v3discovery/discovery.go b/server/etcdserver/api/v3discovery/discovery.go index cb91d6ed7c9..1c274cdba17 100644 --- a/server/etcdserver/api/v3discovery/discovery.go +++ b/server/etcdserver/api/v3discovery/discovery.go @@ -55,22 +55,8 @@ var ( ) type DiscoveryConfig struct { - Token string `json:"discovery-token"` - Endpoints []string `json:"discovery-endpoints"` - - DialTimeout time.Duration `json:"discovery-dial-timeout"` - RequestTimeOut time.Duration `json:"discovery-request-timeout"` - KeepAliveTime time.Duration `json:"discovery-keepalive-time"` - KeepAliveTimeout time.Duration `json:"discovery-keepalive-timeout"` - - InsecureTransport bool `json:"discovery-insecure-transport"` - InsecureSkipVerify bool `json:"discovery-insecure-skip-tls-verify"` - CertFile string `json:"discovery-cert"` - KeyFile string `json:"discovery-key"` - TrustedCAFile string `json:"discovery-cacert"` - - User string `json:"discovery-user"` - Password string `json:"discovery-password"` + clientv3.ConfigSpec `json:"client"` + Token string `json:"token"` } type memberInfo struct { @@ -91,18 +77,18 @@ type clusterInfo struct { } // key prefix for each cluster: "/_etcd/registry/". -func geClusterKeyPrefix(cluster string) string { +func getClusterKeyPrefix(cluster string) string { return path.Join(discoveryPrefix, cluster) } // key format for cluster size: "/_etcd/registry//_config/size". -func geClusterSizeKey(cluster string) string { - return path.Join(geClusterKeyPrefix(cluster), "_config/size") +func getClusterSizeKey(cluster string) string { + return path.Join(getClusterKeyPrefix(cluster), "_config/size") } // key prefix for each member: "/_etcd/registry//members". func getMemberKeyPrefix(clusterToken string) string { - return path.Join(geClusterKeyPrefix(clusterToken), "members") + return path.Join(getClusterKeyPrefix(clusterToken), "members") } // key format for each member: "/_etcd/registry//members/". @@ -211,11 +197,11 @@ func newDiscovery(lg *zap.Logger, dcfg *DiscoveryConfig, id types.ID) (*discover func newClientCfg(dcfg *DiscoveryConfig, lg *zap.Logger) (*clientv3.Config, error) { var cfgtls *transport.TLSInfo - if dcfg.CertFile != "" || dcfg.KeyFile != "" || dcfg.TrustedCAFile != "" { + if dcfg.Secure.Cert != "" || dcfg.Secure.Key != "" || dcfg.Secure.Cacert != "" { cfgtls = &transport.TLSInfo{ - CertFile: dcfg.CertFile, - KeyFile: dcfg.KeyFile, - TrustedCAFile: dcfg.TrustedCAFile, + CertFile: dcfg.Secure.Cert, + KeyFile: dcfg.Secure.Key, + TrustedCAFile: dcfg.Secure.Cacert, Logger: lg, } } @@ -225,8 +211,8 @@ func newClientCfg(dcfg *DiscoveryConfig, lg *zap.Logger) (*clientv3.Config, erro DialTimeout: dcfg.DialTimeout, DialKeepAliveTime: dcfg.KeepAliveTime, DialKeepAliveTimeout: dcfg.KeepAliveTimeout, - Username: dcfg.User, - Password: dcfg.Password, + Username: dcfg.Auth.Username, + Password: dcfg.Auth.Password, } if cfgtls != nil { @@ -240,13 +226,13 @@ func newClientCfg(dcfg *DiscoveryConfig, lg *zap.Logger) (*clientv3.Config, erro // 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. - if cfg.TLS == nil && !dcfg.InsecureTransport { + if cfg.TLS == nil && !dcfg.Secure.InsecureTransport { cfg.TLS = &tls.Config{} } // If the user wants to skip TLS verification then we should set // the InsecureSkipVerify flag in tls configuration. - if cfg.TLS != nil && dcfg.InsecureSkipVerify { + if cfg.TLS != nil && dcfg.Secure.InsecureSkipVerify { cfg.TLS.InsecureSkipVerify = true } @@ -292,8 +278,8 @@ func (d *discovery) joinCluster(config string) (string, error) { } func (d *discovery) getClusterSize() (int, error) { - configKey := geClusterSizeKey(d.clusterToken) - ctx, cancel := context.WithTimeout(context.Background(), d.cfg.RequestTimeOut) + configKey := getClusterSizeKey(d.clusterToken) + ctx, cancel := context.WithTimeout(context.Background(), d.cfg.RequestTimeout) defer cancel() resp, err := d.c.Get(ctx, configKey) @@ -320,7 +306,7 @@ func (d *discovery) getClusterSize() (int, error) { func (d *discovery) getClusterMembers() (*clusterInfo, int64, error) { membersKeyPrefix := getMemberKeyPrefix(d.clusterToken) - ctx, cancel := context.WithTimeout(context.Background(), d.cfg.RequestTimeOut) + ctx, cancel := context.WithTimeout(context.Background(), d.cfg.RequestTimeout) defer cancel() resp, err := d.c.Get(ctx, membersKeyPrefix, clientv3.WithPrefix()) @@ -404,7 +390,7 @@ func (d *discovery) registerSelfRetry(contents string) error { } func (d *discovery) registerSelf(contents string) error { - ctx, cancel := context.WithTimeout(context.Background(), d.cfg.RequestTimeOut) + ctx, cancel := context.WithTimeout(context.Background(), d.cfg.RequestTimeout) memberKey := getMemberKey(d.clusterToken, d.memberId.String()) _, err := d.c.Put(ctx, memberKey, contents) cancel()