1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
287 fs.BoolVar(&cfg.ec.EnableGRPCGateway, "enable-grpc-gateway", cfg.ec.EnableGRPCGateway, "Enable GRPC gateway.")
288
289
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
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
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
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
342
343
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
365 return err
366 }
367
368 func (cfg *config) configFromCmdLine() error {
369
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
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
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
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
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
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