diff --git a/etcdmain/config.go b/etcdmain/config.go index 75ba112b3..b709a8c2c 100644 --- a/etcdmain/config.go +++ b/etcdmain/config.go @@ -75,9 +75,9 @@ type configProxy struct { // config holds the config for a command line invocation of etcd type config struct { - embed.Config - configProxy - configFlags + ec embed.Config + cp configProxy + cf configFlags configFile string printVersion bool ignored []string @@ -85,7 +85,7 @@ type config struct { // configFlags has the set of flags used for command line parsing a Config type configFlags struct { - *flag.FlagSet + flagSet *flag.FlagSet clusterState *flags.StringsFlag fallback *flags.StringsFlag proxy *flags.StringsFlag @@ -93,8 +93,8 @@ type configFlags struct { func newConfig() *config { cfg := &config{ - Config: *embed.NewConfig(), - configProxy: configProxy{ + ec: *embed.NewConfig(), + cp: configProxy{ Proxy: proxyFlagOff, ProxyFailureWaitMs: 5000, ProxyRefreshIntervalMs: 30000, @@ -103,8 +103,8 @@ func newConfig() *config { }, ignored: ignored, } - cfg.configFlags = configFlags{ - FlagSet: flag.NewFlagSet("etcd", flag.ContinueOnError), + cfg.cf = configFlags{ + flagSet: flag.NewFlagSet("etcd", flag.ContinueOnError), clusterState: flags.NewStringsFlag( embed.ClusterStateFlagNew, embed.ClusterStateFlagExisting, @@ -120,7 +120,7 @@ func newConfig() *config { ), } - fs := cfg.FlagSet + fs := cfg.cf.flagSet fs.Usage = func() { fmt.Fprintln(os.Stderr, usageline) } @@ -128,92 +128,92 @@ func newConfig() *config { fs.StringVar(&cfg.configFile, "config-file", "", "Path to the server configuration file") // member - fs.Var(cfg.CorsInfo, "cors", "Comma-separated white list of origins for CORS (cross-origin resource sharing).") - fs.StringVar(&cfg.Dir, "data-dir", cfg.Dir, "Path to the data directory.") - fs.StringVar(&cfg.WalDir, "wal-dir", cfg.WalDir, "Path to the dedicated wal directory.") + fs.Var(cfg.ec.CorsInfo, "cors", "Comma-separated white list of origins for CORS (cross-origin resource sharing).") + fs.StringVar(&cfg.ec.Dir, "data-dir", cfg.ec.Dir, "Path to the data directory.") + fs.StringVar(&cfg.ec.WalDir, "wal-dir", cfg.ec.WalDir, "Path to the dedicated wal directory.") fs.Var(flags.NewURLsValue(embed.DefaultListenPeerURLs), "listen-peer-urls", "List of URLs to listen on for peer traffic.") fs.Var(flags.NewURLsValue(embed.DefaultListenClientURLs), "listen-client-urls", "List of URLs to listen on for client traffic.") - fs.StringVar(&cfg.ListenMetricsUrlsJSON, "listen-metrics-urls", "", "List of URLs to listen on for metrics.") - fs.UintVar(&cfg.MaxSnapFiles, "max-snapshots", cfg.MaxSnapFiles, "Maximum number of snapshot files to retain (0 is unlimited).") - fs.UintVar(&cfg.MaxWalFiles, "max-wals", cfg.MaxWalFiles, "Maximum number of wal files to retain (0 is unlimited).") - fs.StringVar(&cfg.Name, "name", cfg.Name, "Human-readable name for this member.") - fs.Uint64Var(&cfg.SnapCount, "snapshot-count", cfg.SnapCount, "Number of committed transactions to trigger a snapshot to disk.") - fs.UintVar(&cfg.TickMs, "heartbeat-interval", cfg.TickMs, "Time (in milliseconds) of a heartbeat interval.") - fs.UintVar(&cfg.ElectionMs, "election-timeout", cfg.ElectionMs, "Time (in milliseconds) for an election to timeout.") - fs.Int64Var(&cfg.QuotaBackendBytes, "quota-backend-bytes", cfg.QuotaBackendBytes, "Raise alarms when backend size exceeds the given quota. 0 means use the default quota.") - fs.UintVar(&cfg.MaxTxnOps, "max-txn-ops", cfg.MaxTxnOps, "Maximum number of operations permitted in a transaction.") - fs.UintVar(&cfg.MaxRequestBytes, "max-request-bytes", cfg.MaxRequestBytes, "Maximum client request size in bytes the server will accept.") - fs.DurationVar(&cfg.GRPCKeepAliveMinTime, "grpc-keepalive-min-time", cfg.Config.GRPCKeepAliveMinTime, "Minimum interval duration that a client should wait before pinging server.") - fs.DurationVar(&cfg.GRPCKeepAliveInterval, "grpc-keepalive-interval", cfg.Config.GRPCKeepAliveInterval, "Frequency duration of server-to-client ping to check if a connection is alive (0 to disable).") - fs.DurationVar(&cfg.GRPCKeepAliveTimeout, "grpc-keepalive-timeout", cfg.Config.GRPCKeepAliveTimeout, "Additional duration of wait before closing a non-responsive connection (0 to disable).") + fs.StringVar(&cfg.ec.ListenMetricsUrlsJSON, "listen-metrics-urls", "", "List of URLs to listen on for metrics.") + fs.UintVar(&cfg.ec.MaxSnapFiles, "max-snapshots", cfg.ec.MaxSnapFiles, "Maximum number of snapshot files to retain (0 is unlimited).") + fs.UintVar(&cfg.ec.MaxWalFiles, "max-wals", cfg.ec.MaxWalFiles, "Maximum number of wal files to retain (0 is unlimited).") + fs.StringVar(&cfg.ec.Name, "name", cfg.ec.Name, "Human-readable name for this member.") + fs.Uint64Var(&cfg.ec.SnapCount, "snapshot-count", cfg.ec.SnapCount, "Number of committed transactions to trigger a snapshot to disk.") + fs.UintVar(&cfg.ec.TickMs, "heartbeat-interval", cfg.ec.TickMs, "Time (in milliseconds) of a heartbeat interval.") + fs.UintVar(&cfg.ec.ElectionMs, "election-timeout", cfg.ec.ElectionMs, "Time (in milliseconds) for an election to timeout.") + fs.Int64Var(&cfg.ec.QuotaBackendBytes, "quota-backend-bytes", cfg.ec.QuotaBackendBytes, "Raise alarms when backend size exceeds the given quota. 0 means use the default quota.") + fs.UintVar(&cfg.ec.MaxTxnOps, "max-txn-ops", cfg.ec.MaxTxnOps, "Maximum number of operations permitted in a transaction.") + fs.UintVar(&cfg.ec.MaxRequestBytes, "max-request-bytes", cfg.ec.MaxRequestBytes, "Maximum client request size in bytes the server will accept.") + fs.DurationVar(&cfg.ec.GRPCKeepAliveMinTime, "grpc-keepalive-min-time", cfg.ec.GRPCKeepAliveMinTime, "Minimum interval duration that a client should wait before pinging server.") + fs.DurationVar(&cfg.ec.GRPCKeepAliveInterval, "grpc-keepalive-interval", cfg.ec.GRPCKeepAliveInterval, "Frequency duration of server-to-client ping to check if a connection is alive (0 to disable).") + fs.DurationVar(&cfg.ec.GRPCKeepAliveTimeout, "grpc-keepalive-timeout", cfg.ec.GRPCKeepAliveTimeout, "Additional duration of wait before closing a non-responsive connection (0 to disable).") // clustering fs.Var(flags.NewURLsValue(embed.DefaultInitialAdvertisePeerURLs), "initial-advertise-peer-urls", "List of this member's peer URLs to advertise to the rest of the cluster.") fs.Var(flags.NewURLsValue(embed.DefaultAdvertiseClientURLs), "advertise-client-urls", "List of this member's client URLs to advertise to the public.") - fs.StringVar(&cfg.Durl, "discovery", cfg.Durl, "Discovery URL used to bootstrap the cluster.") - fs.Var(cfg.fallback, "discovery-fallback", fmt.Sprintf("Valid values include %s", strings.Join(cfg.fallback.Values, ", "))) + fs.StringVar(&cfg.ec.Durl, "discovery", cfg.ec.Durl, "Discovery URL used to bootstrap the cluster.") + fs.Var(cfg.cf.fallback, "discovery-fallback", fmt.Sprintf("Valid values include %s", strings.Join(cfg.cf.fallback.Values, ", "))) - fs.StringVar(&cfg.Dproxy, "discovery-proxy", cfg.Dproxy, "HTTP proxy to use for traffic to discovery service.") - fs.StringVar(&cfg.DNSCluster, "discovery-srv", cfg.DNSCluster, "DNS domain used to bootstrap initial cluster.") - fs.StringVar(&cfg.InitialCluster, "initial-cluster", cfg.InitialCluster, "Initial cluster configuration for bootstrapping.") - fs.StringVar(&cfg.InitialClusterToken, "initial-cluster-token", cfg.InitialClusterToken, "Initial cluster token for the etcd cluster during bootstrap.") - fs.Var(cfg.clusterState, "initial-cluster-state", "Initial cluster state ('new' or 'existing').") + fs.StringVar(&cfg.ec.Dproxy, "discovery-proxy", cfg.ec.Dproxy, "HTTP proxy to use for traffic to discovery service.") + fs.StringVar(&cfg.ec.DNSCluster, "discovery-srv", cfg.ec.DNSCluster, "DNS domain used to bootstrap initial cluster.") + fs.StringVar(&cfg.ec.InitialCluster, "initial-cluster", cfg.ec.InitialCluster, "Initial cluster configuration for bootstrapping.") + fs.StringVar(&cfg.ec.InitialClusterToken, "initial-cluster-token", cfg.ec.InitialClusterToken, "Initial cluster token for the etcd cluster during bootstrap.") + fs.Var(cfg.cf.clusterState, "initial-cluster-state", "Initial cluster state ('new' or 'existing').") - fs.BoolVar(&cfg.StrictReconfigCheck, "strict-reconfig-check", cfg.StrictReconfigCheck, "Reject reconfiguration requests that would cause quorum loss.") - fs.BoolVar(&cfg.EnableV2, "enable-v2", true, "Accept etcd V2 client requests.") - fs.StringVar(&cfg.ExperimentalEnableV2V3, "experimental-enable-v2v3", cfg.ExperimentalEnableV2V3, "v3 prefix for serving emulated v2 state.") + fs.BoolVar(&cfg.ec.StrictReconfigCheck, "strict-reconfig-check", cfg.ec.StrictReconfigCheck, "Reject reconfiguration requests that would cause quorum loss.") + fs.BoolVar(&cfg.ec.EnableV2, "enable-v2", true, "Accept etcd V2 client requests.") + fs.StringVar(&cfg.ec.ExperimentalEnableV2V3, "experimental-enable-v2v3", cfg.ec.ExperimentalEnableV2V3, "v3 prefix for serving emulated v2 state.") // proxy - fs.Var(cfg.proxy, "proxy", fmt.Sprintf("Valid values include %s", strings.Join(cfg.proxy.Values, ", "))) + fs.Var(cfg.cf.proxy, "proxy", fmt.Sprintf("Valid values include %s", strings.Join(cfg.cf.proxy.Values, ", "))) - fs.UintVar(&cfg.ProxyFailureWaitMs, "proxy-failure-wait", cfg.ProxyFailureWaitMs, "Time (in milliseconds) an endpoint will be held in a failed state.") - fs.UintVar(&cfg.ProxyRefreshIntervalMs, "proxy-refresh-interval", cfg.ProxyRefreshIntervalMs, "Time (in milliseconds) of the endpoints refresh interval.") - fs.UintVar(&cfg.ProxyDialTimeoutMs, "proxy-dial-timeout", cfg.ProxyDialTimeoutMs, "Time (in milliseconds) for a dial to timeout.") - fs.UintVar(&cfg.ProxyWriteTimeoutMs, "proxy-write-timeout", cfg.ProxyWriteTimeoutMs, "Time (in milliseconds) for a write to timeout.") - fs.UintVar(&cfg.ProxyReadTimeoutMs, "proxy-read-timeout", cfg.ProxyReadTimeoutMs, "Time (in milliseconds) for a read to timeout.") + fs.UintVar(&cfg.cp.ProxyFailureWaitMs, "proxy-failure-wait", cfg.cp.ProxyFailureWaitMs, "Time (in milliseconds) an endpoint will be held in a failed state.") + fs.UintVar(&cfg.cp.ProxyRefreshIntervalMs, "proxy-refresh-interval", cfg.cp.ProxyRefreshIntervalMs, "Time (in milliseconds) of the endpoints refresh interval.") + fs.UintVar(&cfg.cp.ProxyDialTimeoutMs, "proxy-dial-timeout", cfg.cp.ProxyDialTimeoutMs, "Time (in milliseconds) for a dial to timeout.") + fs.UintVar(&cfg.cp.ProxyWriteTimeoutMs, "proxy-write-timeout", cfg.cp.ProxyWriteTimeoutMs, "Time (in milliseconds) for a write to timeout.") + fs.UintVar(&cfg.cp.ProxyReadTimeoutMs, "proxy-read-timeout", cfg.cp.ProxyReadTimeoutMs, "Time (in milliseconds) for a read to timeout.") // security - fs.StringVar(&cfg.ClientTLSInfo.CAFile, "ca-file", "", "DEPRECATED: Path to the client server TLS CA file.") - fs.StringVar(&cfg.ClientTLSInfo.CertFile, "cert-file", "", "Path to the client server TLS cert file.") - fs.StringVar(&cfg.ClientTLSInfo.KeyFile, "key-file", "", "Path to the client server TLS key file.") - fs.BoolVar(&cfg.ClientTLSInfo.ClientCertAuth, "client-cert-auth", false, "Enable client cert authentication.") - fs.StringVar(&cfg.ClientTLSInfo.CRLFile, "client-crl-file", "", "Path to the client certificate revocation list file.") - fs.StringVar(&cfg.ClientTLSInfo.TrustedCAFile, "trusted-ca-file", "", "Path to the client server TLS trusted CA key file.") - fs.BoolVar(&cfg.ClientAutoTLS, "auto-tls", false, "Client TLS using generated certificates") - fs.StringVar(&cfg.PeerTLSInfo.CAFile, "peer-ca-file", "", "DEPRECATED: Path to the peer server TLS CA file.") - fs.StringVar(&cfg.PeerTLSInfo.CertFile, "peer-cert-file", "", "Path to the peer server TLS cert file.") - fs.StringVar(&cfg.PeerTLSInfo.KeyFile, "peer-key-file", "", "Path to the peer server TLS key file.") - fs.BoolVar(&cfg.PeerTLSInfo.ClientCertAuth, "peer-client-cert-auth", false, "Enable peer client cert authentication.") - fs.StringVar(&cfg.PeerTLSInfo.TrustedCAFile, "peer-trusted-ca-file", "", "Path to the peer server TLS trusted CA file.") - fs.BoolVar(&cfg.PeerAutoTLS, "peer-auto-tls", false, "Peer TLS using generated certificates") - fs.StringVar(&cfg.PeerTLSInfo.CRLFile, "peer-crl-file", "", "Path to the peer certificate revocation list file.") - fs.StringVar(&cfg.PeerTLSInfo.AllowedCN, "peer-cert-allowed-cn", "", "Allowed CN for inter peer authentication.") + fs.StringVar(&cfg.ec.ClientTLSInfo.CAFile, "ca-file", "", "DEPRECATED: Path to the client server TLS CA file.") + fs.StringVar(&cfg.ec.ClientTLSInfo.CertFile, "cert-file", "", "Path to the client server TLS cert file.") + fs.StringVar(&cfg.ec.ClientTLSInfo.KeyFile, "key-file", "", "Path to the client server TLS key file.") + fs.BoolVar(&cfg.ec.ClientTLSInfo.ClientCertAuth, "client-cert-auth", false, "Enable client cert authentication.") + fs.StringVar(&cfg.ec.ClientTLSInfo.CRLFile, "client-crl-file", "", "Path to the client certificate revocation list file.") + fs.StringVar(&cfg.ec.ClientTLSInfo.TrustedCAFile, "trusted-ca-file", "", "Path to the client server TLS trusted CA key file.") + fs.BoolVar(&cfg.ec.ClientAutoTLS, "auto-tls", false, "Client TLS using generated certificates") + fs.StringVar(&cfg.ec.PeerTLSInfo.CAFile, "peer-ca-file", "", "DEPRECATED: Path to the peer server TLS CA file.") + fs.StringVar(&cfg.ec.PeerTLSInfo.CertFile, "peer-cert-file", "", "Path to the peer server TLS cert file.") + fs.StringVar(&cfg.ec.PeerTLSInfo.KeyFile, "peer-key-file", "", "Path to the peer server TLS key file.") + fs.BoolVar(&cfg.ec.PeerTLSInfo.ClientCertAuth, "peer-client-cert-auth", false, "Enable peer client cert authentication.") + fs.StringVar(&cfg.ec.PeerTLSInfo.TrustedCAFile, "peer-trusted-ca-file", "", "Path to the peer server TLS trusted CA file.") + fs.BoolVar(&cfg.ec.PeerAutoTLS, "peer-auto-tls", false, "Peer TLS using generated certificates") + fs.StringVar(&cfg.ec.PeerTLSInfo.CRLFile, "peer-crl-file", "", "Path to the peer certificate revocation list file.") + fs.StringVar(&cfg.ec.PeerTLSInfo.AllowedCN, "peer-cert-allowed-cn", "", "Allowed CN for inter peer authentication.") // logging - fs.BoolVar(&cfg.Debug, "debug", false, "Enable debug-level logging for etcd.") - fs.StringVar(&cfg.LogPkgLevels, "log-package-levels", "", "Specify a particular log level for each etcd package (eg: 'etcdmain=CRITICAL,etcdserver=DEBUG').") - fs.StringVar(&cfg.LogOutput, "log-output", embed.DefaultLogOutput, "Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd.") + fs.BoolVar(&cfg.ec.Debug, "debug", false, "Enable debug-level logging for etcd.") + fs.StringVar(&cfg.ec.LogPkgLevels, "log-package-levels", "", "Specify a particular log level for each etcd package (eg: 'etcdmain=CRITICAL,etcdserver=DEBUG').") + fs.StringVar(&cfg.ec.LogOutput, "log-output", embed.DefaultLogOutput, "Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd.") // unsafe - fs.BoolVar(&cfg.ForceNewCluster, "force-new-cluster", false, "Force to create a new one member cluster.") + fs.BoolVar(&cfg.ec.ForceNewCluster, "force-new-cluster", false, "Force to create a new one member cluster.") // version fs.BoolVar(&cfg.printVersion, "version", false, "Print the version and exit.") - fs.StringVar(&cfg.AutoCompactionRetention, "auto-compaction-retention", "0", "Auto compaction retention for mvcc key value store. 0 means disable auto compaction.") - fs.StringVar(&cfg.AutoCompactionMode, "auto-compaction-mode", "periodic", "interpret 'auto-compaction-retention' one of: periodic|revision. 'periodic' for duration based retention, defaulting to hours if no time unit is provided (e.g. '5m'). 'revision' for revision number based retention.") + fs.StringVar(&cfg.ec.AutoCompactionRetention, "auto-compaction-retention", "0", "Auto compaction retention for mvcc key value store. 0 means disable auto compaction.") + fs.StringVar(&cfg.ec.AutoCompactionMode, "auto-compaction-mode", "periodic", "interpret 'auto-compaction-retention' one of: periodic|revision. 'periodic' for duration based retention, defaulting to hours if no time unit is provided (e.g. '5m'). 'revision' for revision number based retention.") // pprof profiler via HTTP - fs.BoolVar(&cfg.EnablePprof, "enable-pprof", false, "Enable runtime profiling data via HTTP server. Address is at client URL + \"/debug/pprof/\"") + fs.BoolVar(&cfg.ec.EnablePprof, "enable-pprof", false, "Enable runtime profiling data via HTTP server. Address is at client URL + \"/debug/pprof/\"") // additional metrics - fs.StringVar(&cfg.Metrics, "metrics", cfg.Metrics, "Set level of detail for exported metrics, specify 'extensive' to include histogram metrics") + fs.StringVar(&cfg.ec.Metrics, "metrics", cfg.ec.Metrics, "Set level of detail for exported metrics, specify 'extensive' to include histogram metrics") // auth - fs.StringVar(&cfg.AuthToken, "auth-token", cfg.AuthToken, "Specify auth token specific options.") + fs.StringVar(&cfg.ec.AuthToken, "auth-token", cfg.ec.AuthToken, "Specify auth token specific options.") // experimental - fs.DurationVar(&cfg.ExperimentalCorruptCheckTime, "experimental-corrupt-check-time", cfg.ExperimentalCorruptCheckTime, "Duration of time between cluster corruption check passes.") + fs.DurationVar(&cfg.ec.ExperimentalCorruptCheckTime, "experimental-corrupt-check-time", cfg.ec.ExperimentalCorruptCheckTime, "Duration of time between cluster corruption check passes.") // ignored for _, f := range cfg.ignored { @@ -223,7 +223,7 @@ func newConfig() *config { } func (cfg *config) parse(arguments []string) error { - perr := cfg.FlagSet.Parse(arguments) + perr := cfg.cf.flagSet.Parse(arguments) switch perr { case nil: case flag.ErrHelp: @@ -232,8 +232,8 @@ func (cfg *config) parse(arguments []string) error { default: os.Exit(2) } - if len(cfg.FlagSet.Args()) != 0 { - return fmt.Errorf("'%s' is not a valid flag", cfg.FlagSet.Arg(0)) + if len(cfg.cf.flagSet.Args()) != 0 { + return fmt.Errorf("'%s' is not a valid flag", cfg.cf.flagSet.Arg(0)) } if cfg.printVersion { @@ -255,37 +255,37 @@ func (cfg *config) parse(arguments []string) error { } func (cfg *config) configFromCmdLine() error { - err := flags.SetFlagsFromEnv("ETCD", cfg.FlagSet) + err := flags.SetFlagsFromEnv("ETCD", cfg.cf.flagSet) if err != nil { plog.Fatalf("%v", err) } - cfg.LPUrls = flags.URLsFromFlag(cfg.FlagSet, "listen-peer-urls") - cfg.APUrls = flags.URLsFromFlag(cfg.FlagSet, "initial-advertise-peer-urls") - cfg.LCUrls = flags.URLsFromFlag(cfg.FlagSet, "listen-client-urls") - cfg.ACUrls = flags.URLsFromFlag(cfg.FlagSet, "advertise-client-urls") + cfg.ec.LPUrls = flags.URLsFromFlag(cfg.cf.flagSet, "listen-peer-urls") + cfg.ec.APUrls = flags.URLsFromFlag(cfg.cf.flagSet, "initial-advertise-peer-urls") + cfg.ec.LCUrls = flags.URLsFromFlag(cfg.cf.flagSet, "listen-client-urls") + cfg.ec.ACUrls = flags.URLsFromFlag(cfg.cf.flagSet, "advertise-client-urls") - if len(cfg.ListenMetricsUrlsJSON) > 0 { - u, err := types.NewURLs(strings.Split(cfg.ListenMetricsUrlsJSON, ",")) + if len(cfg.ec.ListenMetricsUrlsJSON) > 0 { + u, err := types.NewURLs(strings.Split(cfg.ec.ListenMetricsUrlsJSON, ",")) if err != nil { plog.Fatalf("unexpected error setting up listen-metrics-urls: %v", err) } - cfg.ListenMetricsUrls = []url.URL(u) + cfg.ec.ListenMetricsUrls = []url.URL(u) } - cfg.ClusterState = cfg.clusterState.String() - cfg.Fallback = cfg.fallback.String() - cfg.Proxy = cfg.proxy.String() + cfg.ec.ClusterState = cfg.cf.clusterState.String() + cfg.cp.Fallback = cfg.cf.fallback.String() + cfg.cp.Proxy = cfg.cf.proxy.String() // disable default advertise-client-urls if lcurls is set - missingAC := flags.IsSet(cfg.FlagSet, "listen-client-urls") && !flags.IsSet(cfg.FlagSet, "advertise-client-urls") + missingAC := flags.IsSet(cfg.cf.flagSet, "listen-client-urls") && !flags.IsSet(cfg.cf.flagSet, "advertise-client-urls") if !cfg.mayBeProxy() && missingAC { - cfg.ACUrls = nil + cfg.ec.ACUrls = nil } // disable default initial-cluster if discovery is set - if (cfg.Durl != "" || cfg.DNSCluster != "") && !flags.IsSet(cfg.FlagSet, "initial-cluster") { - cfg.InitialCluster = "" + if (cfg.ec.Durl != "" || cfg.ec.DNSCluster != "") && !flags.IsSet(cfg.cf.flagSet, "initial-cluster") { + cfg.ec.InitialCluster = "" } return cfg.validate() @@ -296,38 +296,38 @@ func (cfg *config) configFromFile(path string) error { if err != nil { return err } - cfg.Config = *eCfg + cfg.ec = *eCfg // load extra config information b, rerr := ioutil.ReadFile(path) if rerr != nil { return rerr } - if yerr := yaml.Unmarshal(b, &cfg.configProxy); yerr != nil { + if yerr := yaml.Unmarshal(b, &cfg.cp); yerr != nil { return yerr } - if cfg.FallbackJSON != "" { - if err := cfg.fallback.Set(cfg.FallbackJSON); err != nil { + if cfg.cp.FallbackJSON != "" { + if err := cfg.cf.fallback.Set(cfg.cp.FallbackJSON); err != nil { plog.Panicf("unexpected error setting up discovery-fallback flag: %v", err) } - cfg.Fallback = cfg.fallback.String() + cfg.cp.Fallback = cfg.cf.fallback.String() } - if cfg.ProxyJSON != "" { - if err := cfg.proxy.Set(cfg.ProxyJSON); err != nil { + if cfg.cp.ProxyJSON != "" { + if err := cfg.cf.proxy.Set(cfg.cp.ProxyJSON); err != nil { plog.Panicf("unexpected error setting up proxyFlag: %v", err) } - cfg.Proxy = cfg.proxy.String() + cfg.cp.Proxy = cfg.cf.proxy.String() } return nil } func (cfg *config) mayBeProxy() bool { - mayFallbackToProxy := cfg.Durl != "" && cfg.Fallback == fallbackFlagProxy - return cfg.Proxy != proxyFlagOff || mayFallbackToProxy + mayFallbackToProxy := cfg.ec.Durl != "" && cfg.cp.Fallback == fallbackFlagProxy + return cfg.cp.Proxy != proxyFlagOff || mayFallbackToProxy } func (cfg *config) validate() error { - err := cfg.Config.Validate() + err := cfg.ec.Validate() // TODO(yichengq): check this for joining through discovery service case if err == embed.ErrUnsetAdvertiseClientURLsFlag && cfg.mayBeProxy() { return nil @@ -335,6 +335,6 @@ func (cfg *config) validate() error { return err } -func (cfg config) isProxy() bool { return cfg.proxy.String() != proxyFlagOff } -func (cfg config) isReadonlyProxy() bool { return cfg.proxy.String() == proxyFlagReadonly } -func (cfg config) shouldFallbackToProxy() bool { return cfg.fallback.String() == fallbackFlagProxy } +func (cfg config) isProxy() bool { return cfg.cf.proxy.String() != proxyFlagOff } +func (cfg config) isReadonlyProxy() bool { return cfg.cf.proxy.String() == proxyFlagReadonly } +func (cfg config) shouldFallbackToProxy() bool { return cfg.cf.fallback.String() == fallbackFlagProxy } diff --git a/etcdmain/config_test.go b/etcdmain/config_test.go index c82afba47..31306d6fc 100644 --- a/etcdmain/config_test.go +++ b/etcdmain/config_test.go @@ -383,7 +383,7 @@ func TestConfigIsNewCluster(t *testing.T) { if err := cfg.parse(args); err != nil { t.Fatalf("#%d: unexpected clusterState.Set error: %v", i, err) } - if g := cfg.IsNewCluster(); g != tt.wIsNew { + if g := cfg.ec.IsNewCluster(); g != tt.wIsNew { t.Errorf("#%d: isNewCluster = %v, want %v", i, g, tt.wIsNew) } } @@ -400,7 +400,7 @@ func TestConfigIsProxy(t *testing.T) { } for i, tt := range tests { cfg := newConfig() - if err := cfg.proxy.Set(tt.proxy); err != nil { + if err := cfg.cf.proxy.Set(tt.proxy); err != nil { t.Fatalf("#%d: unexpected proxy.Set error: %v", i, err) } if g := cfg.isProxy(); g != tt.wIsProxy { @@ -420,7 +420,7 @@ func TestConfigIsReadonlyProxy(t *testing.T) { } for i, tt := range tests { cfg := newConfig() - if err := cfg.proxy.Set(tt.proxy); err != nil { + if err := cfg.cf.proxy.Set(tt.proxy); err != nil { t.Fatalf("#%d: unexpected proxy.Set error: %v", i, err) } if g := cfg.isReadonlyProxy(); g != tt.wIsReadonly { @@ -439,7 +439,7 @@ func TestConfigShouldFallbackToProxy(t *testing.T) { } for i, tt := range tests { cfg := newConfig() - if err := cfg.fallback.Set(tt.fallback); err != nil { + if err := cfg.cf.fallback.Set(tt.fallback); err != nil { t.Fatalf("#%d: unexpected fallback.Set error: %v", i, err) } if g := cfg.shouldFallbackToProxy(); g != tt.wFallback { @@ -512,62 +512,62 @@ func validateMemberFlags(t *testing.T, cfg *config) { SnapCount: 10, } - if cfg.Dir != wcfg.Dir { - t.Errorf("dir = %v, want %v", cfg.Dir, wcfg.Dir) + if cfg.ec.Dir != wcfg.Dir { + t.Errorf("dir = %v, want %v", cfg.ec.Dir, wcfg.Dir) } - if cfg.MaxSnapFiles != wcfg.MaxSnapFiles { - t.Errorf("maxsnap = %v, want %v", cfg.MaxSnapFiles, wcfg.MaxSnapFiles) + if cfg.ec.MaxSnapFiles != wcfg.MaxSnapFiles { + t.Errorf("maxsnap = %v, want %v", cfg.ec.MaxSnapFiles, wcfg.MaxSnapFiles) } - if cfg.MaxWalFiles != wcfg.MaxWalFiles { - t.Errorf("maxwal = %v, want %v", cfg.MaxWalFiles, wcfg.MaxWalFiles) + if cfg.ec.MaxWalFiles != wcfg.MaxWalFiles { + t.Errorf("maxwal = %v, want %v", cfg.ec.MaxWalFiles, wcfg.MaxWalFiles) } - if cfg.Name != wcfg.Name { - t.Errorf("name = %v, want %v", cfg.Name, wcfg.Name) + if cfg.ec.Name != wcfg.Name { + t.Errorf("name = %v, want %v", cfg.ec.Name, wcfg.Name) } - if cfg.SnapCount != wcfg.SnapCount { - t.Errorf("snapcount = %v, want %v", cfg.SnapCount, wcfg.SnapCount) + if cfg.ec.SnapCount != wcfg.SnapCount { + t.Errorf("snapcount = %v, want %v", cfg.ec.SnapCount, wcfg.SnapCount) } - if !reflect.DeepEqual(cfg.LPUrls, wcfg.LPUrls) { - t.Errorf("listen-peer-urls = %v, want %v", cfg.LPUrls, wcfg.LPUrls) + if !reflect.DeepEqual(cfg.ec.LPUrls, wcfg.LPUrls) { + t.Errorf("listen-peer-urls = %v, want %v", cfg.ec.LPUrls, wcfg.LPUrls) } - if !reflect.DeepEqual(cfg.LCUrls, wcfg.LCUrls) { - t.Errorf("listen-client-urls = %v, want %v", cfg.LCUrls, wcfg.LCUrls) + if !reflect.DeepEqual(cfg.ec.LCUrls, wcfg.LCUrls) { + t.Errorf("listen-client-urls = %v, want %v", cfg.ec.LCUrls, wcfg.LCUrls) } } func validateClusteringFlags(t *testing.T, cfg *config) { wcfg := newConfig() - wcfg.APUrls = []url.URL{{Scheme: "http", Host: "localhost:8000"}, {Scheme: "https", Host: "localhost:8001"}} - wcfg.ACUrls = []url.URL{{Scheme: "http", Host: "localhost:7000"}, {Scheme: "https", Host: "localhost:7001"}} - wcfg.ClusterState = embed.ClusterStateFlagExisting - wcfg.fallback.Set(fallbackFlagExit) - wcfg.InitialCluster = "0=http://localhost:8000" - wcfg.InitialClusterToken = "etcdtest" + wcfg.ec.APUrls = []url.URL{{Scheme: "http", Host: "localhost:8000"}, {Scheme: "https", Host: "localhost:8001"}} + wcfg.ec.ACUrls = []url.URL{{Scheme: "http", Host: "localhost:7000"}, {Scheme: "https", Host: "localhost:7001"}} + wcfg.ec.ClusterState = embed.ClusterStateFlagExisting + wcfg.cf.fallback.Set(fallbackFlagExit) + wcfg.ec.InitialCluster = "0=http://localhost:8000" + wcfg.ec.InitialClusterToken = "etcdtest" - if cfg.ClusterState != wcfg.ClusterState { - t.Errorf("clusterState = %v, want %v", cfg.ClusterState, wcfg.ClusterState) + if cfg.ec.ClusterState != wcfg.ec.ClusterState { + t.Errorf("clusterState = %v, want %v", cfg.ec.ClusterState, wcfg.ec.ClusterState) } - if cfg.fallback.String() != wcfg.fallback.String() { - t.Errorf("fallback = %v, want %v", cfg.fallback, wcfg.fallback) + if cfg.cf.fallback.String() != wcfg.cf.fallback.String() { + t.Errorf("fallback = %v, want %v", cfg.cf.fallback, wcfg.cf.fallback) } - if cfg.InitialCluster != wcfg.InitialCluster { - t.Errorf("initialCluster = %v, want %v", cfg.InitialCluster, wcfg.InitialCluster) + if cfg.ec.InitialCluster != wcfg.ec.InitialCluster { + t.Errorf("initialCluster = %v, want %v", cfg.ec.InitialCluster, wcfg.ec.InitialCluster) } - if cfg.InitialClusterToken != wcfg.InitialClusterToken { - t.Errorf("initialClusterToken = %v, want %v", cfg.InitialClusterToken, wcfg.InitialClusterToken) + if cfg.ec.InitialClusterToken != wcfg.ec.InitialClusterToken { + t.Errorf("initialClusterToken = %v, want %v", cfg.ec.InitialClusterToken, wcfg.ec.InitialClusterToken) } - if !reflect.DeepEqual(cfg.APUrls, wcfg.APUrls) { - t.Errorf("initial-advertise-peer-urls = %v, want %v", cfg.LPUrls, wcfg.LPUrls) + if !reflect.DeepEqual(cfg.ec.APUrls, wcfg.ec.APUrls) { + t.Errorf("initial-advertise-peer-urls = %v, want %v", cfg.ec.LPUrls, wcfg.ec.LPUrls) } - if !reflect.DeepEqual(cfg.ACUrls, wcfg.ACUrls) { - t.Errorf("advertise-client-urls = %v, want %v", cfg.LCUrls, wcfg.LCUrls) + if !reflect.DeepEqual(cfg.ec.ACUrls, wcfg.ec.ACUrls) { + t.Errorf("advertise-client-urls = %v, want %v", cfg.ec.LCUrls, wcfg.ec.LCUrls) } } func validateOtherFlags(t *testing.T, cfg *config) { wcfg := newConfig() - wcfg.proxy.Set(proxyFlagReadonly) - if cfg.proxy.String() != wcfg.proxy.String() { - t.Errorf("proxy = %v, want %v", cfg.proxy, wcfg.proxy) + wcfg.cf.proxy.Set(proxyFlagReadonly) + if cfg.cf.proxy.String() != wcfg.cf.proxy.String() { + t.Errorf("proxy = %v, want %v", cfg.cf.proxy, wcfg.cf.proxy) } } diff --git a/etcdmain/etcd.go b/etcdmain/etcd.go index 47a8e563b..428d7d330 100644 --- a/etcdmain/etcd.go +++ b/etcdmain/etcd.go @@ -58,7 +58,7 @@ func startEtcdOrProxyV2() { grpc.EnableTracing = false cfg := newConfig() - defaultInitialCluster := cfg.InitialCluster + defaultInitialCluster := cfg.ec.InitialCluster err := cfg.parse(os.Args[1:]) if err != nil { @@ -69,7 +69,7 @@ func startEtcdOrProxyV2() { } os.Exit(1) } - cfg.Config.SetupLogging() + cfg.ec.SetupLogging() var stopped <-chan struct{} var errc <-chan error @@ -82,7 +82,7 @@ func startEtcdOrProxyV2() { GoMaxProcs := runtime.GOMAXPROCS(0) plog.Infof("setting maximum number of CPUs to %d, total number of available CPUs is %d", GoMaxProcs, runtime.NumCPU()) - defaultHost, dhErr := (&cfg.Config).UpdateDefaultClusterFromName(defaultInitialCluster) + defaultHost, dhErr := (&cfg.ec).UpdateDefaultClusterFromName(defaultInitialCluster) if defaultHost != "" { plog.Infof("advertising using detected default host %q", defaultHost) } @@ -90,17 +90,17 @@ func startEtcdOrProxyV2() { plog.Noticef("failed to detect default host (%v)", dhErr) } - if cfg.Dir == "" { - cfg.Dir = fmt.Sprintf("%v.etcd", cfg.Name) - plog.Warningf("no data-dir provided, using default data-dir ./%s", cfg.Dir) + if cfg.ec.Dir == "" { + cfg.ec.Dir = fmt.Sprintf("%v.etcd", cfg.ec.Name) + plog.Warningf("no data-dir provided, using default data-dir ./%s", cfg.ec.Dir) } - which := identifyDataDirOrDie(cfg.Dir) + which := identifyDataDirOrDie(cfg.ec.Dir) if which != dirEmpty { plog.Noticef("the server is already initialized as %v before, starting as etcd %v...", which, which) switch which { case dirMember: - stopped, errc, err = startEtcd(&cfg.Config) + stopped, errc, err = startEtcd(&cfg.ec) case dirProxy: err = startProxy(cfg) default: @@ -109,7 +109,7 @@ func startEtcdOrProxyV2() { } else { shouldProxy := cfg.isProxy() if !shouldProxy { - stopped, errc, err = startEtcd(&cfg.Config) + stopped, errc, err = startEtcd(&cfg.ec) if derr, ok := err.(*etcdserver.DiscoveryError); ok && derr.Err == discovery.ErrFullCluster { if cfg.shouldFallbackToProxy() { plog.Noticef("discovery cluster full, falling back to %s", fallbackFlagProxy) @@ -126,17 +126,17 @@ func startEtcdOrProxyV2() { if derr, ok := err.(*etcdserver.DiscoveryError); ok { switch derr.Err { case discovery.ErrDuplicateID: - plog.Errorf("member %q has previously registered with discovery service token (%s).", cfg.Name, cfg.Durl) - plog.Errorf("But etcd could not find valid cluster configuration in the given data dir (%s).", cfg.Dir) + plog.Errorf("member %q has previously registered with discovery service token (%s).", cfg.ec.Name, cfg.ec.Durl) + plog.Errorf("But etcd could not find valid cluster configuration in the given data dir (%s).", cfg.ec.Dir) plog.Infof("Please check the given data dir path if the previous bootstrap succeeded") plog.Infof("or use a new discovery token if the previous bootstrap failed.") case discovery.ErrDuplicateName: - plog.Errorf("member with duplicated name has registered with discovery service token(%s).", cfg.Durl) + plog.Errorf("member with duplicated name has registered with discovery service token(%s).", cfg.ec.Durl) plog.Errorf("please check (cURL) the discovery token for more information.") plog.Errorf("please do not reuse the discovery token and generate a new one to bootstrap the cluster.") default: plog.Errorf("%v", err) - plog.Infof("discovery token %s was used, but failed to bootstrap the cluster.", cfg.Durl) + plog.Infof("discovery token %s was used, but failed to bootstrap the cluster.", cfg.ec.Durl) plog.Infof("please generate a new discovery token and try to bootstrap again.") } os.Exit(1) @@ -144,13 +144,13 @@ func startEtcdOrProxyV2() { if strings.Contains(err.Error(), "include") && strings.Contains(err.Error(), "--initial-cluster") { plog.Infof("%v", err) - if cfg.InitialCluster == cfg.InitialClusterFromName(cfg.Name) { + if cfg.ec.InitialCluster == cfg.ec.InitialClusterFromName(cfg.ec.Name) { plog.Infof("forgot to set --initial-cluster flag?") } - if types.URLs(cfg.APUrls).String() == embed.DefaultInitialAdvertisePeerURLs { + if types.URLs(cfg.ec.APUrls).String() == embed.DefaultInitialAdvertisePeerURLs { plog.Infof("forgot to set --initial-advertise-peer-urls flag?") } - if cfg.InitialCluster == cfg.InitialClusterFromName(cfg.Name) && len(cfg.Durl) == 0 { + if cfg.ec.InitialCluster == cfg.ec.InitialClusterFromName(cfg.ec.Name) && len(cfg.ec.Durl) == 0 { plog.Infof("if you want to use discovery service, please set --discovery flag.") } os.Exit(1) @@ -199,45 +199,45 @@ func startEtcd(cfg *embed.Config) (<-chan struct{}, <-chan error, error) { func startProxy(cfg *config) error { plog.Notice("proxy: this proxy supports v2 API only!") - clientTLSInfo := cfg.ClientTLSInfo + clientTLSInfo := cfg.ec.ClientTLSInfo if clientTLSInfo.Empty() { // Support old proxy behavior of defaulting to PeerTLSInfo // for both client and peer connections. - clientTLSInfo = cfg.PeerTLSInfo + clientTLSInfo = cfg.ec.PeerTLSInfo } - clientTLSInfo.InsecureSkipVerify = cfg.ClientAutoTLS - cfg.PeerTLSInfo.InsecureSkipVerify = cfg.PeerAutoTLS + clientTLSInfo.InsecureSkipVerify = cfg.ec.ClientAutoTLS + cfg.ec.PeerTLSInfo.InsecureSkipVerify = cfg.ec.PeerAutoTLS - pt, err := transport.NewTimeoutTransport(clientTLSInfo, time.Duration(cfg.ProxyDialTimeoutMs)*time.Millisecond, time.Duration(cfg.ProxyReadTimeoutMs)*time.Millisecond, time.Duration(cfg.ProxyWriteTimeoutMs)*time.Millisecond) + pt, err := transport.NewTimeoutTransport(clientTLSInfo, time.Duration(cfg.cp.ProxyDialTimeoutMs)*time.Millisecond, time.Duration(cfg.cp.ProxyReadTimeoutMs)*time.Millisecond, time.Duration(cfg.cp.ProxyWriteTimeoutMs)*time.Millisecond) if err != nil { return err } pt.MaxIdleConnsPerHost = httpproxy.DefaultMaxIdleConnsPerHost - if err = cfg.PeerSelfCert(); err != nil { + if err = cfg.ec.PeerSelfCert(); err != nil { plog.Fatalf("could not get certs (%v)", err) } - tr, err := transport.NewTimeoutTransport(cfg.PeerTLSInfo, time.Duration(cfg.ProxyDialTimeoutMs)*time.Millisecond, time.Duration(cfg.ProxyReadTimeoutMs)*time.Millisecond, time.Duration(cfg.ProxyWriteTimeoutMs)*time.Millisecond) + tr, err := transport.NewTimeoutTransport(cfg.ec.PeerTLSInfo, time.Duration(cfg.cp.ProxyDialTimeoutMs)*time.Millisecond, time.Duration(cfg.cp.ProxyReadTimeoutMs)*time.Millisecond, time.Duration(cfg.cp.ProxyWriteTimeoutMs)*time.Millisecond) if err != nil { return err } - cfg.Dir = filepath.Join(cfg.Dir, "proxy") - err = os.MkdirAll(cfg.Dir, fileutil.PrivateDirMode) + cfg.ec.Dir = filepath.Join(cfg.ec.Dir, "proxy") + err = os.MkdirAll(cfg.ec.Dir, fileutil.PrivateDirMode) if err != nil { return err } var peerURLs []string - clusterfile := filepath.Join(cfg.Dir, "cluster") + clusterfile := filepath.Join(cfg.ec.Dir, "cluster") b, err := ioutil.ReadFile(clusterfile) switch { case err == nil: - if cfg.Durl != "" { + if cfg.ec.Durl != "" { plog.Warningf("discovery token ignored since the proxy has already been initialized. Valid cluster file found at %q", clusterfile) } - if cfg.DNSCluster != "" { + if cfg.ec.DNSCluster != "" { plog.Warningf("DNS SRV discovery ignored since the proxy has already been initialized. Valid cluster file found at %q", clusterfile) } urls := struct{ PeerURLs []string }{} @@ -249,14 +249,14 @@ func startProxy(cfg *config) error { plog.Infof("proxy: using peer urls %v from cluster file %q", peerURLs, clusterfile) case os.IsNotExist(err): var urlsmap types.URLsMap - urlsmap, _, err = cfg.PeerURLsMapAndToken("proxy") + urlsmap, _, err = cfg.ec.PeerURLsMapAndToken("proxy") if err != nil { return fmt.Errorf("error setting up initial cluster: %v", err) } - if cfg.Durl != "" { + if cfg.ec.Durl != "" { var s string - s, err = discovery.GetCluster(cfg.Durl, cfg.Dproxy) + s, err = discovery.GetCluster(cfg.ec.Durl, cfg.ec.Dproxy) if err != nil { return err } @@ -305,10 +305,10 @@ func startProxy(cfg *config) error { return clientURLs } - ph := httpproxy.NewHandler(pt, uf, time.Duration(cfg.ProxyFailureWaitMs)*time.Millisecond, time.Duration(cfg.ProxyRefreshIntervalMs)*time.Millisecond) + ph := httpproxy.NewHandler(pt, uf, time.Duration(cfg.cp.ProxyFailureWaitMs)*time.Millisecond, time.Duration(cfg.cp.ProxyRefreshIntervalMs)*time.Millisecond) ph = &cors.CORSHandler{ Handler: ph, - Info: cfg.CorsInfo, + Info: cfg.ec.CorsInfo, } if cfg.isReadonlyProxy() { @@ -317,24 +317,24 @@ func startProxy(cfg *config) error { // setup self signed certs when serving https cHosts, cTLS := []string{}, false - for _, u := range cfg.LCUrls { + for _, u := range cfg.ec.LCUrls { cHosts = append(cHosts, u.Host) cTLS = cTLS || u.Scheme == "https" } - for _, u := range cfg.ACUrls { + for _, u := range cfg.ec.ACUrls { cHosts = append(cHosts, u.Host) cTLS = cTLS || u.Scheme == "https" } - listenerTLS := cfg.ClientTLSInfo - if cfg.ClientAutoTLS && cTLS { - listenerTLS, err = transport.SelfCert(filepath.Join(cfg.Dir, "clientCerts"), cHosts) + listenerTLS := cfg.ec.ClientTLSInfo + if cfg.ec.ClientAutoTLS && cTLS { + listenerTLS, err = transport.SelfCert(filepath.Join(cfg.ec.Dir, "clientCerts"), cHosts) if err != nil { plog.Fatalf("proxy: could not initialize self-signed client certs (%v)", err) } } // Start a proxy server goroutine for each listen address - for _, u := range cfg.LCUrls { + for _, u := range cfg.ec.LCUrls { l, err := transport.NewListener(u.Host, u.Scheme, &listenerTLS) if err != nil { return err