...

Source file src/go.etcd.io/etcd/server/v3/etcdmain/config.go

Documentation: go.etcd.io/etcd/server/v3/etcdmain

     1  // Copyright 2015 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Every change should be reflected on help.go as well.
    16  
    17  package etcdmain
    18  
    19  import (
    20  	"flag"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"log"
    24  	"os"
    25  	"runtime"
    26  
    27  	"go.etcd.io/etcd/api/v3/version"
    28  	"go.etcd.io/etcd/client/pkg/v3/logutil"
    29  	"go.etcd.io/etcd/client/pkg/v3/tlsutil"
    30  	"go.etcd.io/etcd/pkg/v3/flags"
    31  	cconfig "go.etcd.io/etcd/server/v3/config"
    32  	"go.etcd.io/etcd/server/v3/embed"
    33  	"go.etcd.io/etcd/server/v3/etcdserver/api/rafthttp"
    34  
    35  	"go.uber.org/zap"
    36  	"sigs.k8s.io/yaml"
    37  )
    38  
    39  var (
    40  	proxyFlagOff      = "off"
    41  	proxyFlagReadonly = "readonly"
    42  	proxyFlagOn       = "on"
    43  
    44  	fallbackFlagExit  = "exit"
    45  	fallbackFlagProxy = "proxy"
    46  
    47  	ignored = []string{
    48  		"cluster-active-size",
    49  		"cluster-remove-delay",
    50  		"cluster-sync-interval",
    51  		"config",
    52  		"force",
    53  		"max-result-buffer",
    54  		"max-retry-attempts",
    55  		"peer-heartbeat-interval",
    56  		"peer-election-timeout",
    57  		"retry-interval",
    58  		"snapshot",
    59  		"v",
    60  		"vv",
    61  		// for coverage testing
    62  		"test.coverprofile",
    63  		"test.outputdir",
    64  	}
    65  )
    66  
    67  type configProxy struct {
    68  	ProxyFailureWaitMs     uint `json:"proxy-failure-wait"`
    69  	ProxyRefreshIntervalMs uint `json:"proxy-refresh-interval"`
    70  	ProxyDialTimeoutMs     uint `json:"proxy-dial-timeout"`
    71  	ProxyWriteTimeoutMs    uint `json:"proxy-write-timeout"`
    72  	ProxyReadTimeoutMs     uint `json:"proxy-read-timeout"`
    73  	Fallback               string
    74  	Proxy                  string
    75  	ProxyJSON              string `json:"proxy"`
    76  	FallbackJSON           string `json:"discovery-fallback"`
    77  }
    78  
    79  // config holds the config for a command line invocation of etcd
    80  type config struct {
    81  	ec           embed.Config
    82  	cp           configProxy
    83  	cf           configFlags
    84  	configFile   string
    85  	printVersion bool
    86  	ignored      []string
    87  }
    88  
    89  // configFlags has the set of flags used for command line parsing a Config
    90  type configFlags struct {
    91  	flagSet       *flag.FlagSet
    92  	clusterState  *flags.SelectiveStringValue
    93  	fallback      *flags.SelectiveStringValue
    94  	proxy         *flags.SelectiveStringValue
    95  	v2deprecation *flags.SelectiveStringsValue
    96  }
    97  
    98  func newConfig() *config {
    99  	cfg := &config{
   100  		ec: *embed.NewConfig(),
   101  		cp: configProxy{
   102  			Proxy:                  proxyFlagOff,
   103  			ProxyFailureWaitMs:     5000,
   104  			ProxyRefreshIntervalMs: 30000,
   105  			ProxyDialTimeoutMs:     1000,
   106  			ProxyWriteTimeoutMs:    5000,
   107  		},
   108  		ignored: ignored,
   109  	}
   110  	cfg.cf = configFlags{
   111  		flagSet: flag.NewFlagSet("etcd", flag.ContinueOnError),
   112  		clusterState: flags.NewSelectiveStringValue(
   113  			embed.ClusterStateFlagNew,
   114  			embed.ClusterStateFlagExisting,
   115  		),
   116  		fallback: flags.NewSelectiveStringValue(
   117  			fallbackFlagProxy,
   118  			fallbackFlagExit,
   119  		),
   120  		proxy: flags.NewSelectiveStringValue(
   121  			proxyFlagOff,
   122  			proxyFlagReadonly,
   123  			proxyFlagOn,
   124  		),
   125  		v2deprecation: flags.NewSelectiveStringsValue(
   126  			string(cconfig.V2_DEPR_0_NOT_YET),
   127  			string(cconfig.V2_DEPR_1_WRITE_ONLY),
   128  			string(cconfig.V2_DEPR_1_WRITE_ONLY_DROP),
   129  			string(cconfig.V2_DEPR_2_GONE)),
   130  	}
   131  
   132  	fs := cfg.cf.flagSet
   133  	fs.Usage = func() {
   134  		fmt.Fprintln(os.Stderr, usageline)
   135  	}
   136  
   137  	fs.StringVar(&cfg.configFile, "config-file", "", "Path to the server configuration file. Note that if a configuration file is provided, other command line flags and environment variables will be ignored.")
   138  
   139  	// member
   140  	fs.StringVar(&cfg.ec.Dir, "data-dir", cfg.ec.Dir, "Path to the data directory.")
   141  	fs.StringVar(&cfg.ec.WalDir, "wal-dir", cfg.ec.WalDir, "Path to the dedicated wal directory.")
   142  	fs.Var(
   143  		flags.NewUniqueURLsWithExceptions(embed.DefaultListenPeerURLs, ""),
   144  		"listen-peer-urls",
   145  		"List of URLs to listen on for peer traffic.",
   146  	)
   147  	fs.Var(
   148  		flags.NewUniqueURLsWithExceptions(embed.DefaultListenClientURLs, ""), "listen-client-urls",
   149  		"List of URLs to listen on for client grpc traffic and http as long as --listen-client-http-urls is not specified.",
   150  	)
   151  	fs.Var(
   152  		flags.NewUniqueURLsWithExceptions("", ""), "listen-client-http-urls",
   153  		"List of URLs to listen on for http only client traffic. Enabling this flag removes http services from --listen-client-urls.",
   154  	)
   155  	fs.Var(
   156  		flags.NewUniqueURLsWithExceptions("", ""),
   157  		"listen-metrics-urls",
   158  		"List of URLs to listen on for the metrics and health endpoints.",
   159  	)
   160  	fs.UintVar(&cfg.ec.MaxSnapFiles, "max-snapshots", cfg.ec.MaxSnapFiles, "Maximum number of snapshot files to retain (0 is unlimited).")
   161  	fs.UintVar(&cfg.ec.MaxWalFiles, "max-wals", cfg.ec.MaxWalFiles, "Maximum number of wal files to retain (0 is unlimited).")
   162  	fs.StringVar(&cfg.ec.Name, "name", cfg.ec.Name, "Human-readable name for this member.")
   163  	fs.Uint64Var(&cfg.ec.SnapshotCount, "snapshot-count", cfg.ec.SnapshotCount, "Number of committed transactions to trigger a snapshot to disk.")
   164  	fs.UintVar(&cfg.ec.TickMs, "heartbeat-interval", cfg.ec.TickMs, "Time (in milliseconds) of a heartbeat interval.")
   165  	fs.UintVar(&cfg.ec.ElectionMs, "election-timeout", cfg.ec.ElectionMs, "Time (in milliseconds) for an election to timeout.")
   166  	fs.BoolVar(&cfg.ec.InitialElectionTickAdvance, "initial-election-tick-advance", cfg.ec.InitialElectionTickAdvance, "Whether to fast-forward initial election ticks on boot for faster election.")
   167  	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.")
   168  	fs.StringVar(&cfg.ec.BackendFreelistType, "backend-bbolt-freelist-type", cfg.ec.BackendFreelistType, "BackendFreelistType specifies the type of freelist that boltdb backend uses(array and map are supported types)")
   169  	fs.DurationVar(&cfg.ec.BackendBatchInterval, "backend-batch-interval", cfg.ec.BackendBatchInterval, "BackendBatchInterval is the maximum time before commit the backend transaction.")
   170  	fs.IntVar(&cfg.ec.BackendBatchLimit, "backend-batch-limit", cfg.ec.BackendBatchLimit, "BackendBatchLimit is the maximum operations before commit the backend transaction.")
   171  	fs.UintVar(&cfg.ec.MaxTxnOps, "max-txn-ops", cfg.ec.MaxTxnOps, "Maximum number of operations permitted in a transaction.")
   172  	fs.UintVar(&cfg.ec.MaxRequestBytes, "max-request-bytes", cfg.ec.MaxRequestBytes, "Maximum client request size in bytes the server will accept.")
   173  	fs.DurationVar(&cfg.ec.GRPCKeepAliveMinTime, "grpc-keepalive-min-time", cfg.ec.GRPCKeepAliveMinTime, "Minimum interval duration that a client should wait before pinging server.")
   174  	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).")
   175  	fs.DurationVar(&cfg.ec.GRPCKeepAliveTimeout, "grpc-keepalive-timeout", cfg.ec.GRPCKeepAliveTimeout, "Additional duration of wait before closing a non-responsive connection (0 to disable).")
   176  	fs.BoolVar(&cfg.ec.SocketOpts.ReusePort, "socket-reuse-port", cfg.ec.SocketOpts.ReusePort, "Enable to set socket option SO_REUSEPORT on listeners allowing rebinding of a port already in use.")
   177  	fs.BoolVar(&cfg.ec.SocketOpts.ReuseAddress, "socket-reuse-address", cfg.ec.SocketOpts.ReuseAddress, "Enable to set socket option SO_REUSEADDR on listeners allowing binding to an address in `TIME_WAIT` state.")
   178  
   179  	fs.Var(flags.NewUint32Value(cfg.ec.MaxConcurrentStreams), "max-concurrent-streams", "Maximum concurrent streams that each client can open at a time.")
   180  
   181  	// raft connection timeouts
   182  	fs.DurationVar(&rafthttp.ConnReadTimeout, "raft-read-timeout", rafthttp.DefaultConnReadTimeout, "Read timeout set on each rafthttp connection")
   183  	fs.DurationVar(&rafthttp.ConnWriteTimeout, "raft-write-timeout", rafthttp.DefaultConnWriteTimeout, "Write timeout set on each rafthttp connection")
   184  
   185  	// clustering
   186  	fs.Var(
   187  		flags.NewUniqueURLsWithExceptions(embed.DefaultInitialAdvertisePeerURLs, ""),
   188  		"initial-advertise-peer-urls",
   189  		"List of this member's peer URLs to advertise to the rest of the cluster.",
   190  	)
   191  	fs.Var(
   192  		flags.NewUniqueURLsWithExceptions(embed.DefaultAdvertiseClientURLs, ""),
   193  		"advertise-client-urls",
   194  		"List of this member's client URLs to advertise to the public.",
   195  	)
   196  	fs.StringVar(&cfg.ec.Durl, "discovery", cfg.ec.Durl, "Discovery URL used to bootstrap the cluster.")
   197  	fs.Var(cfg.cf.fallback, "discovery-fallback", fmt.Sprintf("Valid values include %q", cfg.cf.fallback.Valids()))
   198  
   199  	fs.StringVar(&cfg.ec.Dproxy, "discovery-proxy", cfg.ec.Dproxy, "HTTP proxy to use for traffic to discovery service.")
   200  	fs.StringVar(&cfg.ec.DNSCluster, "discovery-srv", cfg.ec.DNSCluster, "DNS domain used to bootstrap initial cluster.")
   201  	fs.StringVar(&cfg.ec.DNSClusterServiceName, "discovery-srv-name", cfg.ec.DNSClusterServiceName, "Service name to query when using DNS discovery.")
   202  	fs.StringVar(&cfg.ec.InitialCluster, "initial-cluster", cfg.ec.InitialCluster, "Initial cluster configuration for bootstrapping.")
   203  	fs.StringVar(&cfg.ec.InitialClusterToken, "initial-cluster-token", cfg.ec.InitialClusterToken, "Initial cluster token for the etcd cluster during bootstrap.")
   204  	fs.Var(cfg.cf.clusterState, "initial-cluster-state", "Initial cluster state ('new' when bootstrapping a new cluster or 'existing' when adding new members to an existing cluster). After successful initialization (bootstrapping or adding), flag is ignored on restarts.")
   205  
   206  	fs.BoolVar(&cfg.ec.StrictReconfigCheck, "strict-reconfig-check", cfg.ec.StrictReconfigCheck, "Reject reconfiguration requests that would cause quorum loss.")
   207  
   208  	fs.BoolVar(&cfg.ec.PreVote, "pre-vote", cfg.ec.PreVote, "Enable to run an additional Raft election phase.")
   209  
   210  	fs.BoolVar(&cfg.ec.EnableV2, "enable-v2", cfg.ec.EnableV2, "Accept etcd V2 client requests. Deprecated in v3.5. Will be decommission in v3.6.")
   211  	fs.StringVar(&cfg.ec.ExperimentalEnableV2V3, "experimental-enable-v2v3", cfg.ec.ExperimentalEnableV2V3, "v3 prefix for serving emulated v2 state. Deprecated in 3.5. Will be decomissioned in 3.6.")
   212  	fs.Var(cfg.cf.v2deprecation, "v2-deprecation", fmt.Sprintf("v2store deprecation stage: %q. ", cfg.cf.proxy.Valids()))
   213  
   214  	// proxy
   215  	fs.Var(cfg.cf.proxy, "proxy", fmt.Sprintf("Valid values include %q", cfg.cf.proxy.Valids()))
   216  	fs.UintVar(&cfg.cp.ProxyFailureWaitMs, "proxy-failure-wait", cfg.cp.ProxyFailureWaitMs, "Time (in milliseconds) an endpoint will be held in a failed state.")
   217  	fs.UintVar(&cfg.cp.ProxyRefreshIntervalMs, "proxy-refresh-interval", cfg.cp.ProxyRefreshIntervalMs, "Time (in milliseconds) of the endpoints refresh interval.")
   218  	fs.UintVar(&cfg.cp.ProxyDialTimeoutMs, "proxy-dial-timeout", cfg.cp.ProxyDialTimeoutMs, "Time (in milliseconds) for a dial to timeout.")
   219  	fs.UintVar(&cfg.cp.ProxyWriteTimeoutMs, "proxy-write-timeout", cfg.cp.ProxyWriteTimeoutMs, "Time (in milliseconds) for a write to timeout.")
   220  	fs.UintVar(&cfg.cp.ProxyReadTimeoutMs, "proxy-read-timeout", cfg.cp.ProxyReadTimeoutMs, "Time (in milliseconds) for a read to timeout.")
   221  
   222  	// security
   223  	fs.StringVar(&cfg.ec.ClientTLSInfo.CertFile, "cert-file", "", "Path to the client server TLS cert file.")
   224  	fs.StringVar(&cfg.ec.ClientTLSInfo.KeyFile, "key-file", "", "Path to the client server TLS key file.")
   225  	fs.StringVar(&cfg.ec.ClientTLSInfo.ClientCertFile, "client-cert-file", "", "Path to an explicit peer client TLS cert file otherwise cert file will be used when client auth is required.")
   226  	fs.StringVar(&cfg.ec.ClientTLSInfo.ClientKeyFile, "client-key-file", "", "Path to an explicit peer client TLS key file otherwise key file will be used when client auth is required.")
   227  	fs.BoolVar(&cfg.ec.ClientTLSInfo.ClientCertAuth, "client-cert-auth", false, "Enable client cert authentication.")
   228  	fs.StringVar(&cfg.ec.ClientTLSInfo.CRLFile, "client-crl-file", "", "Path to the client certificate revocation list file.")
   229  	fs.StringVar(&cfg.ec.ClientTLSInfo.AllowedHostname, "client-cert-allowed-hostname", "", "Allowed TLS hostname for client cert authentication.")
   230  	fs.StringVar(&cfg.ec.ClientTLSInfo.TrustedCAFile, "trusted-ca-file", "", "Path to the client server TLS trusted CA cert file.")
   231  	fs.BoolVar(&cfg.ec.ClientAutoTLS, "auto-tls", false, "Client TLS using generated certificates")
   232  	fs.StringVar(&cfg.ec.PeerTLSInfo.CertFile, "peer-cert-file", "", "Path to the peer server TLS cert file.")
   233  	fs.StringVar(&cfg.ec.PeerTLSInfo.KeyFile, "peer-key-file", "", "Path to the peer server TLS key file.")
   234  	fs.StringVar(&cfg.ec.PeerTLSInfo.ClientCertFile, "peer-client-cert-file", "", "Path to an explicit peer client TLS cert file otherwise peer cert file will be used when client auth is required.")
   235  	fs.StringVar(&cfg.ec.PeerTLSInfo.ClientKeyFile, "peer-client-key-file", "", "Path to an explicit peer client TLS key file otherwise peer key file will be used when client auth is required.")
   236  	fs.BoolVar(&cfg.ec.PeerTLSInfo.ClientCertAuth, "peer-client-cert-auth", false, "Enable peer client cert authentication.")
   237  	fs.StringVar(&cfg.ec.PeerTLSInfo.TrustedCAFile, "peer-trusted-ca-file", "", "Path to the peer server TLS trusted CA file.")
   238  	fs.BoolVar(&cfg.ec.PeerAutoTLS, "peer-auto-tls", false, "Peer TLS using generated certificates")
   239  	fs.UintVar(&cfg.ec.SelfSignedCertValidity, "self-signed-cert-validity", 1, "The validity period of the client and peer certificates, unit is year")
   240  	fs.StringVar(&cfg.ec.PeerTLSInfo.CRLFile, "peer-crl-file", "", "Path to the peer certificate revocation list file.")
   241  	fs.StringVar(&cfg.ec.PeerTLSInfo.AllowedCN, "peer-cert-allowed-cn", "", "Allowed CN for inter peer authentication.")
   242  	fs.StringVar(&cfg.ec.PeerTLSInfo.AllowedHostname, "peer-cert-allowed-hostname", "", "Allowed TLS hostname for inter peer authentication.")
   243  	fs.Var(flags.NewStringsValue(""), "cipher-suites", "Comma-separated list of supported TLS cipher suites between client/server and peers (empty will be auto-populated by Go).")
   244  	fs.BoolVar(&cfg.ec.PeerTLSInfo.SkipClientSANVerify, "experimental-peer-skip-client-san-verification", false, "Skip verification of SAN field in client certificate for peer connections.")
   245  	fs.StringVar(&cfg.ec.TlsMinVersion, "tls-min-version", string(tlsutil.TLSVersion12), "Minimum TLS version supported by etcd. Possible values: TLS1.2, TLS1.3.")
   246  	fs.StringVar(&cfg.ec.TlsMaxVersion, "tls-max-version", string(tlsutil.TLSVersionDefault), "Maximum TLS version supported by etcd. Possible values: TLS1.2, TLS1.3 (empty defers to Go).")
   247  
   248  	fs.Var(
   249  		flags.NewUniqueURLsWithExceptions("*", "*"),
   250  		"cors",
   251  		"Comma-separated white list of origins for CORS, or cross-origin resource sharing, (empty or * means allow all)",
   252  	)
   253  	fs.Var(flags.NewUniqueStringsValue("*"), "host-whitelist", "Comma-separated acceptable hostnames from HTTP client requests, if server is not secure (empty means allow all).")
   254  
   255  	// logging
   256  	fs.StringVar(&cfg.ec.Logger, "logger", "zap", "Currently only supports 'zap' for structured logging.")
   257  	fs.Var(flags.NewUniqueStringsValue(embed.DefaultLogOutput), "log-outputs", "Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd, or list of comma separated output targets.")
   258  	fs.StringVar(&cfg.ec.LogLevel, "log-level", logutil.DefaultLogLevel, "Configures log level. Only supports debug, info, warn, error, panic, or fatal. Default 'info'.")
   259  	fs.BoolVar(&cfg.ec.EnableLogRotation, "enable-log-rotation", false, "Enable log rotation of a single log-outputs file target.")
   260  	fs.StringVar(&cfg.ec.LogRotationConfigJSON, "log-rotation-config-json", embed.DefaultLogRotationConfig, "Configures log rotation if enabled with a JSON logger config. Default: MaxSize=100(MB), MaxAge=0(days,no limit), MaxBackups=0(no limit), LocalTime=false(UTC), Compress=false(gzip)")
   261  
   262  	// version
   263  	fs.BoolVar(&cfg.printVersion, "version", false, "Print the version and exit.")
   264  
   265  	fs.StringVar(&cfg.ec.AutoCompactionRetention, "auto-compaction-retention", "0", "Auto compaction retention for mvcc key value store. 0 means disable auto compaction.")
   266  	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.")
   267  
   268  	// pprof profiler via HTTP
   269  	fs.BoolVar(&cfg.ec.EnablePprof, "enable-pprof", false, "Enable runtime profiling data via HTTP server. Address is at client URL + \"/debug/pprof/\"")
   270  
   271  	// additional metrics
   272  	fs.StringVar(&cfg.ec.Metrics, "metrics", cfg.ec.Metrics, "Set level of detail for exported metrics, specify 'extensive' to include server side grpc histogram metrics")
   273  
   274  	// experimental distributed tracing
   275  	fs.BoolVar(&cfg.ec.ExperimentalEnableDistributedTracing, "experimental-enable-distributed-tracing", false, "Enable experimental distributed  tracing using OpenTelemetry Tracing.")
   276  	fs.StringVar(&cfg.ec.ExperimentalDistributedTracingAddress, "experimental-distributed-tracing-address", embed.ExperimentalDistributedTracingAddress, "Address for distributed tracing used for OpenTelemetry Tracing (if enabled with experimental-enable-distributed-tracing flag).")
   277  	fs.StringVar(&cfg.ec.ExperimentalDistributedTracingServiceName, "experimental-distributed-tracing-service-name", embed.ExperimentalDistributedTracingServiceName, "Configures service name for distributed tracing to be used to define service name for OpenTelemetry Tracing (if enabled with experimental-enable-distributed-tracing flag). 'etcd' is the default service name. Use the same service name for all instances of etcd.")
   278  	fs.StringVar(&cfg.ec.ExperimentalDistributedTracingServiceInstanceID, "experimental-distributed-tracing-instance-id", "", "Configures service instance ID for distributed tracing to be used to define service instance ID key for OpenTelemetry Tracing (if enabled with experimental-enable-distributed-tracing flag). There is no default value set. This ID must be unique per etcd instance.")
   279  	fs.IntVar(&cfg.ec.ExperimentalDistributedTracingSamplingRatePerMillion, "experimental-distributed-tracing-sampling-rate", 0, "Number of samples to collect per million spans for OpenTelemetry Tracing (if enabled with experimental-enable-distributed-tracing flag).")
   280  
   281  	// auth
   282  	fs.StringVar(&cfg.ec.AuthToken, "auth-token", cfg.ec.AuthToken, "Specify auth token specific options.")
   283  	fs.UintVar(&cfg.ec.BcryptCost, "bcrypt-cost", cfg.ec.BcryptCost, "Specify bcrypt algorithm cost factor for auth password hashing.")
   284  	fs.UintVar(&cfg.ec.AuthTokenTTL, "auth-token-ttl", cfg.ec.AuthTokenTTL, "The lifetime in seconds of the auth token.")
   285  
   286  	// gateway
   287  	fs.BoolVar(&cfg.ec.EnableGRPCGateway, "enable-grpc-gateway", cfg.ec.EnableGRPCGateway, "Enable GRPC gateway.")
   288  
   289  	// experimental
   290  	fs.BoolVar(&cfg.ec.ExperimentalInitialCorruptCheck, "experimental-initial-corrupt-check", cfg.ec.ExperimentalInitialCorruptCheck, "Enable to check data corruption before serving any client/peer traffic.")
   291  	fs.DurationVar(&cfg.ec.ExperimentalCorruptCheckTime, "experimental-corrupt-check-time", cfg.ec.ExperimentalCorruptCheckTime, "Duration of time between cluster corruption check passes.")
   292  	fs.BoolVar(&cfg.ec.ExperimentalCompactHashCheckEnabled, "experimental-compact-hash-check-enabled", cfg.ec.ExperimentalCompactHashCheckEnabled, "Enable leader to periodically check followers compaction hashes.")
   293  	fs.DurationVar(&cfg.ec.ExperimentalCompactHashCheckTime, "experimental-compact-hash-check-time", cfg.ec.ExperimentalCompactHashCheckTime, "Duration of time between leader checks followers compaction hashes.")
   294  
   295  	fs.BoolVar(&cfg.ec.ExperimentalEnableLeaseCheckpoint, "experimental-enable-lease-checkpoint", false, "Enable leader to send regular checkpoints to other members to prevent reset of remaining TTL on leader change.")
   296  	// TODO: delete in v3.7
   297  	fs.BoolVar(&cfg.ec.ExperimentalEnableLeaseCheckpointPersist, "experimental-enable-lease-checkpoint-persist", false, "Enable persisting remainingTTL to prevent indefinite auto-renewal of long lived leases. Always enabled in v3.6. Should be used to ensure smooth upgrade from v3.5 clusters with this feature enabled. Requires experimental-enable-lease-checkpoint to be enabled.")
   298  	fs.IntVar(&cfg.ec.ExperimentalCompactionBatchLimit, "experimental-compaction-batch-limit", cfg.ec.ExperimentalCompactionBatchLimit, "Sets the maximum revisions deleted in each compaction batch.")
   299  	fs.DurationVar(&cfg.ec.ExperimentalWatchProgressNotifyInterval, "experimental-watch-progress-notify-interval", cfg.ec.ExperimentalWatchProgressNotifyInterval, "Duration of periodic watch progress notifications.")
   300  	fs.DurationVar(&cfg.ec.ExperimentalDowngradeCheckTime, "experimental-downgrade-check-time", cfg.ec.ExperimentalDowngradeCheckTime, "Duration of time between two downgrade status check.")
   301  	fs.DurationVar(&cfg.ec.ExperimentalWarningApplyDuration, "experimental-warning-apply-duration", cfg.ec.ExperimentalWarningApplyDuration, "Time duration after which a warning is generated if request takes more time.")
   302  	fs.BoolVar(&cfg.ec.ExperimentalMemoryMlock, "experimental-memory-mlock", cfg.ec.ExperimentalMemoryMlock, "Enable to enforce etcd pages (in particular bbolt) to stay in RAM.")
   303  	fs.BoolVar(&cfg.ec.ExperimentalTxnModeWriteWithSharedBuffer, "experimental-txn-mode-write-with-shared-buffer", true, "Enable the write transaction to use a shared buffer in its readonly check operations.")
   304  	fs.UintVar(&cfg.ec.ExperimentalBootstrapDefragThresholdMegabytes, "experimental-bootstrap-defrag-threshold-megabytes", 0, "Enable the defrag during etcd server bootstrap on condition that it will free at least the provided threshold of disk space. Needs to be set to non-zero value to take effect.")
   305  
   306  	// unsafe
   307  	fs.BoolVar(&cfg.ec.UnsafeNoFsync, "unsafe-no-fsync", false, "Disables fsync, unsafe, will cause data loss.")
   308  	fs.BoolVar(&cfg.ec.ForceNewCluster, "force-new-cluster", false, "Force to create a new one member cluster.")
   309  
   310  	// ignored
   311  	for _, f := range cfg.ignored {
   312  		fs.Var(&flags.IgnoredFlag{Name: f}, f, "")
   313  	}
   314  	return cfg
   315  }
   316  
   317  func (cfg *config) parse(arguments []string) error {
   318  	perr := cfg.cf.flagSet.Parse(arguments)
   319  	switch perr {
   320  	case nil:
   321  	case flag.ErrHelp:
   322  		fmt.Println(flagsline)
   323  		os.Exit(0)
   324  	default:
   325  		os.Exit(2)
   326  	}
   327  	if len(cfg.cf.flagSet.Args()) != 0 {
   328  		return fmt.Errorf("'%s' is not a valid flag", cfg.cf.flagSet.Arg(0))
   329  	}
   330  
   331  	if cfg.printVersion {
   332  		fmt.Printf("etcd Version: %s\n", version.Version)
   333  		fmt.Printf("Git SHA: %s\n", version.GitSHA)
   334  		fmt.Printf("Go Version: %s\n", runtime.Version())
   335  		fmt.Printf("Go OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
   336  		os.Exit(0)
   337  	}
   338  
   339  	var err error
   340  
   341  	// This env variable must be parsed separately
   342  	// because we need to determine whether to use or
   343  	// ignore the env variables based on if the config file is set.
   344  	if cfg.configFile == "" {
   345  		cfg.configFile = os.Getenv(flags.FlagToEnv("ETCD", "config-file"))
   346  	}
   347  
   348  	if cfg.configFile != "" {
   349  		err = cfg.configFromFile(cfg.configFile)
   350  		if lg := cfg.ec.GetLogger(); lg != nil {
   351  			lg.Info(
   352  				"loaded server configuration, other configuration command line flags and environment variables will be ignored if provided",
   353  				zap.String("path", cfg.configFile),
   354  			)
   355  		}
   356  	} else {
   357  		err = cfg.configFromCmdLine()
   358  	}
   359  
   360  	if cfg.ec.V2Deprecation == "" {
   361  		cfg.ec.V2Deprecation = cconfig.V2_DEPR_DEFAULT
   362  	}
   363  
   364  	// now logger is set up
   365  	return err
   366  }
   367  
   368  func (cfg *config) configFromCmdLine() error {
   369  	// user-specified logger is not setup yet, use this logger during flag parsing
   370  	lg, err := logutil.CreateDefaultZapLogger(zap.InfoLevel)
   371  	if err != nil {
   372  		return err
   373  	}
   374  	verKey := "ETCD_VERSION"
   375  	if verVal := os.Getenv(verKey); verVal != "" {
   376  		// unset to avoid any possible side-effect.
   377  		os.Unsetenv(verKey)
   378  
   379  		lg.Warn(
   380  			"cannot set special environment variable",
   381  			zap.String("key", verKey),
   382  			zap.String("value", verVal),
   383  		)
   384  	}
   385  
   386  	err = flags.SetFlagsFromEnv(lg, "ETCD", cfg.cf.flagSet)
   387  	if err != nil {
   388  		return err
   389  	}
   390  
   391  	if rafthttp.ConnReadTimeout < rafthttp.DefaultConnReadTimeout {
   392  		rafthttp.ConnReadTimeout = rafthttp.DefaultConnReadTimeout
   393  		lg.Info(fmt.Sprintf("raft-read-timeout increased to minimum value: %v", rafthttp.DefaultConnReadTimeout))
   394  	}
   395  	if rafthttp.ConnWriteTimeout < rafthttp.DefaultConnWriteTimeout {
   396  		rafthttp.ConnWriteTimeout = rafthttp.DefaultConnWriteTimeout
   397  		lg.Info(fmt.Sprintf("raft-write-timeout increased to minimum value: %v", rafthttp.DefaultConnWriteTimeout))
   398  	}
   399  
   400  	cfg.ec.ListenPeerUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "listen-peer-urls")
   401  	cfg.ec.AdvertisePeerUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "initial-advertise-peer-urls")
   402  	cfg.ec.ListenClientUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "listen-client-urls")
   403  	cfg.ec.ListenClientHttpUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "listen-client-http-urls")
   404  	cfg.ec.AdvertiseClientUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "advertise-client-urls")
   405  	cfg.ec.ListenMetricsUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "listen-metrics-urls")
   406  
   407  	cfg.ec.CORS = flags.UniqueURLsMapFromFlag(cfg.cf.flagSet, "cors")
   408  	cfg.ec.HostWhitelist = flags.UniqueStringsMapFromFlag(cfg.cf.flagSet, "host-whitelist")
   409  
   410  	cfg.ec.CipherSuites = flags.StringsFromFlag(cfg.cf.flagSet, "cipher-suites")
   411  
   412  	cfg.ec.MaxConcurrentStreams = flags.Uint32FromFlag(cfg.cf.flagSet, "max-concurrent-streams")
   413  
   414  	cfg.ec.LogOutputs = flags.UniqueStringsFromFlag(cfg.cf.flagSet, "log-outputs")
   415  
   416  	cfg.ec.ClusterState = cfg.cf.clusterState.String()
   417  	cfg.cp.Fallback = cfg.cf.fallback.String()
   418  	cfg.cp.Proxy = cfg.cf.proxy.String()
   419  
   420  	cfg.ec.V2Deprecation = cconfig.V2DeprecationEnum(cfg.cf.v2deprecation.String())
   421  
   422  	// disable default advertise-client-urls if lcurls is set
   423  	missingAC := flags.IsSet(cfg.cf.flagSet, "listen-client-urls") && !flags.IsSet(cfg.cf.flagSet, "advertise-client-urls")
   424  	if !cfg.mayBeProxy() && missingAC {
   425  		cfg.ec.AdvertiseClientUrls = nil
   426  	}
   427  
   428  	// disable default initial-cluster if discovery is set
   429  	if (cfg.ec.Durl != "" || cfg.ec.DNSCluster != "" || cfg.ec.DNSClusterServiceName != "") && !flags.IsSet(cfg.cf.flagSet, "initial-cluster") {
   430  		cfg.ec.InitialCluster = ""
   431  	}
   432  
   433  	return cfg.validate()
   434  }
   435  
   436  func (cfg *config) configFromFile(path string) error {
   437  	eCfg, err := embed.ConfigFromFile(path)
   438  	if err != nil {
   439  		return err
   440  	}
   441  	cfg.ec = *eCfg
   442  
   443  	// load extra config information
   444  	b, rerr := ioutil.ReadFile(path)
   445  	if rerr != nil {
   446  		return rerr
   447  	}
   448  	if yerr := yaml.Unmarshal(b, &cfg.cp); yerr != nil {
   449  		return yerr
   450  	}
   451  
   452  	if cfg.cp.FallbackJSON != "" {
   453  		if err := cfg.cf.fallback.Set(cfg.cp.FallbackJSON); err != nil {
   454  			log.Fatalf("unexpected error setting up discovery-fallback flag: %v", err)
   455  		}
   456  		cfg.cp.Fallback = cfg.cf.fallback.String()
   457  	}
   458  
   459  	if cfg.cp.ProxyJSON != "" {
   460  		if err := cfg.cf.proxy.Set(cfg.cp.ProxyJSON); err != nil {
   461  			log.Fatalf("unexpected error setting up proxyFlag: %v", err)
   462  		}
   463  		cfg.cp.Proxy = cfg.cf.proxy.String()
   464  	}
   465  	return nil
   466  }
   467  
   468  func (cfg *config) mayBeProxy() bool {
   469  	mayFallbackToProxy := cfg.ec.Durl != "" && cfg.cp.Fallback == fallbackFlagProxy
   470  	return cfg.cp.Proxy != proxyFlagOff || mayFallbackToProxy
   471  }
   472  
   473  func (cfg *config) validate() error {
   474  	err := cfg.ec.Validate()
   475  	// TODO(yichengq): check this for joining through discovery service case
   476  	if err == embed.ErrUnsetAdvertiseClientURLsFlag && cfg.mayBeProxy() {
   477  		return nil
   478  	}
   479  	return err
   480  }
   481  
   482  func (cfg config) isProxy() bool               { return cfg.cf.proxy.String() != proxyFlagOff }
   483  func (cfg config) isReadonlyProxy() bool       { return cfg.cf.proxy.String() == proxyFlagReadonly }
   484  func (cfg config) shouldFallbackToProxy() bool { return cfg.cf.fallback.String() == fallbackFlagProxy }
   485  

View as plain text