diff --git a/server/config/config.go b/server/config/config.go index 3bf994b7a9f2..8f57112b3c60 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -188,12 +188,6 @@ type ServerConfig struct { // be refined to mlock in-use area of bbolt only. MemoryMlock bool `json:"memory-mlock"` - // ExperimentalTxnModeWriteWithSharedBuffer enable write transaction to use - // a shared buffer in its readonly check operations. - // TODO: Delete in v3.7 - // Deprecated: Use TxnModeWriteWithSharedBuffer Feature Gate instead. Will be decommissioned in v3.7. - ExperimentalTxnModeWriteWithSharedBuffer bool `json:"experimental-txn-mode-write-with-shared-buffer"` - // BootstrapDefragThresholdMegabytes is the minimum number of megabytes needed to be freed for etcd server to // consider running defrag during bootstrap. Needs to be set to non-zero value to take effect. BootstrapDefragThresholdMegabytes uint `json:"bootstrap-defrag-threshold-megabytes"` @@ -204,8 +198,8 @@ type ServerConfig struct { // V2Deprecation defines a phase of v2store deprecation process. V2Deprecation V2DeprecationEnum `json:"v2-deprecation"` - // ExperimentalLocalAddress is the local IP address to use when communicating with a peer. - ExperimentalLocalAddress string `json:"experimental-local-address"` + // LocalAddress is the local IP address to use when communicating with a peer. + LocalAddress string `json:"local-address"` // ServerFeatureGate is a server level feature gate ServerFeatureGate featuregate.FeatureGate diff --git a/server/embed/config.go b/server/embed/config.go index 536e18867735..5b4aceeb19c3 100644 --- a/server/embed/config.go +++ b/server/embed/config.go @@ -101,21 +101,11 @@ const ( // Compress = false // compress the rotated log in gzip format DefaultLogRotationConfig = `{"maxsize": 100, "maxage": 0, "maxbackups": 0, "localtime": false, "compress": false}` - // ExperimentalDistributedTracingAddress is the default collector address. - // TODO: delete in v3.7 - // Deprecated: Use DefaultDistributedTracingAddress instead. Will be decommissioned in v3.7. - ExperimentalDistributedTracingAddress = "localhost:4317" // DefaultDistributedTracingAddress is the default collector address. DefaultDistributedTracingAddress = "localhost:4317" - // ExperimentalDistributedTracingServiceName is the default etcd service name. - // TODO: delete in v3.7 - // Deprecated: Use DefaultDistributedTracingServiceName instead. Will be decommissioned in v3.7. - ExperimentalDistributedTracingServiceName = "etcd" // DefaultDistributedTracingServiceName is the default etcd service name. DefaultDistributedTracingServiceName = "etcd" - DefaultExperimentalTxnModeWriteWithSharedBuffer = true - // DefaultStrictReconfigCheck is the default value for "--strict-reconfig-check" flag. // It's enabled by default. DefaultStrictReconfigCheck = true @@ -143,28 +133,6 @@ var ( // indirection for testing getCluster = srv.GetCluster - - // in 3.6, we are migration all the --experimental flags to feature gate and flags without the prefix. - // This is the mapping from the non boolean `experimental-` to the new flags. - // TODO: delete in v3.7 - experimentalFlagMigrationMap = map[string]string{ - "experimental-compact-hash-check-time": "compact-hash-check-time", - "experimental-corrupt-check-time": "corrupt-check-time", - "experimental-compaction-batch-limit": "compaction-batch-limit", - "experimental-watch-progress-notify-interval": "watch-progress-notify-interval", - "experimental-warning-apply-duration": "warning-apply-duration", - "experimental-bootstrap-defrag-threshold-megabytes": "bootstrap-defrag-threshold-megabytes", - "experimental-memory-mlock": "memory-mlock", - "experimental-snapshot-catchup-entries": "snapshot-catchup-entries", - "experimental-compaction-sleep-interval": "compaction-sleep-interval", - "experimental-downgrade-check-time": "downgrade-check-time", - "experimental-peer-skip-client-san-verification": "peer-skip-client-san-verification", - "experimental-enable-distributed-tracing": "enable-distributed-tracing", - "experimental-distributed-tracing-address": "distributed-tracing-address", - "experimental-distributed-tracing-service-name": "distributed-tracing-service-name", - "experimental-distributed-tracing-instance-id": "distributed-tracing-instance-id", - "experimental-distributed-tracing-sampling-rate": "distributed-tracing-sampling-rate", - } ) var ( @@ -200,17 +168,6 @@ type Config struct { // Deprecated: Will be decommissioned in v3.7. SnapshotCount uint64 `json:"snapshot-count"` - // ExperimentalSnapshotCatchUpEntries is the number of entries for a slow follower - // to catch-up after compacting the raft storage entries. - // We expect the follower has a millisecond level latency with the leader. - // The max throughput is around 10K. Keep a 5K entries is enough for helping - // follower to catch up. - // TODO: remove in v3.7. - // Note we made a mistake in https://github.com/etcd-io/etcd/pull/15033. The json tag - // `*-catch-up-*` isn't consistent with the command line flag `*-catchup-*`. - // Deprecated: Use SnapshotCatchUpEntries instead. Will be removed in v3.7. - ExperimentalSnapshotCatchUpEntries uint64 `json:"experimental-snapshot-catch-up-entries"` - // SnapshotCatchUpEntries is the number of entires for a slow follower // to catch-up after compacting the raft storage entries. // We expect the follower has a millisecond level latency with the leader. @@ -401,73 +358,24 @@ type Config struct { // AuthTokenTTL in seconds of the simple token AuthTokenTTL uint `json:"auth-token-ttl"` - // ExperimentalInitialCorruptCheck defines to check data corrution on boot. - // TODO: delete in v3.7 - // Deprecated: Use InitialCorruptCheck Feature Gate instead. Will be decommissioned in v3.7. - ExperimentalInitialCorruptCheck bool `json:"experimental-initial-corrupt-check"` - // ExperimentalCorruptCheckTime is the duration of time between cluster corruption check passes. - // TODO: delete in v3.7 - // Deprecated: Use CorruptCheckTime instead. Will be decommissioned in v3.7. - ExperimentalCorruptCheckTime time.Duration `json:"experimental-corrupt-check-time"` // CorruptCheckTime is the duration of time between cluster corruption check passes. CorruptCheckTime time.Duration `json:"corrupt-check-time"` - // ExperimentalCompactHashCheckEnabled enables leader to periodically check followers compaction hashes. - // TODO: delete in v3.7 - // Deprecated: Use CompactHashCheck Feature Gate. Will be decommissioned in v3.7. - ExperimentalCompactHashCheckEnabled bool `json:"experimental-compact-hash-check-enabled"` - // ExperimentalCompactHashCheckTime is the duration of time between leader checks followers compaction hashes. - // TODO: delete in v3.7 - // Deprecated: Use CompactHashCheckTime instead. Will be decommissioned in v3.7. - ExperimentalCompactHashCheckTime time.Duration `json:"experimental-compact-hash-check-time"` + // CompactHashCheckTime is the duration of time between leader checks followers compaction hashes. CompactHashCheckTime time.Duration `json:"compact-hash-check-time"` - - // ExperimentalEnableLeaseCheckpoint enables leader to send regular checkpoints to other members to prevent reset of remaining TTL on leader change. - ExperimentalEnableLeaseCheckpoint bool `json:"experimental-enable-lease-checkpoint"` - // ExperimentalEnableLeaseCheckpointPersist enables 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. - // TODO: Delete in v3.7 - // Deprecated: To be decommissioned in v3.7. - ExperimentalEnableLeaseCheckpointPersist bool `json:"experimental-enable-lease-checkpoint-persist"` - // ExperimentalCompactionBatchLimit Sets the maximum revisions deleted in each compaction batch. - // TODO: Delete in v3.7 - // Deprecated: Use CompactionBatchLimit instead. Will be decommissioned in v3.7. - ExperimentalCompactionBatchLimit int `json:"experimental-compaction-batch-limit"` // CompactionBatchLimit Sets the maximum revisions deleted in each compaction batch. CompactionBatchLimit int `json:"compaction-batch-limit"` - // ExperimentalCompactionSleepInterval is the sleep interval between every etcd compaction loop. - // TODO: Delete in v3.7 - // Deprecated: Use CompactionSleepInterval instead. Will be decommissioned in v3.7. - ExperimentalCompactionSleepInterval time.Duration `json:"experimental-compaction-sleep-interval"` // CompactionSleepInterval is the sleep interval between every etcd compaction loop. CompactionSleepInterval time.Duration `json:"compaction-sleep-interval"` - // ExperimentalWatchProgressNotifyInterval is the time duration of periodic watch progress notifications. - // TODO: Delete in v3.7 - // Deprecated: Use WatchProgressNotifyInterval instead. Will be decommissioned in v3.7. - ExperimentalWatchProgressNotifyInterval time.Duration `json:"experimental-watch-progress-notify-interval"` // WatchProgressNotifyInterval is the time duration of periodic watch progress notifications. WatchProgressNotifyInterval time.Duration `json:"watch-progress-notify-interval"` - // ExperimentalWarningApplyDuration is the time duration after which a warning is generated if applying request - // takes more time than this value. - // TODO: Delete in v3.7 - // Deprecated: Use WarningApplyDuration instead. Will be decommissioned in v3.7. - ExperimentalWarningApplyDuration time.Duration `json:"experimental-warning-apply-duration"` // WarningApplyDuration is the time duration after which a warning is generated if applying request WarningApplyDuration time.Duration `json:"warning-apply-duration"` - // ExperimentalBootstrapDefragThresholdMegabytes is the minimum number of megabytes needed to be freed for etcd server to - // consider running defrag during bootstrap. Needs to be set to non-zero value to take effect. - // TODO: Delete in v3.7 - // Deprecated: Use BootstrapDefragThresholdMegabytes instead. Will be decommissioned in v3.7. - ExperimentalBootstrapDefragThresholdMegabytes uint `json:"experimental-bootstrap-defrag-threshold-megabytes"` // BootstrapDefragThresholdMegabytes is the minimum number of megabytes needed to be freed for etcd server to BootstrapDefragThresholdMegabytes uint `json:"bootstrap-defrag-threshold-megabytes"` // WarningUnaryRequestDuration is the time duration after which a warning is generated if applying // unary request takes more time than this value. WarningUnaryRequestDuration time.Duration `json:"warning-unary-request-duration"` - // ExperimentalWarningUnaryRequestDuration is the time duration after which a warning is generated if applying - // TODO: Delete in v3.7 - // Deprecated: Use WarningUnaryRequestDuration. Will be decommissioned in v3.7. - ExperimentalWarningUnaryRequestDuration time.Duration `json:"experimental-warning-unary-request-duration"` // MaxLearners sets a limit to the number of learner members that can exist in the cluster membership. MaxLearners int `json:"max-learners"` @@ -479,55 +387,23 @@ type Config struct { ListenMetricsUrls []url.URL ListenMetricsUrlsJSON string `json:"listen-metrics-urls"` - // ExperimentalEnableDistributedTracing indicates if experimental tracing using OpenTelemetry is enabled. - // TODO: delete in v3.7 - // Deprecated: Use EnableDistributedTracing instead. Will be decommissioned in v3.7. - ExperimentalEnableDistributedTracing bool `json:"experimental-enable-distributed-tracing"` // EnableDistributedTracing indicates if tracing using OpenTelemetry is enabled. EnableDistributedTracing bool `json:"enable-distributed-tracing"` - // ExperimentalDistributedTracingAddress is the address of the OpenTelemetry Collector. - // Can only be set if ExperimentalEnableDistributedTracing is true. - // TODO: delete in v3.7 - // Deprecated: Use DistributedTracingAddress instead. Will be decommissioned in v3.7. - ExperimentalDistributedTracingAddress string `json:"experimental-distributed-tracing-address"` // DistributedTracingAddress is the address of the OpenTelemetry Collector. // Can only be set if EnableDistributedTracing is true. DistributedTracingAddress string `json:"distributed-tracing-address"` - // ExperimentalDistributedTracingServiceName is the name of the service. - // Can only be used if ExperimentalEnableDistributedTracing is true. - // TODO: delete in v3.7 - // Deprecated: Use DistributedTracingServiceName instead. Will be decommissioned in v3.7. - ExperimentalDistributedTracingServiceName string `json:"experimental-distributed-tracing-service-name"` // DistributedTracingServiceName is the name of the service. // Can only be used if EnableDistributedTracing is true. DistributedTracingServiceName string `json:"distributed-tracing-service-name"` - // ExperimentalDistributedTracingServiceInstanceID is the ID key of the service. - // This ID must be unique, as helps to distinguish instances of the same service - // that exist at the same time. - // Can only be used if ExperimentalEnableDistributedTracing is true. - // TODO: delete in v3.7 - // Deprecated: Use DistributedTracingServiceInstanceID instead. Will be decommissioned in v3.7. - ExperimentalDistributedTracingServiceInstanceID string `json:"experimental-distributed-tracing-instance-id"` // DistributedTracingServiceInstanceID is the ID key of the service. // This ID must be unique, as helps to distinguish instances of the same service // that exist at the same time. // Can only be used if EnableDistributedTracing is true. DistributedTracingServiceInstanceID string `json:"distributed-tracing-instance-id"` - // ExperimentalDistributedTracingSamplingRatePerMillion is the number of samples to collect per million spans. - // Defaults to 0. - // TODO: delete in v3.7 - // Deprecated: Use DistributedTracingSamplingRatePerMillion instead. Will be decommissioned in v3.7. - ExperimentalDistributedTracingSamplingRatePerMillion int `json:"experimental-distributed-tracing-sampling-rate"` // DistributedTracingSamplingRatePerMillion is the number of samples to collect per million spans. // Defaults to 0. DistributedTracingSamplingRatePerMillion int `json:"distributed-tracing-sampling-rate"` - // ExperimentalPeerSkipClientSanVerification determines whether to skip verification of SAN field - // in client certificate for peer connections. - // TODO: Delete in v3.7 - // Deprecated: Use `peer-skip-client-san-verification` instead. Will be decommissioned in v3.7. - ExperimentalPeerSkipClientSanVerification bool `json:"experimental-peer-skip-client-san-verification"` - // Logger is logger options: currently only supports "zap". // "capnslog" is removed in v3.5. Logger string `json:"logger"` @@ -562,10 +438,6 @@ type Config struct { // Setting this is unsafe and will cause data loss. UnsafeNoFsync bool `json:"unsafe-no-fsync"` - // ExperimentalDowngradeCheckTime is the duration between two downgrade status checks (in seconds). - // TODO: Delete `ExperimentalDowngradeCheckTime` in v3.7. - // Deprecated: Use DowngradeCheckTime instead. Will be decommissioned in v3.7. - ExperimentalDowngradeCheckTime time.Duration `json:"experimental-downgrade-check-time"` // DowngradeCheckTime is the duration between two downgrade status checks (in seconds). DowngradeCheckTime time.Duration `json:"downgrade-check-time"` @@ -577,21 +449,6 @@ type Config struct { // be refined to mlock in-use area of bbolt only. MemoryMlock bool `json:"memory-mlock"` - // ExperimentalMemoryMlock enables mlocking of etcd owned memory pages. - // TODO: Delete in v3.7 - // Deprecated: Use MemoryMlock instad. To be decommissioned in v3.7. - ExperimentalMemoryMlock bool `json:"experimental-memory-mlock"` - - // ExperimentalTxnModeWriteWithSharedBuffer enables write transaction to use a shared buffer in its readonly check operations. - // TODO: Delete in v3.7 - // Deprecated: Use TxnModeWriteWithSharedBuffer Feature Flag. Will be decommissioned in v3.7. - ExperimentalTxnModeWriteWithSharedBuffer bool `json:"experimental-txn-mode-write-with-shared-buffer"` - - // ExperimentalStopGRPCServiceOnDefrag enables etcd gRPC service to stop serving client requests on defragmentation. - // TODO: Delete in v3.7 - // Deprecated: Use StopGRPCServiceOnDefrag Feature Flag. Will be decommissioned in v3.7. - ExperimentalStopGRPCServiceOnDefrag bool `json:"experimental-stop-grpc-service-on-defrag"` - // V2Deprecation describes phase of API & Storage V2 support. // Do not set this field for embedded use cases, as it has no effect. However, setting it will not cause any harm. // TODO: Delete in v3.8 @@ -652,9 +509,8 @@ func NewConfig() *Config { Name: DefaultName, - SnapshotCount: etcdserver.DefaultSnapshotCount, - ExperimentalSnapshotCatchUpEntries: etcdserver.DefaultSnapshotCatchUpEntries, - SnapshotCatchUpEntries: etcdserver.DefaultSnapshotCatchUpEntries, + SnapshotCount: etcdserver.DefaultSnapshotCount, + SnapshotCatchUpEntries: etcdserver.DefaultSnapshotCatchUpEntries, MaxTxnOps: DefaultMaxTxnOps, MaxRequestBytes: DefaultMaxRequestBytes, @@ -706,23 +562,14 @@ func NewConfig() *Config { LogRotationConfigJSON: DefaultLogRotationConfig, EnableGRPCGateway: true, - ExperimentalDowngradeCheckTime: DefaultDowngradeCheckTime, - DowngradeCheckTime: DefaultDowngradeCheckTime, - MemoryMlock: false, - // TODO: delete in v3.7 - ExperimentalMemoryMlock: false, - ExperimentalStopGRPCServiceOnDefrag: false, - MaxLearners: membership.DefaultMaxLearners, + DowngradeCheckTime: DefaultDowngradeCheckTime, + MemoryMlock: false, + MaxLearners: membership.DefaultMaxLearners, - ExperimentalTxnModeWriteWithSharedBuffer: DefaultExperimentalTxnModeWriteWithSharedBuffer, - ExperimentalDistributedTracingAddress: DefaultDistributedTracingAddress, - DistributedTracingAddress: DefaultDistributedTracingAddress, - ExperimentalDistributedTracingServiceName: DefaultDistributedTracingServiceName, - DistributedTracingServiceName: DefaultDistributedTracingServiceName, + DistributedTracingAddress: DefaultDistributedTracingAddress, + DistributedTracingServiceName: DefaultDistributedTracingServiceName, CompactHashCheckTime: DefaultCompactHashCheckTime, - // TODO: delete in v3.7 - ExperimentalCompactHashCheckTime: DefaultCompactHashCheckTime, V2Deprecation: config.V2DeprDefault, @@ -860,7 +707,6 @@ func (cfg *Config) AddFlags(fs *flag.FlagSet) { fs.Var(flags.NewStringsValue(""), "peer-cert-allowed-cn", "Comma-separated list of allowed CNs for inter-peer TLS authentication.") fs.Var(flags.NewStringsValue(""), "peer-cert-allowed-hostname", "Comma-separated list of allowed SAN hostnames for inter-peer TLS authentication.") 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).") - fs.BoolVar(&cfg.ExperimentalPeerSkipClientSanVerification, "experimental-peer-skip-client-san-verification", false, "Skip verification of SAN field in client certificate for peer connections.Deprecated in v3.6 and will be decommissioned in v3.7. Use peer-skip-client-san-verification instead") fs.BoolVar(&cfg.PeerTLSInfo.SkipClientSANVerify, "peer-skip-client-san-verification", false, "Skip verification of SAN field in client certificate for peer connections.") fs.StringVar(&cfg.TlsMinVersion, "tls-min-version", string(tlsutil.TLSVersion12), "Minimum TLS version supported by etcd. Possible values: TLS1.2, TLS1.3.") fs.StringVar(&cfg.TlsMaxVersion, "tls-max-version", string(tlsutil.TLSVersionDefault), "Maximum TLS version supported by etcd. Possible values: TLS1.2, TLS1.3 (empty defers to Go).") @@ -889,20 +735,10 @@ func (cfg *Config) AddFlags(fs *flag.FlagSet) { // additional metrics fs.StringVar(&cfg.Metrics, "metrics", cfg.Metrics, "Set level of detail for exported metrics, specify 'extensive' to include server side grpc histogram metrics") - // experimental distributed tracing - fs.BoolVar(&cfg.ExperimentalEnableDistributedTracing, "experimental-enable-distributed-tracing", false, "Enable experimental distributed tracing using OpenTelemetry Tracing. Deprecated in v3.6 and will be decommissioned in v3.7. Use --enable-distributed-tracing instead.") fs.BoolVar(&cfg.EnableDistributedTracing, "enable-distributed-tracing", false, "Enable distributed tracing using OpenTelemetry Tracing.") - - fs.StringVar(&cfg.ExperimentalDistributedTracingAddress, "experimental-distributed-tracing-address", cfg.ExperimentalDistributedTracingAddress, "Address for distributed tracing used for OpenTelemetry Tracing (if enabled with experimental-enable-distributed-tracing flag). Deprecated in v3.6 and will be decommissioned in v3.7. Use --distributed-tracing-address instead.") fs.StringVar(&cfg.DistributedTracingAddress, "distributed-tracing-address", cfg.DistributedTracingAddress, "Address for distributed tracing used for OpenTelemetry Tracing (if enabled with enable-distributed-tracing flag).") - - fs.StringVar(&cfg.ExperimentalDistributedTracingServiceName, "experimental-distributed-tracing-service-name", cfg.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. Deprecated in v3.6 and will be decommissioned in v3.7. Use --distributed-tracing-service-name instead.") fs.StringVar(&cfg.DistributedTracingServiceName, "distributed-tracing-service-name", cfg.DistributedTracingServiceName, "Configures service name for distributed tracing to be used to define service name for OpenTelemetry Tracing (if enabled with enable-distributed-tracing flag). 'etcd' is the default service name. Use the same service name for all instances of etcd.") - - fs.StringVar(&cfg.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. Deprecated in v3.6 and will be decommissioned in v3.7. Use --distributed-tracing-instance-id instead.") fs.StringVar(&cfg.DistributedTracingServiceInstanceID, "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 enable-distributed-tracing flag). There is no default value set. This ID must be unique per etcd instance.") - - fs.IntVar(&cfg.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). Deprecated in v3.6 and will be decommissioned in v3.7. Use --distributed-tracing-sampling-rate instead.") fs.IntVar(&cfg.DistributedTracingSamplingRatePerMillion, "distributed-tracing-sampling-rate", 0, "Number of samples to collect per million spans for OpenTelemetry Tracing (if enabled with enable-distributed-tracing flag).") // auth @@ -912,48 +748,18 @@ func (cfg *Config) AddFlags(fs *flag.FlagSet) { // gateway fs.BoolVar(&cfg.EnableGRPCGateway, "enable-grpc-gateway", cfg.EnableGRPCGateway, "Enable GRPC gateway.") - - // experimental - fs.BoolVar(&cfg.ExperimentalInitialCorruptCheck, "experimental-initial-corrupt-check", cfg.ExperimentalInitialCorruptCheck, "Enable to check data corruption before serving any client/peer traffic.") - // TODO: delete in v3.7 - fs.DurationVar(&cfg.ExperimentalCorruptCheckTime, "experimental-corrupt-check-time", cfg.ExperimentalCorruptCheckTime, "Duration of time between cluster corruption check passes. Deprecated in v3.6 and will be decommissioned in v3.7. Use --corrupt-check-time instead") fs.DurationVar(&cfg.CorruptCheckTime, "corrupt-check-time", cfg.CorruptCheckTime, "Duration of time between cluster corruption check passes.") - // TODO: delete in v3.7 - fs.BoolVar(&cfg.ExperimentalCompactHashCheckEnabled, "experimental-compact-hash-check-enabled", cfg.ExperimentalCompactHashCheckEnabled, "Enable leader to periodically check followers compaction hashes. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--feature-gates=CompactHashCheck=true' instead") - fs.DurationVar(&cfg.ExperimentalCompactHashCheckTime, "experimental-compact-hash-check-time", cfg.ExperimentalCompactHashCheckTime, "Duration of time between leader checks followers compaction hashes. Deprecated in v3.6 and will be decommissioned in v3.7. Use --compact-hash-check-time instead.") - fs.DurationVar(&cfg.CompactHashCheckTime, "compact-hash-check-time", cfg.CompactHashCheckTime, "Duration of time between leader checks followers compaction hashes.") - fs.BoolVar(&cfg.ExperimentalEnableLeaseCheckpoint, "experimental-enable-lease-checkpoint", false, "Enable leader to send regular checkpoints to other members to prevent reset of remaining TTL on leader change.") - // TODO: delete in v3.7 - fs.BoolVar(&cfg.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.") - // TODO: delete in v3.7 - fs.IntVar(&cfg.ExperimentalCompactionBatchLimit, "experimental-compaction-batch-limit", cfg.ExperimentalCompactionBatchLimit, "Sets the maximum revisions deleted in each compaction batch. Deprecated in v3.6 and will be decommissioned in v3.7. Use --compaction-batch-limit instead.") fs.IntVar(&cfg.CompactionBatchLimit, "compaction-batch-limit", cfg.CompactionBatchLimit, "Sets the maximum revisions deleted in each compaction batch.") - fs.DurationVar(&cfg.ExperimentalCompactionSleepInterval, "experimental-compaction-sleep-interval", cfg.ExperimentalCompactionSleepInterval, "Sets the sleep interval between each compaction batch. Deprecated in v3.6 and will be decommissioned in v3.7. Use --compaction-sleep-interval instead.") fs.DurationVar(&cfg.CompactionSleepInterval, "compaction-sleep-interval", cfg.CompactionSleepInterval, "Sets the sleep interval between each compaction batch.") - // TODO: delete in v3.7 - fs.DurationVar(&cfg.ExperimentalWatchProgressNotifyInterval, "experimental-watch-progress-notify-interval", cfg.ExperimentalWatchProgressNotifyInterval, "Duration of periodic watch progress notifications. Deprecated in v3.6 and will be decommissioned in v3.7. Use --watch-progress-notify-interval instead.") fs.DurationVar(&cfg.WatchProgressNotifyInterval, "watch-progress-notify-interval", cfg.WatchProgressNotifyInterval, "Duration of periodic watch progress notifications.") fs.DurationVar(&cfg.DowngradeCheckTime, "downgrade-check-time", cfg.DowngradeCheckTime, "Duration of time between two downgrade status checks.") - // TODO: delete in v3.7 - fs.DurationVar(&cfg.ExperimentalDowngradeCheckTime, "experimental-downgrade-check-time", cfg.ExperimentalDowngradeCheckTime, "Duration of time between two downgrade status checks. Deprecated in v3.6 and will be decommissioned in v3.7. Use --downgrade-check-time instead.") - // TODO: delete in v3.7 - fs.DurationVar(&cfg.ExperimentalWarningApplyDuration, "experimental-warning-apply-duration", cfg.ExperimentalWarningApplyDuration, "Time duration after which a warning is generated if request takes more time. Deprecated in v3.6 and will be decommissioned in v3.7. Use --warning-watch-progress-duration instead.") fs.DurationVar(&cfg.WarningApplyDuration, "warning-apply-duration", cfg.WarningApplyDuration, "Time duration after which a warning is generated if watch progress takes more time.") fs.DurationVar(&cfg.WarningUnaryRequestDuration, "warning-unary-request-duration", cfg.WarningUnaryRequestDuration, "Time duration after which a warning is generated if a unary request takes more time.") - fs.DurationVar(&cfg.ExperimentalWarningUnaryRequestDuration, "experimental-warning-unary-request-duration", cfg.ExperimentalWarningUnaryRequestDuration, "Time duration after which a warning is generated if a unary request takes more time. It's deprecated, and will be decommissioned in v3.7. Use --warning-unary-request-duration instead.") - // TODO: delete in v3.7 - fs.BoolVar(&cfg.ExperimentalMemoryMlock, "experimental-memory-mlock", cfg.ExperimentalMemoryMlock, "Enable to enforce etcd pages (in particular bbolt) to stay in RAM.") fs.BoolVar(&cfg.MemoryMlock, "memory-mlock", cfg.MemoryMlock, "Enable to enforce etcd pages (in particular bbolt) to stay in RAM.") - fs.BoolVar(&cfg.ExperimentalTxnModeWriteWithSharedBuffer, "experimental-txn-mode-write-with-shared-buffer", true, "Enable the write transaction to use a shared buffer in its readonly check operations.") - fs.BoolVar(&cfg.ExperimentalStopGRPCServiceOnDefrag, "experimental-stop-grpc-service-on-defrag", cfg.ExperimentalStopGRPCServiceOnDefrag, "Enable etcd gRPC service to stop serving client requests on defragmentation.") - // TODO: delete in v3.7 - fs.UintVar(&cfg.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. It's deprecated, and will be decommissioned in v3.7. Use --bootstrap-defrag-threshold-megabytes instead.") fs.UintVar(&cfg.BootstrapDefragThresholdMegabytes, "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.") - // TODO: delete in v3.7 fs.IntVar(&cfg.MaxLearners, "max-learners", membership.DefaultMaxLearners, "Sets the maximum number of learners that can be available in the cluster membership.") - fs.Uint64Var(&cfg.ExperimentalSnapshotCatchUpEntries, "experimental-snapshot-catchup-entries", cfg.ExperimentalSnapshotCatchUpEntries, "Number of entries for a slow follower to catch up after compacting the raft storage entries. Deprecated in v3.6 and will be decommissioned in v3.7. Use --snapshot-catchup-entries instead.") fs.Uint64Var(&cfg.SnapshotCatchUpEntries, "snapshot-catchup-entries", cfg.SnapshotCatchUpEntries, "Number of entries for a slow follower to catch up after compacting the raft storage entries.") // unsafe @@ -1013,28 +819,6 @@ func (cfg *configYAML) configFromFile(path string) error { } } - // attempt to fix a bug introduced in https://github.com/etcd-io/etcd/pull/15033 - // both `experimental-snapshot-catch-up-entries` and `experimental-snapshot-catchup-entries` refer to the same field, - // map the YAML field "experimental-snapshot-catch-up-entries" to the flag "experimental-snapshot-catchup-entries". - if val, ok := cfgMap["experimental-snapshot-catch-up-entries"]; ok { - cfgMap["experimental-snapshot-catchup-entries"] = val - cfg.ExperimentalSnapshotCatchUpEntries = uint64(val.(float64)) - cfg.FlagsExplicitlySet["experimental-snapshot-catchup-entries"] = true - } - - getBoolFlagVal := func(flagName string) *bool { - flagVal, ok := cfgMap[flagName] - if !ok { - return nil - } - boolVal := flagVal.(bool) - return &boolVal - } - err = SetFeatureGatesFromExperimentalFlags(cfg.ServerFeatureGate, getBoolFlagVal, cfg.configJSON.ServerFeatureGatesJSON) - if err != nil { - return err - } - if cfg.configJSON.ListenPeerURLs != "" { u, err := types.NewURLs(strings.Split(cfg.configJSON.ListenPeerURLs, ",")) if err != nil { @@ -1128,36 +912,6 @@ func (cfg *configYAML) configFromFile(path string) error { return cfg.Validate() } -// SetFeatureGatesFromExperimentalFlags sets the feature gate values if the feature gate is not explicitly set -// while their corresponding experimental flags are explicitly set, for all the features in ExperimentalFlagToFeatureMap. -// TODO: remove after all experimental flags are deprecated. -func SetFeatureGatesFromExperimentalFlags(fg featuregate.FeatureGate, getExperimentalFlagVal func(string) *bool, featureGatesVal string) error { - m := make(map[featuregate.Feature]bool) - // verify that the feature gate and its experimental flag are not both set at the same time. - for expFlagName, featureName := range features.ExperimentalFlagToFeatureMap { - flagVal := getExperimentalFlagVal(expFlagName) - if flagVal == nil { - continue - } - if strings.Contains(featureGatesVal, string(featureName)) { - return fmt.Errorf("cannot specify both flags: --%s=%v and --%s=%s=%v at the same time, please just use --%s=%s=%v", - expFlagName, *flagVal, ServerFeatureGateFlagName, featureName, fg.Enabled(featureName), ServerFeatureGateFlagName, featureName, fg.Enabled(featureName)) - } - m[featureName] = *flagVal - } - - // filter out unknown features for fg, because we could use SetFeatureGatesFromExperimentalFlags both for - // server and cluster level feature gates. - allFeatures := fg.(featuregate.MutableFeatureGate).GetAll() - mFiltered := make(map[string]bool) - for k, v := range m { - if _, ok := allFeatures[k]; ok { - mFiltered[string(k)] = v - } - } - return fg.(featuregate.MutableFeatureGate).SetFromMap(mFiltered) -} - func updateCipherSuites(tls *transport.TLSInfo, ss []string) error { if len(tls.CipherSuites) > 0 && len(ss) > 0 { return fmt.Errorf("TLSInfo.CipherSuites is already specified (given %v)", ss) @@ -1185,14 +939,6 @@ func updateMinMaxVersions(info *transport.TLSInfo, min, max string) { // Validate ensures that '*embed.Config' fields are properly configured. func (cfg *Config) Validate() error { - // make sure there is no conflict in the flag settings in the ExperimentalNonBoolFlagMigrationMap - // TODO: delete in v3.7 - for oldFlag, newFlag := range experimentalFlagMigrationMap { - if cfg.FlagsExplicitlySet[oldFlag] && cfg.FlagsExplicitlySet[newFlag] { - return fmt.Errorf("cannot set --%s and --%s at the same time, please use --%s only", oldFlag, newFlag, newFlag) - } - } - if err := cfg.setupLogging(); err != nil { return err } @@ -1297,10 +1043,7 @@ func (cfg *Config) Validate() error { if cfg.ServerFeatureGate.Enabled(features.LeaseCheckpointPersist) && !cfg.ServerFeatureGate.Enabled(features.LeaseCheckpoint) { return fmt.Errorf("enabling feature gate LeaseCheckpointPersist requires enabling feature gate LeaseCheckpoint") } - // TODO: delete in v3.7 - if cfg.ExperimentalCompactHashCheckTime <= 0 { - return fmt.Errorf("--experimental-compact-hash-check-time must be >0 (set to %v)", cfg.ExperimentalCompactHashCheckTime) - } + if cfg.CompactHashCheckTime <= 0 { return fmt.Errorf("--compact-hash-check-time must be >0 (set to %v)", cfg.CompactHashCheckTime) } diff --git a/server/embed/config_test.go b/server/embed/config_test.go index 526b42799c6f..729595aab22c 100644 --- a/server/embed/config_test.go +++ b/server/embed/config_test.go @@ -22,7 +22,6 @@ import ( "net" "net/url" "os" - "strconv" "testing" "time" @@ -97,16 +96,10 @@ func TestConfigFileOtherFields(t *testing.T) { func TestConfigFileFeatureGates(t *testing.T) { testCases := []struct { - name string - serverFeatureGatesJSON string - experimentalStopGRPCServiceOnDefrag string - experimentalInitialCorruptCheck string - experimentalCompactHashCheckEnabled string - experimentalTxnModeWriteWithSharedBuffer string - experimentalEnableLeaseCheckpoint string - experimentalEnableLeaseCheckpointPersist string - expectErr bool - expectedFeatures map[featuregate.Feature]bool + name string + serverFeatureGatesJSON string + expectErr bool + expectedFeatures map[featuregate.Feature]bool }{ { name: "default", @@ -118,94 +111,6 @@ func TestConfigFileFeatureGates(t *testing.T) { features.LeaseCheckpointPersist: false, }, }, - { - name: "cannot set both experimental flag and feature gate flag for StopGRPCServiceOnDefrag", - serverFeatureGatesJSON: "StopGRPCServiceOnDefrag=true", - experimentalStopGRPCServiceOnDefrag: "false", - expectErr: true, - }, - { - name: "cannot set both experimental flag and feature gate flag for InitialCorruptCheck", - serverFeatureGatesJSON: "InitialCorruptCheck=true", - experimentalInitialCorruptCheck: "false", - expectErr: true, - }, - { - name: "cannot set both experimental flag and feature gate flag for TxnModeWriteWithSharedBuffer", - serverFeatureGatesJSON: "TxnModeWriteWithSharedBuffer=true", - experimentalTxnModeWriteWithSharedBuffer: "false", - expectErr: true, - }, - { - name: "ok to set different experimental flag and feature gate flag", - serverFeatureGatesJSON: "InitialCorruptCheck=true", - experimentalStopGRPCServiceOnDefrag: "true", - expectedFeatures: map[featuregate.Feature]bool{ - features.StopGRPCServiceOnDefrag: true, - features.TxnModeWriteWithSharedBuffer: true, - features.InitialCorruptCheck: true, - }, - }, - { - name: "ok to set different multiple experimental flags and feature gate flags", - serverFeatureGatesJSON: "StopGRPCServiceOnDefrag=true,TxnModeWriteWithSharedBuffer=true,LeaseCheckpoint=true,SetMemberLocalAddr=true", - experimentalCompactHashCheckEnabled: "true", - experimentalInitialCorruptCheck: "true", - expectedFeatures: map[featuregate.Feature]bool{ - features.StopGRPCServiceOnDefrag: true, - features.CompactHashCheck: true, - features.InitialCorruptCheck: true, - features.TxnModeWriteWithSharedBuffer: true, - features.LeaseCheckpoint: true, - features.SetMemberLocalAddr: true, - }, - }, - { - name: "can set feature gate StopGRPCServiceOnDefrag to true from experimental flag", - experimentalStopGRPCServiceOnDefrag: "true", - expectedFeatures: map[featuregate.Feature]bool{ - features.StopGRPCServiceOnDefrag: true, - features.TxnModeWriteWithSharedBuffer: true, - }, - }, - { - name: "can set feature gate StopGRPCServiceOnDefrag to false from experimental flag", - experimentalStopGRPCServiceOnDefrag: "false", - expectedFeatures: map[featuregate.Feature]bool{ - features.StopGRPCServiceOnDefrag: false, - features.TxnModeWriteWithSharedBuffer: true, - }, - }, - { - name: "can set feature gate experimentalInitialCorruptCheck to true from experimental flag", - experimentalInitialCorruptCheck: "true", - expectedFeatures: map[featuregate.Feature]bool{ - features.InitialCorruptCheck: true, - features.TxnModeWriteWithSharedBuffer: true, - }, - }, - { - name: "can set feature gate experimentalInitialCorruptCheck to false from experimental flag", - experimentalInitialCorruptCheck: "false", - expectedFeatures: map[featuregate.Feature]bool{ - features.InitialCorruptCheck: false, - features.TxnModeWriteWithSharedBuffer: true, - }, - }, - { - name: "can set feature gate TxnModeWriteWithSharedBuffer to true from experimental flag", - experimentalTxnModeWriteWithSharedBuffer: "true", - expectedFeatures: map[featuregate.Feature]bool{ - features.TxnModeWriteWithSharedBuffer: true, - }, - }, - { - name: "can set feature gate TxnModeWriteWithSharedBuffer to false from experimental flag", - experimentalTxnModeWriteWithSharedBuffer: "false", - expectedFeatures: map[featuregate.Feature]bool{ - features.TxnModeWriteWithSharedBuffer: false, - }, - }, { name: "can set feature gate StopGRPCServiceOnDefrag to true from feature gate flag", serverFeatureGatesJSON: "StopGRPCServiceOnDefrag=true", @@ -244,28 +149,6 @@ func TestConfigFileFeatureGates(t *testing.T) { features.TxnModeWriteWithSharedBuffer: false, }, }, - { - name: "cannot set both experimental flag and feature gate flag for ExperimentalCompactHashCheckEnabled", - serverFeatureGatesJSON: "CompactHashCheck=true", - experimentalCompactHashCheckEnabled: "false", - expectErr: true, - }, - { - name: "can set feature gate experimentalCompactHashCheckEnabled to true from experimental flag", - experimentalCompactHashCheckEnabled: "true", - expectedFeatures: map[featuregate.Feature]bool{ - features.CompactHashCheck: true, - features.TxnModeWriteWithSharedBuffer: true, - }, - }, - { - name: "can set feature gate experimentalCompactHashCheckEnabled to false from experimental flag", - experimentalCompactHashCheckEnabled: "false", - expectedFeatures: map[featuregate.Feature]bool{ - features.CompactHashCheck: false, - features.TxnModeWriteWithSharedBuffer: true, - }, - }, { name: "can set feature gate CompactHashCheck to true from feature gate flag", serverFeatureGatesJSON: "CompactHashCheck=true", @@ -274,17 +157,6 @@ func TestConfigFileFeatureGates(t *testing.T) { features.TxnModeWriteWithSharedBuffer: true, }, }, - { - name: "can set feature gate experimentalEnableLeaseCheckpoint and experimentalEnableLeaseCheckpointPersist to true from experimental flag", - experimentalEnableLeaseCheckpoint: "true", - experimentalEnableLeaseCheckpointPersist: "true", - expectedFeatures: map[featuregate.Feature]bool{ - features.CompactHashCheck: false, - features.TxnModeWriteWithSharedBuffer: true, - features.LeaseCheckpoint: true, - features.LeaseCheckpointPersist: true, - }, - }, { name: "can set feature gate LeaseCheckpoint and LeaseCheckpointPersist to true from feature gate flag", serverFeatureGatesJSON: "LeaseCheckpointPersist=true,LeaseCheckpoint=true", @@ -294,75 +166,15 @@ func TestConfigFileFeatureGates(t *testing.T) { features.LeaseCheckpointPersist: true, }, }, - { - name: "cannot set feature gate experimentalEnableLeaseCheckpoint=false and experimentalEnableLeaseCheckpointPersist=true", - experimentalEnableLeaseCheckpoint: "false", - experimentalEnableLeaseCheckpointPersist: "true", - expectErr: true, - }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { yc := struct { - ExperimentalStopGRPCServiceOnDefrag *bool `json:"experimental-stop-grpc-service-on-defrag,omitempty"` - ExperimentalInitialCorruptCheck *bool `json:"experimental-initial-corrupt-check,omitempty"` - ExperimentalCompactHashCheckEnabled *bool `json:"experimental-compact-hash-check-enabled,omitempty"` - ExperimentalTxnModeWriteWithSharedBuffer *bool `json:"experimental-txn-mode-write-with-shared-buffer,omitempty"` - ExperimentalEnableLeaseCheckpoint *bool `json:"experimental-enable-lease-checkpoint,omitempty"` - ExperimentalEnableLeaseCheckpointPersist *bool `json:"experimental-enable-lease-checkpoint-persist,omitempty"` - ServerFeatureGatesJSON string `json:"feature-gates"` + ServerFeatureGatesJSON string `json:"feature-gates"` }{ ServerFeatureGatesJSON: tc.serverFeatureGatesJSON, } - if tc.experimentalInitialCorruptCheck != "" { - experimentalInitialCorruptCheck, err := strconv.ParseBool(tc.experimentalInitialCorruptCheck) - if err != nil { - t.Fatal(err) - } - yc.ExperimentalInitialCorruptCheck = &experimentalInitialCorruptCheck - } - - if tc.experimentalTxnModeWriteWithSharedBuffer != "" { - experimentalTxnModeWriteWithSharedBuffer, err := strconv.ParseBool(tc.experimentalTxnModeWriteWithSharedBuffer) - if err != nil { - t.Fatal(err) - } - yc.ExperimentalTxnModeWriteWithSharedBuffer = &experimentalTxnModeWriteWithSharedBuffer - } - - if tc.experimentalStopGRPCServiceOnDefrag != "" { - experimentalStopGRPCServiceOnDefrag, err := strconv.ParseBool(tc.experimentalStopGRPCServiceOnDefrag) - if err != nil { - t.Fatal(err) - } - yc.ExperimentalStopGRPCServiceOnDefrag = &experimentalStopGRPCServiceOnDefrag - } - - if tc.experimentalCompactHashCheckEnabled != "" { - experimentalCompactHashCheckEnabled, err := strconv.ParseBool(tc.experimentalCompactHashCheckEnabled) - if err != nil { - t.Fatal(err) - } - yc.ExperimentalCompactHashCheckEnabled = &experimentalCompactHashCheckEnabled - } - - if tc.experimentalEnableLeaseCheckpoint != "" { - experimentalEnableLeaseCheckpoint, err := strconv.ParseBool(tc.experimentalEnableLeaseCheckpoint) - if err != nil { - t.Fatal(err) - } - yc.ExperimentalEnableLeaseCheckpoint = &experimentalEnableLeaseCheckpoint - } - - if tc.experimentalEnableLeaseCheckpointPersist != "" { - experimentalEnableLeaseCheckpointPersist, err := strconv.ParseBool(tc.experimentalEnableLeaseCheckpointPersist) - if err != nil { - t.Fatal(err) - } - yc.ExperimentalEnableLeaseCheckpointPersist = &experimentalEnableLeaseCheckpointPersist - } - b, err := yaml.Marshal(&yc) if err != nil { t.Fatal(err) @@ -444,111 +256,111 @@ func TestInferLocalAddr(t *testing.T) { expectedLocalAddr string }{ { - "defaults, ExperimentalSetMemberLocalAddr=false ", + "defaults, SetMemberLocalAddr=false ", []string{DefaultInitialAdvertisePeerURLs}, "SetMemberLocalAddr=false", "", }, { - "IPv4 address, ExperimentalSetMemberLocalAddr=false ", + "IPv4 address, SetMemberLocalAddr=false ", []string{"https://192.168.100.110:2380"}, "SetMemberLocalAddr=false", "", }, { - "defaults, ExperimentalSetMemberLocalAddr=true", + "defaults, SetMemberLocalAddr=true", []string{DefaultInitialAdvertisePeerURLs}, "SetMemberLocalAddr=true", "", }, { - "IPv4 unspecified address, ExperimentalSetMemberLocalAddr=true", + "IPv4 unspecified address, SetMemberLocalAddr=true", []string{"https://0.0.0.0:2380"}, "SetMemberLocalAddr=true", "", }, { - "IPv6 unspecified address, ExperimentalSetMemberLocalAddr=true", + "IPv6 unspecified address, SetMemberLocalAddr=true", []string{"https://[::]:2380"}, "SetMemberLocalAddr=true", "", }, { - "IPv4 loopback address, ExperimentalSetMemberLocalAddr=true", + "IPv4 loopback address, SetMemberLocalAddr=true", []string{"https://127.0.0.1:2380"}, "SetMemberLocalAddr=true", "", }, { - "IPv6 loopback address, ExperimentalSetMemberLocalAddr=true", + "IPv6 loopback address, SetMemberLocalAddr=true", []string{"https://[::1]:2380"}, "SetMemberLocalAddr=true", "", }, { - "IPv4 address, ExperimentalSetMemberLocalAddr=true", + "IPv4 address, SetMemberLocalAddr=true", []string{"https://192.168.100.110:2380"}, "SetMemberLocalAddr=true", "192.168.100.110", }, { - "Hostname only, ExperimentalSetMemberLocalAddr=true", + "Hostname only, SetMemberLocalAddr=true", []string{"https://123-host-3.corp.internal:2380"}, "SetMemberLocalAddr=true", "", }, { - "Hostname and IPv4 address, ExperimentalSetMemberLocalAddr=true", + "Hostname and IPv4 address, SetMemberLocalAddr=true", []string{"https://123-host-3.corp.internal:2380", "https://192.168.100.110:2380"}, "SetMemberLocalAddr=true", "192.168.100.110", }, { - "IPv4 address and Hostname, ExperimentalSetMemberLocalAddr=true", + "IPv4 address and Hostname, SetMemberLocalAddr=true", []string{"https://192.168.100.110:2380", "https://123-host-3.corp.internal:2380"}, "SetMemberLocalAddr=true", "192.168.100.110", }, { - "IPv4 and IPv6 addresses, ExperimentalSetMemberLocalAddr=true", + "IPv4 and IPv6 addresses, SetMemberLocalAddr=true", []string{"https://192.168.100.110:2380", "https://[2001:db8:85a3::8a2e:370:7334]:2380"}, "SetMemberLocalAddr=true", "192.168.100.110", }, { - "IPv6 and IPv4 addresses, ExperimentalSetMemberLocalAddr=true", + "IPv6 and IPv4 addresses, SetMemberLocalAddr=true", // IPv4 addresses will always sort before IPv6 ones anyway []string{"https://[2001:db8:85a3::8a2e:370:7334]:2380", "https://192.168.100.110:2380"}, "SetMemberLocalAddr=true", "192.168.100.110", }, { - "Hostname, IPv4 and IPv6 addresses, ExperimentalSetMemberLocalAddr=true", + "Hostname, IPv4 and IPv6 addresses, SetMemberLocalAddr=true", []string{"https://123-host-3.corp.internal:2380", "https://192.168.100.110:2380", "https://[2001:db8:85a3::8a2e:370:7334]:2380"}, "SetMemberLocalAddr=true", "192.168.100.110", }, { - "Hostname, IPv6 and IPv4 addresses, ExperimentalSetMemberLocalAddr=true", + "Hostname, IPv6 and IPv4 addresses, SetMemberLocalAddr=true", // IPv4 addresses will always sort before IPv6 ones anyway []string{"https://123-host-3.corp.internal:2380", "https://[2001:db8:85a3::8a2e:370:7334]:2380", "https://192.168.100.110:2380"}, "SetMemberLocalAddr=true", "192.168.100.110", }, { - "IPv6 address, ExperimentalSetMemberLocalAddr=true", + "IPv6 address, SetMemberLocalAddr=true", []string{"https://[2001:db8:85a3::8a2e:370:7334]:2380"}, "SetMemberLocalAddr=true", "2001:db8:85a3::8a2e:370:7334", }, { - "Hostname and IPv6 address, ExperimentalSetMemberLocalAddr=true", + "Hostname and IPv6 address, SetMemberLocalAddr=true", []string{"https://123-host-3.corp.internal:2380", "https://[2001:db8:85a3::8a2e:370:7334]:2380"}, "SetMemberLocalAddr=true", "2001:db8:85a3::8a2e:370:7334", }, { - "IPv6 address and Hostname, ExperimentalSetMemberLocalAddr=true", + "IPv6 address and Hostname, SetMemberLocalAddr=true", []string{"https://[2001:db8:85a3::8a2e:370:7334]:2380", "https://123-host-3.corp.internal:2380"}, "SetMemberLocalAddr=true", "2001:db8:85a3::8a2e:370:7334", @@ -960,104 +772,6 @@ func TestUndefinedAutoCompactionModeValidate(t *testing.T) { require.Error(t, err) } -func TestSetFeatureGatesFromExperimentalFlags(t *testing.T) { - testCases := []struct { - name string - featureGatesFlag string - experimentalStopGRPCServiceOnDefrag string - expectErr bool - expectedFeatures map[featuregate.Feature]bool - }{ - { - name: "default", - expectedFeatures: map[featuregate.Feature]bool{ - features.StopGRPCServiceOnDefrag: false, - "TestAlpha": false, - "TestBeta": true, - }, - }, - { - name: "cannot set experimental flag and feature gate to true at the same time", - featureGatesFlag: "StopGRPCServiceOnDefrag=true", - experimentalStopGRPCServiceOnDefrag: "true", - expectErr: true, - }, - { - name: "cannot set experimental flag and feature gate to false at the same time", - featureGatesFlag: "StopGRPCServiceOnDefrag=false", - experimentalStopGRPCServiceOnDefrag: "false", - expectErr: true, - }, - { - name: "cannot set experimental flag and feature gate to different values at the same time", - featureGatesFlag: "StopGRPCServiceOnDefrag=true", - experimentalStopGRPCServiceOnDefrag: "false", - expectErr: true, - }, - { - name: "can set experimental flag and other feature gates", - featureGatesFlag: "TestAlpha=true,TestBeta=false", - experimentalStopGRPCServiceOnDefrag: "true", - expectedFeatures: map[featuregate.Feature]bool{ - features.StopGRPCServiceOnDefrag: true, - "TestAlpha": true, - "TestBeta": false, - }, - }, - { - name: "can set feature gate when its experimental flag is not explicitly set", - featureGatesFlag: "TestAlpha=true,StopGRPCServiceOnDefrag=true", - expectedFeatures: map[featuregate.Feature]bool{ - features.StopGRPCServiceOnDefrag: true, - "TestAlpha": true, - "TestBeta": true, - }, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - fg := features.NewDefaultServerFeatureGate("test", nil) - err := fg.(featuregate.MutableFeatureGate).Add( - map[featuregate.Feature]featuregate.FeatureSpec{ - "TestAlpha": {Default: false, PreRelease: featuregate.Alpha}, - "TestBeta": {Default: true, PreRelease: featuregate.Beta}, - }) - require.NoError(t, err) - - fg.(featuregate.MutableFeatureGate).Set(tc.featureGatesFlag) - var getExperimentalFlagVal func(flagName string) *bool - if tc.experimentalStopGRPCServiceOnDefrag == "" { - // experimental flag is not explicitly set - getExperimentalFlagVal = func(flagName string) *bool { - return nil - } - } else { - // mexperimental flag is explicitly set - getExperimentalFlagVal = func(flagName string) *bool { - // only the experimental-stop-grpc-service-on-defrag flag can be set in this test. - if flagName != "experimental-stop-grpc-service-on-defrag" { - return nil - } - flagVal, parseErr := strconv.ParseBool(tc.experimentalStopGRPCServiceOnDefrag) - require.NoError(t, parseErr) - return &flagVal - } - } - err = SetFeatureGatesFromExperimentalFlags(fg, getExperimentalFlagVal, tc.featureGatesFlag) - if tc.expectErr { - require.Error(t, err) - return - } - require.NoError(t, err) - for k, v := range tc.expectedFeatures { - if fg.Enabled(k) != v { - t.Errorf("expected feature gate %s=%v, got %v", k, v, fg.Enabled(k)) - } - } - }) - } -} - func TestMatchNewConfigAddFlags(t *testing.T) { cfg := NewConfig() fs := flag.NewFlagSet("etcd", flag.ContinueOnError) diff --git a/server/embed/etcd.go b/server/embed/etcd.go index 95c0d6d92f97..6a5b2f1c356d 100644 --- a/server/embed/etcd.go +++ b/server/embed/etcd.go @@ -234,7 +234,7 @@ func StartEtcd(inCfg *Config) (e *Etcd, err error) { BootstrapDefragThresholdMegabytes: cfg.BootstrapDefragThresholdMegabytes, MaxLearners: cfg.MaxLearners, V2Deprecation: cfg.V2DeprecationEffective(), - ExperimentalLocalAddress: cfg.InferLocalAddr(), + LocalAddress: cfg.InferLocalAddr(), ServerFeatureGate: cfg.ServerFeatureGate, Metrics: cfg.Metrics, } @@ -255,7 +255,7 @@ func StartEtcd(inCfg *Config) (e *Etcd, err error) { ) } - srvcfg.PeerTLSInfo.LocalAddr = srvcfg.ExperimentalLocalAddress + srvcfg.PeerTLSInfo.LocalAddr = srvcfg.LocalAddress print(e.cfg.logger, *cfg, srvcfg, memberInitialized) @@ -348,7 +348,7 @@ func print(lg *zap.Logger, ec Config, sc config.ServerConfig, memberInitialized zap.Strings("advertise-client-urls", ec.getAdvertiseClientURLs()), zap.Strings("listen-client-urls", ec.getListenClientURLs()), zap.Strings("listen-metrics-urls", ec.getMetricsURLs()), - zap.String("experimental-local-address", sc.ExperimentalLocalAddress), + zap.String("local-address", sc.LocalAddress), zap.Strings("cors", cors), zap.Strings("host-whitelist", hss), zap.String("initial-cluster", sc.InitialPeerURLsMap.String()), diff --git a/server/etcdmain/config.go b/server/etcdmain/config.go index 9fed0bbf049c..9968cae3499e 100644 --- a/server/etcdmain/config.go +++ b/server/etcdmain/config.go @@ -62,23 +62,6 @@ var ( "snapshot-count": "--snapshot-count is deprecated in 3.6 and will be decommissioned in 3.7.", "max-snapshots": "--max-snapshots is deprecated in 3.6 and will be decommissioned in 3.7.", "v2-deprecation": "--v2-deprecation is deprecated and scheduled for removal in v3.8. The default value is enforced, ignoring user input.", - "experimental-compact-hash-check-enabled": "--experimental-compact-hash-check-enabled is deprecated in 3.6 and will be decommissioned in 3.7. Use '--feature-gates=CompactHashCheck=true' instead.", - "experimental-compact-hash-check-time": "--experimental-compact-hash-check-time is deprecated in 3.6 and will be decommissioned in 3.7. Use '--compact-hash-check-time' instead.", - "experimental-txn-mode-write-with-shared-buffer": "--experimental-txn-mode-write-with-shared-buffer is deprecated in v3.6 and will be decommissioned in v3.7. Use '--feature-gates=TxnModeWriteWithSharedBuffer=true' instead.", - "experimental-corrupt-check-time": "--experimental-corrupt-check-time is deprecated in v3.6 and will be decommissioned in v3.7. Use '--corrupt-check-time' instead.", - "experimental-compaction-batch-limit": "--experimental-compaction-batch-limit is deprecated in v3.6 and will be decommissioned in v3.7. Use '--compaction-batch-limit' instead.", - "experimental-watch-progress-notify-interval": "--experimental-watch-progress-notify-interval is deprecated in v3.6 and will be decommissioned in v3.7. Use '--watch-progress-notify-interval' instead.", - "experimental-warning-apply-duration": "--experimental-warning-apply-duration is deprecated in v3.6 and will be decommissioned in v3.7. Use '--warning-apply-duration' instead.", - "experimental-bootstrap-defrag-threshold-megabytes": "--experimental-bootstrap-defrag-threshold-megabytes is deprecated in v3.6 and will be decommissioned in v3.7. Use '--bootstrap-defrag-threshold-megabytes' instead.", - "experimental-memory-mlock": "--experimental-memory-mlock is deprecated in v3.6 and will be decommissioned in v3.7. Use '--memory-mlock' instead.", - "experimental-snapshot-catchup-entries": "--experimental-snapshot-catchup-entries is deprecated in v3.6 and will be decommissioned in v3.7. Use '--snapshot-catchup-entries' instead.", - "experimental-compaction-sleep-interval": "--experimental-compaction-sleep-interval is deprecated in v3.6 and will be decommissioned in v3.7. Use 'compaction-sleep-interval' instead.", - "experimental-downgrade-check-time": "--experimental-downgrade-check-time is deprecated in v3.6 and will be decommissioned in v3.7. Use '--downgrade-check-time' instead.", - "experimental-enable-distributed-tracing": "--experimental-enable-distributed-tracing is deprecated in 3.6 and will be decommissioned in 3.7. Use --enable-distributed-tracing instead.", - "experimental-distributed-tracing-address": "--experimental-distributed-tracing-address is deprecated in 3.6 and will be decommissioned in 3.7. Use --distributed-tracing-address instead.", - "experimental-distributed-tracing-service-name": "--experimental-distributed-tracing-service-name is deprecated in 3.6 and will be decommissioned in 3.7. Use --distributed-tracing-service-name instead.", - "experimental-distributed-tracing-instance-id": "--experimental-distributed-tracing-instance-id is deprecated in 3.6 and will be decommissioned in 3.7. Use --distributed-tracing-instance-id instead.", - "experimental-distributed-tracing-sampling-rate": "--experimental-distributed-tracing-sampling-rate is deprecated in 3.6 and will be decommissioned in 3.7. Use --distributed-tracing-sampling-rate instead.", } ) @@ -182,78 +165,10 @@ func (cfg *config) parse(arguments []string) error { err = cfg.configFromCmdLine() } - // params related to experimental flag deprecation - // TODO: delete in v3.7 - if cfg.ec.FlagsExplicitlySet["experimental-compact-hash-check-time"] { - cfg.ec.CompactHashCheckTime = cfg.ec.ExperimentalCompactHashCheckTime - } - - if cfg.ec.FlagsExplicitlySet["experimental-corrupt-check-time"] { - cfg.ec.CorruptCheckTime = cfg.ec.ExperimentalCorruptCheckTime - } - - if cfg.ec.FlagsExplicitlySet["experimental-compaction-batch-limit"] { - cfg.ec.CompactionBatchLimit = cfg.ec.ExperimentalCompactionBatchLimit - } - - if cfg.ec.FlagsExplicitlySet["experimental-watch-progress-notify-interval"] { - cfg.ec.WatchProgressNotifyInterval = cfg.ec.ExperimentalWatchProgressNotifyInterval - } - - if cfg.ec.FlagsExplicitlySet["experimental-warning-apply-duration"] { - cfg.ec.WarningApplyDuration = cfg.ec.ExperimentalWarningApplyDuration - } - - if cfg.ec.FlagsExplicitlySet["experimental-bootstrap-defrag-threshold-megabytes"] { - cfg.ec.BootstrapDefragThresholdMegabytes = cfg.ec.ExperimentalBootstrapDefragThresholdMegabytes - } - if cfg.ec.FlagsExplicitlySet["experimental-peer-skip-client-san-verification"] { - cfg.ec.PeerTLSInfo.SkipClientSANVerify = cfg.ec.ExperimentalPeerSkipClientSanVerification - } - - if cfg.ec.FlagsExplicitlySet["experimental-memory-mlock"] { - cfg.ec.MemoryMlock = cfg.ec.ExperimentalMemoryMlock - } - - if cfg.ec.FlagsExplicitlySet["experimental-snapshot-catchup-entries"] { - cfg.ec.SnapshotCatchUpEntries = cfg.ec.ExperimentalSnapshotCatchUpEntries - } - - if cfg.ec.FlagsExplicitlySet["experimental-compaction-sleep-interval"] { - cfg.ec.CompactionSleepInterval = cfg.ec.ExperimentalCompactionSleepInterval - } - - if cfg.ec.FlagsExplicitlySet["experimental-downgrade-check-time"] { - cfg.ec.DowngradeCheckTime = cfg.ec.ExperimentalDowngradeCheckTime - } - - if cfg.ec.FlagsExplicitlySet["experimental-enable-distributed-tracing"] { - cfg.ec.EnableDistributedTracing = cfg.ec.ExperimentalEnableDistributedTracing - } - - if cfg.ec.FlagsExplicitlySet["experimental-distributed-tracing-address"] { - cfg.ec.DistributedTracingAddress = cfg.ec.ExperimentalDistributedTracingAddress - } - - if cfg.ec.FlagsExplicitlySet["experimental-distributed-tracing-service-name"] { - cfg.ec.DistributedTracingServiceName = cfg.ec.ExperimentalDistributedTracingServiceName - } - - if cfg.ec.FlagsExplicitlySet["experimental-distributed-tracing-instance-id"] { - cfg.ec.DistributedTracingServiceInstanceID = cfg.ec.ExperimentalDistributedTracingServiceInstanceID - } - - if cfg.ec.FlagsExplicitlySet["experimental-distributed-tracing-sampling-rate"] { - cfg.ec.DistributedTracingSamplingRatePerMillion = cfg.ec.ExperimentalDistributedTracingSamplingRatePerMillion - } - // `V2Deprecation` (--v2-deprecation) is deprecated and scheduled for removal in v3.8. The default value is enforced, ignoring user input. cfg.ec.V2Deprecation = cconfig.V2DeprDefault - cfg.ec.WarningUnaryRequestDuration, perr = cfg.parseWarningUnaryRequestDuration() - if perr != nil { - return perr - } + cfg.ec.WarningUnaryRequestDuration = cfg.parseWarningUnaryRequestDuration() // Check for deprecated options from both command line and config file var warningsForDeprecatedOpts []string @@ -348,21 +263,6 @@ func (cfg *config) configFromCmdLine() error { cfg.ec.FlagsExplicitlySet[f.Name] = true }) - getBoolFlagVal := func(flagName string) *bool { - boolVal, parseErr := flags.GetBoolFlagVal(cfg.cf.flagSet, flagName) - if parseErr != nil { - panic(parseErr) - } - return boolVal - } - - // SetFeatureGatesFromExperimentalFlags validates that cmd line flags for experimental feature and their feature gates are not explicitly set simultaneously, - // and passes the values of cmd line flags for experimental feature to the server feature gate. - err = embed.SetFeatureGatesFromExperimentalFlags(cfg.ec.ServerFeatureGate, getBoolFlagVal, cfg.cf.flagSet.Lookup(embed.ServerFeatureGateFlagName).Value.String()) - if err != nil { - return err - } - return cfg.validate() } @@ -383,23 +283,10 @@ func (cfg *config) validate() error { return cfg.ec.Validate() } -func (cfg *config) parseWarningUnaryRequestDuration() (time.Duration, error) { - if cfg.ec.ExperimentalWarningUnaryRequestDuration != 0 && cfg.ec.WarningUnaryRequestDuration != 0 { - return 0, errors.New( - "both --experimental-warning-unary-request-duration and --warning-unary-request-duration flags are set. " + - "Use only --warning-unary-request-duration") - } - +func (cfg *config) parseWarningUnaryRequestDuration() time.Duration { if cfg.ec.WarningUnaryRequestDuration != 0 { - return cfg.ec.WarningUnaryRequestDuration, nil - } - - if cfg.ec.ExperimentalWarningUnaryRequestDuration != 0 { - cfg.ec.GetLogger().Warn( - "--experimental-warning-unary-request-duration is deprecated, and will be decommissioned in v3.7. " + - "Use --warning-unary-request-duration instead.") - return cfg.ec.ExperimentalWarningUnaryRequestDuration, nil + return cfg.ec.WarningUnaryRequestDuration } - return embed.DefaultWarningUnaryRequestDuration, nil + return embed.DefaultWarningUnaryRequestDuration } diff --git a/server/etcdmain/config_test.go b/server/etcdmain/config_test.go index 56e300bdfb85..643e89715568 100644 --- a/server/etcdmain/config_test.go +++ b/server/etcdmain/config_test.go @@ -21,10 +21,8 @@ import ( "net/url" "os" "reflect" - "strconv" "strings" "testing" - "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -33,7 +31,6 @@ import ( "go.etcd.io/etcd/pkg/v3/featuregate" "go.etcd.io/etcd/pkg/v3/flags" "go.etcd.io/etcd/server/v3/embed" - "go.etcd.io/etcd/server/v3/etcdserver" "go.etcd.io/etcd/server/v3/features" ) @@ -44,7 +41,7 @@ func TestConfigParsingMemberFlags(t *testing.T) { "-max-wals=10", "-max-snapshots=10", "-snapshot-count=10", - "-experimental-snapshot-catchup-entries=1000", + "-snapshot-catchup-entries=1000", "-listen-peer-urls=http://localhost:8000,https://localhost:8001", "-listen-client-urls=http://localhost:7000,https://localhost:7001", "-listen-client-http-urls=http://localhost:7002,https://localhost:7003", @@ -322,73 +319,6 @@ func TestConfigParsingMissedAdvertiseClientURLsFlag(t *testing.T) { } } -// TestExperimentalSnapshotCatchUpEntriesFlagMigration tests the migration from -// --experimental-snapshot-catch-up-entries to --snapshot-catch-up-entries -func TestExperimentalSnapshotCatchUpEntriesFlagMigration(t *testing.T) { - testCases := []struct { - name string - snapshotCatchUpEntries uint64 - experimentalSnapshotCatchUpEntries uint64 - wantErr bool - wantConfig uint64 - }{ - { - name: "default", - wantConfig: etcdserver.DefaultSnapshotCatchUpEntries, - }, - { - name: "cannot set both experimental flag and non experimental flag", - experimentalSnapshotCatchUpEntries: 1000, - snapshotCatchUpEntries: 2000, - wantErr: true, - }, - { - name: "can set experimental flag", - experimentalSnapshotCatchUpEntries: 1000, - wantConfig: 1000, - }, - { - name: "can set non-experimental flag", - snapshotCatchUpEntries: 2000, - wantConfig: 2000, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cmdLineArgs := []string{} - yc := struct { - ExperimentalSnapshotCatchUpEntries uint64 `json:"experimental-snapshot-catch-up-entries,omitempty"` - SnapshotCatchUpEntries uint64 `json:"snapshot-catchup-entries,omitempty"` - }{} - - if tc.snapshotCatchUpEntries > 0 { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--snapshot-catchup-entries=%d", tc.snapshotCatchUpEntries)) - yc.SnapshotCatchUpEntries = tc.snapshotCatchUpEntries - } - - if tc.experimentalSnapshotCatchUpEntries > 0 { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-snapshot-catchup-entries=%d", tc.experimentalSnapshotCatchUpEntries)) - yc.ExperimentalSnapshotCatchUpEntries = tc.experimentalSnapshotCatchUpEntries - } - - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.wantErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatal("expect parse error") - } - return - } - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - - require.Equal(t, tc.wantConfig, cfgFromCmdLine.ec.SnapshotCatchUpEntries) - require.Equal(t, tc.wantConfig, cfgFromFile.ec.SnapshotCatchUpEntries) - }) - } -} - func TestConfigIsNewCluster(t *testing.T) { tests := []struct { state string @@ -482,35 +412,6 @@ func TestParseFeatureGateFlags(t *testing.T) { features.StopGRPCServiceOnDefrag: false, }, }, - { - name: "cannot set both experimental flag and feature gate flag", - args: []string{ - "--experimental-stop-grpc-service-on-defrag=false", - "--feature-gates=StopGRPCServiceOnDefrag=true", - }, - expectErr: true, - }, - { - name: "ok to set different experimental flag and feature gate flag", - args: []string{ - "--experimental-stop-grpc-service-on-defrag=true", - "--feature-gates=InitialCorruptCheck=true", - }, - expectedFeatures: map[featuregate.Feature]bool{ - features.StopGRPCServiceOnDefrag: true, - features.InitialCorruptCheck: true, - }, - }, - { - name: "can set feature gate from experimental flag", - args: []string{ - "--experimental-stop-grpc-service-on-defrag=true", - }, - expectedFeatures: map[featuregate.Feature]bool{ - features.StopGRPCServiceOnDefrag: true, - features.InitialCorruptCheck: false, - }, - }, { name: "can set feature gate from feature gate flag", args: []string{ @@ -543,641 +444,6 @@ func TestParseFeatureGateFlags(t *testing.T) { } } -// TestDowngradeCheckTimeFlagMigration tests the migration from -// --experimental-downgrade-check-time to --downgrade-check-time -func TestDowngradeCheckTimeFlagMigration(t *testing.T) { - testCases := []struct { - name string - downgradeCheckTime string - experimentalDowngradeCheckTime string - wantErr bool - wantConfig time.Duration - }{ - { - name: "default", - wantConfig: embed.DefaultDowngradeCheckTime, - }, - { - name: "cannot set both experimental flag and non experimental flag", - experimentalDowngradeCheckTime: "1m", - downgradeCheckTime: "2m", - wantErr: true, - }, - { - name: "can set experimental flag", - experimentalDowngradeCheckTime: "1m", - wantConfig: time.Minute, - }, - { - name: "can set non-experimental flag", - downgradeCheckTime: "2m", - wantConfig: 2 * time.Minute, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cmdLineArgs := []string{} - yc := struct { - ExperimentalDowngradeCheckTime time.Duration `json:"experimental-downgrade-check-time,omitempty"` - DowngradeCheckTime time.Duration `json:"downgrade-check-time,omitempty"` - }{} - - if tc.downgradeCheckTime != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--downgrade-check-time=%s", tc.downgradeCheckTime)) - downgradeCheckTime, err := time.ParseDuration(tc.downgradeCheckTime) - require.NoError(t, err) - yc.DowngradeCheckTime = downgradeCheckTime - } - - if tc.experimentalDowngradeCheckTime != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-downgrade-check-time=%s", tc.experimentalDowngradeCheckTime)) - experimentalDowngradeCheckTime, err := time.ParseDuration(tc.experimentalDowngradeCheckTime) - require.NoError(t, err) - yc.ExperimentalDowngradeCheckTime = experimentalDowngradeCheckTime - } - - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.wantErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatal("expect parse error") - } - return - } - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - - require.Equal(t, tc.wantConfig, cfgFromCmdLine.ec.DowngradeCheckTime) - require.Equal(t, tc.wantConfig, cfgFromFile.ec.DowngradeCheckTime) - }) - } -} - -// TestCompactHashCheckTimeFlagMigration tests the migration from -// --experimental-compact-hash-check-time to --compact-hash-check-time -// TODO: delete in v3.7 -func TestCompactHashCheckTimeFlagMigration(t *testing.T) { - testCases := []struct { - name string - compactHashCheckTime string - experimentalCompactHashCheckTime string - expectErr bool - expectedCompactHashCheckTime time.Duration - }{ - { - name: "default", - expectedCompactHashCheckTime: time.Minute, - }, - { - name: "cannot set both experimental flag and non experimental flag", - compactHashCheckTime: "2m", - experimentalCompactHashCheckTime: "3m", - expectErr: true, - }, - { - name: "can set experimental flag", - experimentalCompactHashCheckTime: "3m", - expectedCompactHashCheckTime: 3 * time.Minute, - }, - { - name: "can set non experimental flag", - compactHashCheckTime: "2m", - expectedCompactHashCheckTime: 2 * time.Minute, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cmdLineArgs := []string{} - yc := struct { - ExperimentalCompactHashCheckTime time.Duration `json:"experimental-compact-hash-check-time,omitempty"` - CompactHashCheckTime time.Duration `json:"compact-hash-check-time,omitempty"` - }{} - - if tc.compactHashCheckTime != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--compact-hash-check-time=%s", tc.compactHashCheckTime)) - compactHashCheckTime, err := time.ParseDuration(tc.compactHashCheckTime) - require.NoError(t, err) - yc.CompactHashCheckTime = compactHashCheckTime - } - - if tc.experimentalCompactHashCheckTime != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-compact-hash-check-time=%s", tc.experimentalCompactHashCheckTime)) - experimentalCompactHashCheckTime, err := time.ParseDuration(tc.experimentalCompactHashCheckTime) - require.NoError(t, err) - yc.ExperimentalCompactHashCheckTime = experimentalCompactHashCheckTime - } - - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.expectErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatal("expect parse error") - } - return - } - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - - require.Equal(t, tc.expectedCompactHashCheckTime, cfgFromCmdLine.ec.CompactHashCheckTime) - require.Equal(t, tc.expectedCompactHashCheckTime, cfgFromFile.ec.CompactHashCheckTime) - }) - } -} - -// TestCompactionSleepIntervalFlagMigration tests the migration from -// --experimental-compaction-sleep-interval to --compaction-sleep-interval -func TestCompactionSleepIntervalFlagMigration(t *testing.T) { - testCases := []struct { - name string - compactionSleepInterval string - experimentalCompactionSleepInterval string - wantErr bool - wantConfig time.Duration - }{ - { - name: "default", - wantConfig: time.Duration(0), - }, - { - name: "cannot set both experimental flag and non experimental flag", - experimentalCompactionSleepInterval: "30s", - compactionSleepInterval: "15s", - wantErr: true, - }, - { - name: "can set experimental flag", - experimentalCompactionSleepInterval: "30s", - wantConfig: 30 * time.Second, - }, - { - name: "can set non-experimental flag", - compactionSleepInterval: "1m", - wantConfig: time.Minute, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cmdLineArgs := []string{} - yc := struct { - ExperimentalCompactionSleepInterval time.Duration `json:"experimental-compaction-sleep-interval,omitempty"` - CompactionSleepInterval time.Duration `json:"compaction-sleep-interval,omitempty"` - }{} - - if tc.compactionSleepInterval != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--compaction-sleep-interval=%s", tc.compactionSleepInterval)) - compactionSleepInterval, err := time.ParseDuration(tc.compactionSleepInterval) - require.NoError(t, err) - yc.CompactionSleepInterval = compactionSleepInterval - } - - if tc.experimentalCompactionSleepInterval != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-compaction-sleep-interval=%s", tc.experimentalCompactionSleepInterval)) - experimentalCompactionSleepInterval, err := time.ParseDuration(tc.experimentalCompactionSleepInterval) - require.NoError(t, err) - yc.ExperimentalCompactionSleepInterval = experimentalCompactionSleepInterval - } - - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.wantErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatal("expect parse error") - } - return - } - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - - require.Equal(t, tc.wantConfig, cfgFromCmdLine.ec.CompactionSleepInterval) - require.Equal(t, tc.wantConfig, cfgFromFile.ec.CompactionSleepInterval) - }) - } -} - -// TestCorruptCheckTimeFlagMigration tests the migration from -// --experimental-corrupt-check-time to --corrupt-check-time -// TODO: delete in v3.7 -func TestCorruptCheckTimeFlagMigration(t *testing.T) { - testCases := []struct { - name string - corruptCheckTime string - experimentalCorruptCheckTime string - expectErr bool - expectedCorruptCheckTime time.Duration - }{ - { - name: "cannot set both experimental flag and non experimental flag", - corruptCheckTime: "2m", - experimentalCorruptCheckTime: "3m", - expectErr: true, - }, - { - name: "can set experimental flag", - experimentalCorruptCheckTime: "3m", - expectedCorruptCheckTime: 3 * time.Minute, - }, - { - name: "can set non experimental flag", - corruptCheckTime: "2m", - expectedCorruptCheckTime: 2 * time.Minute, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cmdLineArgs := []string{} - yc := struct { - ExperimentalCorruptCheckTime time.Duration `json:"experimental-corrupt-check-time,omitempty"` - CorruptCheckTime time.Duration `json:"corrupt-check-time,omitempty"` - }{} - - if tc.corruptCheckTime != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--corrupt-check-time=%s", tc.corruptCheckTime)) - corruptCheckTime, err := time.ParseDuration(tc.corruptCheckTime) - require.NoError(t, err) - yc.CorruptCheckTime = corruptCheckTime - } - - if tc.experimentalCorruptCheckTime != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-corrupt-check-time=%s", tc.experimentalCorruptCheckTime)) - experimentalCorruptCheckTime, err := time.ParseDuration(tc.experimentalCorruptCheckTime) - require.NoError(t, err) - yc.ExperimentalCorruptCheckTime = experimentalCorruptCheckTime - } - - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.expectErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatal("expect parse error") - } - return - } - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - - require.Equal(t, tc.expectedCorruptCheckTime, cfgFromCmdLine.ec.CorruptCheckTime) - require.Equal(t, tc.expectedCorruptCheckTime, cfgFromFile.ec.CorruptCheckTime) - }) - } -} - -// TestCompactionBatchLimitFlagMigration tests the migration from -// --experimental-compaction-batch-limit to --compaction-batch-limit -// TODO: delete in v3.7 -func TestCompactionBatchLimitFlagMigration(t *testing.T) { - testCases := []struct { - name string - compactionBatchLimit int - experimentalCompactionBatchLimit int - expectErr bool - expectedCompactionBatchLimit int - }{ - { - name: "cannot set both experimental flag and non experimental flag", - compactionBatchLimit: 1, - experimentalCompactionBatchLimit: 2, - expectErr: true, - }, - { - name: "can set experimental flag", - experimentalCompactionBatchLimit: 2, - expectedCompactionBatchLimit: 2, - }, - { - name: "can set non experimental flag", - compactionBatchLimit: 1, - expectedCompactionBatchLimit: 1, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cmdLineArgs := []string{} - yc := struct { - ExperimentalCompactionBatchLimit int `json:"experimental-compaction-batch-limit,omitempty"` - CompactionBatchLimit int `json:"compaction-batch-limit,omitempty"` - }{} - - if tc.compactionBatchLimit != 0 { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--compaction-batch-limit=%d", tc.compactionBatchLimit)) - yc.CompactionBatchLimit = tc.compactionBatchLimit - } - - if tc.experimentalCompactionBatchLimit != 0 { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-compaction-batch-limit=%d", tc.experimentalCompactionBatchLimit)) - yc.ExperimentalCompactionBatchLimit = tc.experimentalCompactionBatchLimit - } - - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.expectErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatal("expect parse error") - } - return - } - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - - require.Equal(t, tc.expectedCompactionBatchLimit, cfgFromCmdLine.ec.CompactionBatchLimit) - require.Equal(t, tc.expectedCompactionBatchLimit, cfgFromFile.ec.CompactionBatchLimit) - }) - } -} - -// TestWatchProgressNotifyInterval tests the migration from -// --experimental-watch-progress-notify-interval to --watch-progress-notify-interval -// TODO: delete in v3.7 -func TestWatchProgressNotifyInterval(t *testing.T) { - testCases := []struct { - name string - watchProgressNotifyInterval string - experimentalWatchProgressNotifyInterval string - expectErr bool - expectedWatchProgressNotifyInterval time.Duration - }{ - { - name: "cannot set both experimental flag and non experimental flag", - watchProgressNotifyInterval: "2m", - experimentalWatchProgressNotifyInterval: "3m", - expectErr: true, - }, - { - name: "can set experimental flag", - experimentalWatchProgressNotifyInterval: "3m", - expectedWatchProgressNotifyInterval: 3 * time.Minute, - }, - { - name: "can set non experimental flag", - watchProgressNotifyInterval: "2m", - expectedWatchProgressNotifyInterval: 2 * time.Minute, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cmdLineArgs := []string{} - yc := struct { - ExperimentalWatchProgressNotifyInterval time.Duration `json:"experimental-watch-progress-notify-interval,omitempty"` - WatchProgressNotifyInterval time.Duration `json:"watch-progress-notify-interval,omitempty"` - }{} - - if tc.watchProgressNotifyInterval != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--watch-progress-notify-interval=%s", tc.watchProgressNotifyInterval)) - watchProgressNotifyInterval, err := time.ParseDuration(tc.watchProgressNotifyInterval) - require.NoError(t, err) - yc.WatchProgressNotifyInterval = watchProgressNotifyInterval - } - - if tc.experimentalWatchProgressNotifyInterval != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-watch-progress-notify-interval=%s", tc.experimentalWatchProgressNotifyInterval)) - experimentalWatchProgressNotifyInterval, err := time.ParseDuration(tc.experimentalWatchProgressNotifyInterval) - require.NoError(t, err) - yc.ExperimentalWatchProgressNotifyInterval = experimentalWatchProgressNotifyInterval - } - - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.expectErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatal("expect parse error") - } - return - } - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - - require.Equal(t, tc.expectedWatchProgressNotifyInterval, cfgFromCmdLine.ec.WatchProgressNotifyInterval) - require.Equal(t, tc.expectedWatchProgressNotifyInterval, cfgFromFile.ec.WatchProgressNotifyInterval) - }) - } -} - -// TestWarningApplyDuration tests the migration from -// --experimental-warning-apply-duration to --warning-apply-duration -// TODO: delete in v3.7 -func TestWarningApplyDuration(t *testing.T) { - testCases := []struct { - name string - warningApplyDuration string - experimentalWarningApplyDuration string - expectErr bool - expectedWarningApplyDuration time.Duration - }{ - { - name: "cannot set both experimental flag and non experimental flag", - warningApplyDuration: "2m", - experimentalWarningApplyDuration: "3m", - expectErr: true, - }, - { - name: "can set experimental flag", - experimentalWarningApplyDuration: "3m", - expectedWarningApplyDuration: 3 * time.Minute, - }, - { - name: "can set non experimental flag", - warningApplyDuration: "2m", - expectedWarningApplyDuration: 2 * time.Minute, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cmdLineArgs := []string{} - yc := struct { - ExperimentalWarningApplyDuration time.Duration `json:"experimental-warning-apply-duration,omitempty"` - WarningApplyDuration time.Duration `json:"warning-apply-duration,omitempty"` - }{} - - if tc.warningApplyDuration != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--warning-apply-duration=%s", tc.warningApplyDuration)) - warningApplyDuration, err := time.ParseDuration(tc.warningApplyDuration) - require.NoError(t, err) - yc.WarningApplyDuration = warningApplyDuration - } - - if tc.experimentalWarningApplyDuration != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-warning-apply-duration=%s", tc.experimentalWarningApplyDuration)) - experimentalWarningApplyDuration, err := time.ParseDuration(tc.experimentalWarningApplyDuration) - require.NoError(t, err) - yc.ExperimentalWarningApplyDuration = experimentalWarningApplyDuration - } - - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.expectErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatal("expect parse error") - } - return - } - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - - require.Equal(t, tc.expectedWarningApplyDuration, cfgFromCmdLine.ec.WarningApplyDuration) - require.Equal(t, tc.expectedWarningApplyDuration, cfgFromFile.ec.WarningApplyDuration) - }) - } -} - -// TestBootstrapDefragThresholdMegabytesFlagMigration tests the migration from -// --experimental-bootstrap-defrag-threshold-megabytes to --bootstrap-defrag-threshold-megabytes -// TODO: delete in v3.7 -func TestBootstrapDefragThresholdMegabytesFlagMigration(t *testing.T) { - testCases := []struct { - name string - bootstrapDefragThresholdMegabytes uint - experimentalBootstrapDefragThresholdMegabytes uint - expectErr bool - expectedBootstrapDefragThresholdMegabytes uint - }{ - { - name: "cannot set both experimental flag and non experimental flag", - bootstrapDefragThresholdMegabytes: 100, - experimentalBootstrapDefragThresholdMegabytes: 200, - expectErr: true, - }, - { - name: "can set experimental flag", - experimentalBootstrapDefragThresholdMegabytes: 200, - expectedBootstrapDefragThresholdMegabytes: 200, - }, - { - name: "can set non experimental flag", - bootstrapDefragThresholdMegabytes: 100, - expectedBootstrapDefragThresholdMegabytes: 100, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cmdLineArgs := []string{} - yc := struct { - ExperimentalBootstrapDefragThresholdMegabytes uint `json:"experimental-bootstrap-defrag-threshold-megabytes,omitempty"` - BootstrapDefragThresholdMegabytes uint `json:"bootstrap-defrag-threshold-megabytes,omitempty"` - }{} - - if tc.bootstrapDefragThresholdMegabytes != 0 { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--bootstrap-defrag-threshold-megabytes=%d", tc.bootstrapDefragThresholdMegabytes)) - yc.BootstrapDefragThresholdMegabytes = tc.bootstrapDefragThresholdMegabytes - } - - if tc.experimentalBootstrapDefragThresholdMegabytes != 0 { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-bootstrap-defrag-threshold-megabytes=%d", tc.experimentalBootstrapDefragThresholdMegabytes)) - yc.ExperimentalBootstrapDefragThresholdMegabytes = tc.experimentalBootstrapDefragThresholdMegabytes - } - - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.expectErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatal("expect parse error") - } - return - } - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - - require.Equal(t, tc.expectedBootstrapDefragThresholdMegabytes, cfgFromCmdLine.ec.BootstrapDefragThresholdMegabytes) - require.Equal(t, tc.expectedBootstrapDefragThresholdMegabytes, cfgFromFile.ec.BootstrapDefragThresholdMegabytes) - }) - } -} - -// TestMemoryMlockFlagMigration tests the migration from -// --experimental-memory-mlock to --memory-mlock -// TODO: delete in v3.7 -func TestMemoryMlockFlagMigration(t *testing.T) { - testCases := []struct { - name string - memoryMlock bool - experimentalMemoryMlock bool - expectedMemoryMlock bool - expectErr bool - }{ - { - name: "default", - expectedMemoryMlock: false, - }, - { - name: "cannot set both experimental flag and non experimental flag", - memoryMlock: true, - experimentalMemoryMlock: true, - expectErr: true, - }, - { - name: "can set experimental flag", - experimentalMemoryMlock: true, - expectedMemoryMlock: true, - }, - { - name: "can set non experimental flag", - memoryMlock: true, - expectedMemoryMlock: true, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cmdLineArgs := []string{} - yc := struct { - MemoryMlock bool `json:"memory-mlock,omitempty"` - ExperimentalMemoryMlock bool `json:"experimental-memory-mlock,omitempty"` - }{} - - if tc.memoryMlock { - cmdLineArgs = append(cmdLineArgs, "--memory-mlock") - yc.MemoryMlock = tc.memoryMlock - } - - if tc.experimentalMemoryMlock { - cmdLineArgs = append(cmdLineArgs, "--experimental-memory-mlock") - yc.ExperimentalMemoryMlock = tc.experimentalMemoryMlock - } - - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.expectErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatal("expect parse error") - } - return - } - - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - - if cfgFromCmdLine.ec.MemoryMlock != tc.expectedMemoryMlock { - t.Errorf("expected MemoryMlock=%v, got %v", tc.expectedMemoryMlock, cfgFromCmdLine.ec.MemoryMlock) - } - if cfgFromFile.ec.MemoryMlock != tc.expectedMemoryMlock { - t.Errorf("expected MemoryMlock=%v, got %v", tc.expectedMemoryMlock, cfgFromFile.ec.MemoryMlock) - } - }) - } -} - -// TODO delete in v3.7 -func generateCfgsFromFileAndCmdLine(t *testing.T, yc any, cmdLineArgs []string) (*config, error, *config, error) { - b, err := yaml.Marshal(&yc) - require.NoError(t, err) - - tmpfile := mustCreateCfgFile(t, b) - defer os.Remove(tmpfile.Name()) - - cfgFromCmdLine := newConfig() - errFromCmdLine := cfgFromCmdLine.parse(cmdLineArgs) - - cfgFromFile := newConfig() - errFromFile := cfgFromFile.parse([]string{fmt.Sprintf("--config-file=%s", tmpfile.Name())}) - return cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile -} - func mustCreateCfgFile(t *testing.T, b []byte) *os.File { tmpfile, err := os.CreateTemp(t.TempDir(), "servercfg") if err != nil { @@ -1266,19 +532,8 @@ func validateClusteringFlags(t *testing.T, cfg *config) { func TestConfigFileDeprecatedOptions(t *testing.T) { // Define a minimal config struct with only the fields we need type configFileYAML struct { - SnapshotCount uint64 `json:"snapshot-count,omitempty"` - MaxSnapFiles uint `json:"max-snapshots,omitempty"` - ExperimentalCompactHashCheckEnabled bool `json:"experimental-compact-hash-check-enabled,omitempty"` - ExperimentalCompactHashCheckTime time.Duration `json:"experimental-compact-hash-check-time,omitempty"` - ExperimentalWarningUnaryRequestDuration time.Duration `json:"experimental-warning-unary-request-duration,omitempty"` - ExperimentalCorruptCheckTime time.Duration `json:"experimental-corrupt-check-time,omitempty"` - ExperimentalCompactionBatchLimit int `json:"experimental-compaction-batch-limit,omitempty"` - ExperimentalWatchProgressNotifyInterval time.Duration `json:"experimental-watch-progress-notify-interval,omitempty"` - ExperimentalWarningApplyDuration time.Duration `json:"experimental-warning-apply-duration,omitempty"` - ExperimentalBootstrapDefragThresholdMegabytes uint `json:"experimental-bootstrap-defrag-threshold-megabytes,omitempty"` - ExperimentalSnapshotCatchUpEntries uint64 `json:"experimental-snapshot-catch-up-entries,omitempty"` - ExperimentalCompactionSleepInterval time.Duration `json:"experimental-compaction-sleep-interval,omitempty"` - ExperimentalDowngradeCheckTime time.Duration `json:"experimental-downgrade-check-time,omitempty"` + SnapshotCount uint64 `json:"snapshot-count,omitempty"` + MaxSnapFiles uint `json:"max-snapshots,omitempty"` } testCases := []struct { @@ -1291,34 +546,6 @@ func TestConfigFileDeprecatedOptions(t *testing.T) { configFileYAML: configFileYAML{}, expectedFlags: map[string]struct{}{}, }, - { - name: "deprecated experimental options", - configFileYAML: configFileYAML{ - ExperimentalCompactHashCheckEnabled: true, - ExperimentalCompactHashCheckTime: 2 * time.Minute, - ExperimentalWarningUnaryRequestDuration: time.Second, - ExperimentalCorruptCheckTime: time.Minute, - ExperimentalCompactionBatchLimit: 1, - ExperimentalWatchProgressNotifyInterval: 3 * time.Minute, - ExperimentalWarningApplyDuration: 3 * time.Minute, - ExperimentalBootstrapDefragThresholdMegabytes: 100, - ExperimentalSnapshotCatchUpEntries: 1000, - ExperimentalCompactionSleepInterval: 30 * time.Second, - ExperimentalDowngradeCheckTime: 1 * time.Minute, - }, - expectedFlags: map[string]struct{}{ - "experimental-compact-hash-check-enabled": {}, - "experimental-compact-hash-check-time": {}, - "experimental-corrupt-check-time": {}, - "experimental-compaction-batch-limit": {}, - "experimental-watch-progress-notify-interval": {}, - "experimental-warning-apply-duration": {}, - "experimental-bootstrap-defrag-threshold-megabytes": {}, - "experimental-snapshot-catchup-entries": {}, - "experimental-compaction-sleep-interval": {}, - "experimental-downgrade-check-time": {}, - }, - }, { name: "deprecated snapshot options", configFileYAML: configFileYAML{ @@ -1361,349 +588,6 @@ func TestConfigFileDeprecatedOptions(t *testing.T) { // Compare sets of flags assert.Equalf(t, tc.expectedFlags, foundFlags, "deprecated flags mismatch - expected: %v, got: %v", tc.expectedFlags, foundFlags) - - // Note: experimental-warning-unary-request-duration deprecation is handled - // through a separate mechanism in embed.Config - if tc.configFileYAML.ExperimentalWarningUnaryRequestDuration != 0 { - assert.Equalf(t, cfg.ec.WarningUnaryRequestDuration, - tc.configFileYAML.ExperimentalWarningUnaryRequestDuration, - "experimental warning duration mismatch - expected: %v, got: %v", - tc.configFileYAML.ExperimentalWarningUnaryRequestDuration, - cfg.ec.WarningUnaryRequestDuration) - } - }) - } -} - -// TestPeerSkipClientSanVerificationFlagMigration tests the migration from -// --experimental-peer-skip-client-san-verification to --peer-skip-client-san-verification -// TODO: delete in v3.7 -func TestPeerSkipClientSanVerificationFlagMigration(t *testing.T) { - testCases := []struct { - name string - peerSkipClientSanVerification string - experimentalPeerSkipClientSanVerification string - useConfigFile bool - expectErr bool - expectedPeerSkipClientSanVerification bool - }{ - { - name: "cannot set both experimental flag and non experimental flag", - peerSkipClientSanVerification: "true", - experimentalPeerSkipClientSanVerification: "true", - expectErr: true, - }, - { - name: "can set experimental flag to true", - experimentalPeerSkipClientSanVerification: "true", - expectedPeerSkipClientSanVerification: true, - }, - { - name: "can set experimental flag to false", - experimentalPeerSkipClientSanVerification: "false", - expectedPeerSkipClientSanVerification: false, - }, - { - name: "can set non experimental flag to true", - peerSkipClientSanVerification: "true", - expectedPeerSkipClientSanVerification: true, - }, - { - name: "can set non experimental flag to false", - peerSkipClientSanVerification: "false", - expectedPeerSkipClientSanVerification: false, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - type securityConfig struct { - SkipClientSanVerification bool `json:"skip-client-san-verification,omitempty"` - } - cmdLineArgs := []string{} - yc := struct { - ExperimentalPeerSkipClientSanVerification bool `json:"experimental-peer-skip-client-san-verification,omitempty"` - PeerSecurityJSON securityConfig `json:"peer-transport-security"` - }{} - - if tc.peerSkipClientSanVerification != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--peer-skip-client-san-verification=%s", tc.peerSkipClientSanVerification)) - val, err := strconv.ParseBool(tc.peerSkipClientSanVerification) - if err != nil { - t.Fatal(err) - } - yc.PeerSecurityJSON.SkipClientSanVerification = val - } - - if tc.experimentalPeerSkipClientSanVerification != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-peer-skip-client-san-verification=%s", tc.experimentalPeerSkipClientSanVerification)) - val, err := strconv.ParseBool(tc.experimentalPeerSkipClientSanVerification) - if err != nil { - t.Fatal(err) - } - yc.ExperimentalPeerSkipClientSanVerification = val - } - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.expectErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatalf("expect parse error, got errFromCmdLine=%v, errFromFile=%v", errFromCmdLine, errFromFile) - } - return - } - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - if cfgFromCmdLine.ec.PeerTLSInfo.SkipClientSANVerify != tc.expectedPeerSkipClientSanVerification { - t.Errorf("expected SkipClientSANVerify=%v, got %v", - tc.expectedPeerSkipClientSanVerification, - cfgFromCmdLine.ec.PeerTLSInfo.SkipClientSANVerify) - } - if cfgFromFile.ec.PeerTLSInfo.SkipClientSANVerify != tc.expectedPeerSkipClientSanVerification { - t.Errorf("expected SkipClientSANVerify=%v, got %v", - tc.expectedPeerSkipClientSanVerification, - cfgFromFile.ec.PeerTLSInfo.SkipClientSANVerify) - } - }) - } -} - -// TestDistributedTracingFlagsMigration tests the migration from -// --experimental-distributed-tracing-* to --distributed-tracing-* -// TODO: delete in v3.7 -func TestDistributedTracingFlagsMigration(t *testing.T) { - testCases := []struct { - name string - - enableDistributedTracing string - distributedTracingAddress string - distributedTracingServiceName string - distributedTracingServiceInstanceID string - distributedTracingSamplingRatePerMillion string - - experimentalEnableDistributedTracing string - experimentalDistributedTracingAddress string - experimentalDistributedTracingServiceName string - experimentalDistributedTracingServiceInstanceID string - experimentalDistributedTracingSamplingRatePerMillion string - - expectedEnableDistributedTracing bool - expectedDistributedTracingAddress string - expectedDistributedTracingServiceName string - expectedDistributedTracingServiceInstanceID string - expectedDistributedTracingSamplingRatePerMillion int - - expectErr bool - }{ - // cannot set both experimental flags and non-experimental flags - { - name: "cannot set both experimental flag and non experimental flag 1", - enableDistributedTracing: "true", - experimentalEnableDistributedTracing: "true", - expectErr: true, - }, - { - name: "cannot set both experimental flag and non experimental flag 2", - distributedTracingAddress: "localhost:4317", - experimentalDistributedTracingAddress: "localhost:4318", - expectErr: true, - }, - { - name: "cannot set both experimental flag and non experimental flag 3", - distributedTracingServiceName: "etcd1", - experimentalDistributedTracingServiceName: "etcd2", - expectErr: true, - }, - { - name: "cannot set both experimental flag and non experimental flag 4", - distributedTracingServiceInstanceID: "fakeID", - experimentalDistributedTracingServiceInstanceID: "fakeID", - expectErr: true, - }, - { - name: "cannot set both experimental flag and non experimental flag 5", - distributedTracingSamplingRatePerMillion: "100", - experimentalDistributedTracingSamplingRatePerMillion: "100", - expectErr: true, - }, - // can set either --experimental-enable-distributed-tracing or --enable-distributed-tracing - { - name: "can set experimental-enable-distributed-tracing to true", - experimentalEnableDistributedTracing: "true", - expectedEnableDistributedTracing: true, - }, - { - name: "can set experimental-enable-distributed-tracing to false", - experimentalEnableDistributedTracing: "false", - expectedEnableDistributedTracing: false, - }, - { - name: "can set enable-distributed-tracing to true", - enableDistributedTracing: "true", - expectedEnableDistributedTracing: true, - }, - { - name: "can set enable-distributed-tracing to false", - enableDistributedTracing: "false", - expectedEnableDistributedTracing: false, - }, - // can set either --experimental-distributed-tracing-address or --distributed-tracing-address - { - name: "can set experimental-distributed-tracing-address", - experimentalDistributedTracingAddress: "localhost:1234", - expectedDistributedTracingAddress: "localhost:1234", - }, - { - name: "can set distributed-tracing-address", - distributedTracingAddress: "localhost:1234", - expectedDistributedTracingAddress: "localhost:1234", - }, - // can set either --experimental-distributed-tracing-service-name or --distributed-tracing-service-name - { - name: "can set experimental-distributed-tracing-service-name", - experimentalDistributedTracingServiceName: "fakeSererName", - expectedDistributedTracingServiceName: "fakeSererName", - }, - { - name: "can set distributed-tracing-service-name", - distributedTracingServiceName: "fakeSererName", - expectedDistributedTracingServiceName: "fakeSererName", - }, - // can set either --experimental-distributed-tracing-instance-id or --distributed-tracing-instance-id - { - name: "can set experimental-distributed-tracing-instance-id", - experimentalDistributedTracingServiceInstanceID: "fakeID", - expectedDistributedTracingServiceInstanceID: "fakeID", - }, - { - name: "can set distributed-tracing-instance-id", - distributedTracingServiceInstanceID: "fakeID", - expectedDistributedTracingServiceInstanceID: "fakeID", - }, - // can set either --experimental-distributed-tracing-sampling-rate or --distributed-tracing-sampling-rate - { - name: "can set experimental-distributed-tracing-sampling-rate", - experimentalDistributedTracingSamplingRatePerMillion: "200", - expectedDistributedTracingSamplingRatePerMillion: 200, - }, - { - name: "can set distributed-tracing-sampling-rate", - distributedTracingSamplingRatePerMillion: "300", - expectedDistributedTracingSamplingRatePerMillion: 300, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cmdLineArgs := []string{} - yc := struct { - ExperimentalEnableDistributedTracing bool `json:"experimental-enable-distributed-tracing,omitempty"` - EnableDistributedTracing bool `json:"enable-distributed-tracing,omitempty"` - - ExperimentalDistributedTracingAddress string `json:"experimental-distributed-tracing-address,omitempty"` - DistributedTracingAddress string `json:"distributed-tracing-address,omitempty"` - - ExperimentalDistributedTracingServiceName string `json:"experimental-distributed-tracing-service-name,omitempty"` - DistributedTracingServiceName string `json:"distributed-tracing-service-name,omitempty"` - - ExperimentalDistributedTracingServiceInstanceID string `json:"experimental-distributed-tracing-instance-id,omitempty"` - DistributedTracingServiceInstanceID string `json:"distributed-tracing-instance-id,omitempty"` - - ExperimentalDistributedTracingSamplingRatePerMillion int `json:"experimental-distributed-tracing-sampling-rate,omitempty"` - DistributedTracingSamplingRatePerMillion int `json:"distributed-tracing-sampling-rate,omitempty"` - }{} - - // --enable-distributed-tracing and --experimental-enable-distributed-tracing - if tc.enableDistributedTracing != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--enable-distributed-tracing=%s", tc.enableDistributedTracing)) - val, err := strconv.ParseBool(tc.enableDistributedTracing) - require.NoError(t, err) - yc.EnableDistributedTracing = val - } - if tc.experimentalEnableDistributedTracing != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-enable-distributed-tracing=%s", tc.experimentalEnableDistributedTracing)) - val, err := strconv.ParseBool(tc.experimentalEnableDistributedTracing) - require.NoError(t, err) - yc.ExperimentalEnableDistributedTracing = val - } - - // --distributed-tracing-address and --experimental-distributed-tracing-address - if tc.distributedTracingAddress != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--distributed-tracing-address=%s", tc.distributedTracingAddress)) - yc.DistributedTracingAddress = tc.distributedTracingAddress - } - if tc.experimentalDistributedTracingAddress != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-distributed-tracing-address=%s", tc.experimentalDistributedTracingAddress)) - yc.ExperimentalDistributedTracingAddress = tc.experimentalDistributedTracingAddress - } - - // --distributed-tracing-service-name and --experimental-distributed-tracing-service-name - if tc.distributedTracingServiceName != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--distributed-tracing-service-name=%s", tc.distributedTracingServiceName)) - yc.DistributedTracingServiceName = tc.distributedTracingServiceName - } - if tc.experimentalDistributedTracingServiceName != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-distributed-tracing-service-name=%s", tc.experimentalDistributedTracingServiceName)) - yc.ExperimentalDistributedTracingServiceName = tc.experimentalDistributedTracingServiceName - } - - // --distributed-tracing-instance-id and --experimental-distributed-tracing-instance-id - if tc.distributedTracingServiceInstanceID != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--distributed-tracing-instance-id=%s", tc.distributedTracingServiceInstanceID)) - yc.DistributedTracingServiceInstanceID = tc.distributedTracingServiceInstanceID - } - if tc.experimentalDistributedTracingServiceInstanceID != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-distributed-tracing-instance-id=%s", tc.experimentalDistributedTracingServiceInstanceID)) - yc.ExperimentalDistributedTracingServiceInstanceID = tc.experimentalDistributedTracingServiceInstanceID - } - - // --distributed-tracing-sampling-rate and --experimental-distributed-tracing-sampling-rate - if tc.distributedTracingSamplingRatePerMillion != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--distributed-tracing-sampling-rate=%s", tc.distributedTracingSamplingRatePerMillion)) - val, err := strconv.ParseInt(tc.distributedTracingSamplingRatePerMillion, 10, 64) - require.NoError(t, err) - yc.DistributedTracingSamplingRatePerMillion = int(val) - } - if tc.experimentalDistributedTracingSamplingRatePerMillion != "" { - cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-distributed-tracing-sampling-rate=%s", tc.experimentalDistributedTracingSamplingRatePerMillion)) - val, err := strconv.ParseInt(tc.experimentalDistributedTracingSamplingRatePerMillion, 10, 64) - require.NoError(t, err) - yc.ExperimentalDistributedTracingSamplingRatePerMillion = int(val) - } - - cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs) - - if tc.expectErr { - if errFromCmdLine == nil || errFromFile == nil { - t.Fatalf("expect parse error, got errFromCmdLine=%v, errFromFile=%v", errFromCmdLine, errFromFile) - } - return - } - if errFromCmdLine != nil || errFromFile != nil { - t.Fatal("error parsing config") - } - - // verify the expected values - require.Equal(t, tc.expectedEnableDistributedTracing, cfgFromCmdLine.ec.EnableDistributedTracing) - require.Equal(t, tc.expectedEnableDistributedTracing, cfgFromFile.ec.EnableDistributedTracing) - - if tc.expectedDistributedTracingAddress != "" { - require.Equal(t, tc.expectedDistributedTracingAddress, cfgFromCmdLine.ec.DistributedTracingAddress) - require.Equal(t, tc.expectedDistributedTracingAddress, cfgFromFile.ec.DistributedTracingAddress) - } - - if tc.expectedDistributedTracingServiceName != "" { - require.Equal(t, tc.expectedDistributedTracingServiceName, cfgFromCmdLine.ec.DistributedTracingServiceName) - require.Equal(t, tc.expectedDistributedTracingServiceName, cfgFromFile.ec.DistributedTracingServiceName) - } - - if tc.expectedDistributedTracingServiceInstanceID != "" { - require.Equal(t, tc.expectedDistributedTracingServiceInstanceID, cfgFromCmdLine.ec.DistributedTracingServiceInstanceID) - require.Equal(t, tc.expectedDistributedTracingServiceInstanceID, cfgFromFile.ec.DistributedTracingServiceInstanceID) - } - - require.Equal(t, tc.expectedDistributedTracingSamplingRatePerMillion, cfgFromCmdLine.ec.DistributedTracingSamplingRatePerMillion) - require.Equal(t, tc.expectedDistributedTracingSamplingRatePerMillion, cfgFromFile.ec.DistributedTracingSamplingRatePerMillion) }) } } diff --git a/server/etcdmain/help.go b/server/etcdmain/help.go index bc71b2eb3295..bf03c34ed547 100644 --- a/server/etcdmain/help.go +++ b/server/etcdmain/help.go @@ -260,89 +260,41 @@ Logging: --warning-unary-request-duration '300ms' Set time duration after which a warning is logged if a unary request takes more than this duration. -Experimental distributed tracing: - --experimental-enable-distributed-tracing 'false' - Enable experimental distributed tracing. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--enable-distributed-tracing' instead. +Distributed tracing: --enable-distributed-tracing 'false' Enable distributed tracing. - --experimental-distributed-tracing-address 'localhost:4317' - Distributed tracing collector address. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--distributed-tracing-address' instead. --distributed-tracing-address 'localhost:4317' Distributed tracing collector address. - --experimental-distributed-tracing-service-name 'etcd' - Distributed tracing service name, must be same across all etcd instances. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--distributed-tracing-service-name' instead. --distributed-tracing-service-name 'etcd' Distributed tracing service name, must be same across all etcd instances. - --experimental-distributed-tracing-instance-id '' - Distributed tracing instance ID, must be unique per each etcd instance. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--distributed-tracing-instance-id' instead. --distributed-tracing-instance-id '' Distributed tracing instance ID, must be unique per each etcd instance. - --experimental-distributed-tracing-sampling-rate '0' - Number of samples to collect per million spans for distributed tracing. Disabled by default. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--distributed-tracing-sampling-rate' instead. --distributed-tracing-sampling-rate '0' Number of samples to collect per million spans for distributed tracing. -Experimental feature: - --experimental-initial-corrupt-check 'false' - Enable to check data corruption before serving any client/peer traffic. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--feature-gates=InitialCorruptCheck=true' instead. - --experimental-corrupt-check-time '0s' - Duration of time between cluster corruption check passes. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--corrupt-check-time' instead. +Features: --corrupt-check-time '0s' Duration of time between cluster corruption check passes. - --experimental-compact-hash-check-enabled 'false' - Enable leader to periodically check followers compaction hashes. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--feature-gates=CompactHashCheck=true' instead. - --experimental-compact-hash-check-time '1m' - Duration of time between leader checks followers compaction hashes. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--compact-hash-check-time' instead. --compact-hash-check-time '1m' Duration of time between leader checks followers compaction hashes. - --experimental-enable-lease-checkpoint 'false' - ExperimentalEnableLeaseCheckpoint enables primary lessor to persist lease remainingTTL to prevent indefinite auto-renewal of long lived leases. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--feature-gates=LeaseCheckpoint=true' instead. - --experimental-compaction-batch-limit 1000 - ExperimentalCompactionBatchLimit sets the maximum revisions deleted in each compaction batch. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--compaction-batch-limit' instead. --compaction-batch-limit 1000 CompactionBatchLimit sets the maximum revisions deleted in each compaction batch. - --experimental-peer-skip-client-san-verification 'false' - Skip verification of SAN field in client certificate for peer connections. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--peer-skip-client-san-verification' instead. --peer-skip-client-san-verification 'false' Skip verification of SAN field in client certificate for peer connections. - --experimental-watch-progress-notify-interval '10m' - Duration of periodical watch progress notification. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--watch-progress-notify-interval' instead. --watch-progress-notify-interval '10m' Duration of periodical watch progress notification. - --experimental-warning-apply-duration '100ms' - Warning is generated if requests take more than this duration. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--warning-apply-duration' instead. --warning-apply-duration '100ms' Warning is generated if requests take more than this duration. - --experimental-txn-mode-write-with-shared-buffer 'true' - Enable the write transaction to use a shared buffer in its readonly check operations. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--feature-gates=TxnModeWriteWithSharedBuffer=true' instead. - --experimental-bootstrap-defrag-threshold-megabytes - 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. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--bootstrap-defrag-threshold-megabytes' instead. --bootstrap-defrag-threshold-megabytes 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. - --experimental-warning-unary-request-duration '300ms' - Set time duration after which a warning is generated if a unary request takes more than this duration. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--warning-unary-request-duration' instead. --max-learners '1' Set the max number of learner members allowed in the cluster membership. - --experimental-snapshot-catch-up-entries '5000' - Number of entries for a slow follower to catch up after compacting the raft storage entries. - --experimental-compaction-sleep-interval - Sets the sleep interval between each compaction batch. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--compaction-sleep-interval' instead. --compaction-sleep-interval Sets the sleep interval between each compaction batch. - --experimental-downgrade-check-time - Duration of time between two downgrade status checks. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--downgrade-check-time' instead. --downgrade-check-time Duration of time between two downgrade status checks. - --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. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--feature-gates=LeaseCheckpointPersist=true' instead. - --experimental-memory-mlock - Enable to enforce etcd pages (in particular bbolt) to stay in RAM. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--memory-mlock' instead. - --experimental-snapshot-catchup-entries - Number of entries for a slow follower to catch up after compacting the raft storage entries. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--snapshot-catchup-entries' instead. --snapshot-catchup-entries Number of entries for a slow follower to catch up after compacting the raft storage entries. - --experimental-stop-grpc-service-on-defrag - Enable etcd gRPC service to stop serving client requests on defragmentation. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--feature-gates=StopGRPCServiceOnDefrag=true' instead. Unsafe feature: --force-new-cluster 'false' diff --git a/server/etcdserver/bootstrap.go b/server/etcdserver/bootstrap.go index b25b7f6e1dbb..0d4e6ff964d6 100644 --- a/server/etcdserver/bootstrap.go +++ b/server/etcdserver/bootstrap.go @@ -261,8 +261,8 @@ func maybeDefragBackend(cfg config.ServerConfig, be backend.Backend) error { zap.String("current-db-size", humanize.Bytes(uint64(size))), zap.Int64("current-db-size-in-use-bytes", sizeInUse), zap.String("current-db-size-in-use", humanize.Bytes(uint64(sizeInUse))), - zap.Uint("experimental-bootstrap-defrag-threshold-bytes", thresholdBytes), - zap.String("experimental-bootstrap-defrag-threshold", humanize.Bytes(uint64(thresholdBytes))), + zap.Uint("bootstrap-defrag-threshold-bytes", thresholdBytes), + zap.String("bootstrap-defrag-threshold", humanize.Bytes(uint64(thresholdBytes))), ) return nil } diff --git a/server/features/etcd_features.go b/server/features/etcd_features.go index 230b37c703a3..6ff85e35779d 100644 --- a/server/features/etcd_features.go +++ b/server/features/etcd_features.go @@ -76,28 +76,15 @@ const ( SetMemberLocalAddr featuregate.Feature = "SetMemberLocalAddr" ) -var ( - DefaultEtcdServerFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ - StopGRPCServiceOnDefrag: {Default: false, PreRelease: featuregate.Alpha}, - InitialCorruptCheck: {Default: false, PreRelease: featuregate.Alpha}, - CompactHashCheck: {Default: false, PreRelease: featuregate.Alpha}, - TxnModeWriteWithSharedBuffer: {Default: true, PreRelease: featuregate.Beta}, - LeaseCheckpoint: {Default: false, PreRelease: featuregate.Alpha}, - LeaseCheckpointPersist: {Default: false, PreRelease: featuregate.Alpha}, - SetMemberLocalAddr: {Default: false, PreRelease: featuregate.Alpha}, - } - // ExperimentalFlagToFeatureMap is the map from the cmd line flags of experimental features - // to their corresponding feature gates. - // Deprecated: Only add existing experimental features here. DO NOT use for new features. - ExperimentalFlagToFeatureMap = map[string]featuregate.Feature{ - "experimental-stop-grpc-service-on-defrag": StopGRPCServiceOnDefrag, - "experimental-initial-corrupt-check": InitialCorruptCheck, - "experimental-compact-hash-check-enabled": CompactHashCheck, - "experimental-txn-mode-write-with-shared-buffer": TxnModeWriteWithSharedBuffer, - "experimental-enable-lease-checkpoint": LeaseCheckpoint, - "experimental-enable-lease-checkpoint-persist": LeaseCheckpointPersist, - } -) +var DefaultEtcdServerFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ + StopGRPCServiceOnDefrag: {Default: false, PreRelease: featuregate.Alpha}, + InitialCorruptCheck: {Default: false, PreRelease: featuregate.Alpha}, + CompactHashCheck: {Default: false, PreRelease: featuregate.Alpha}, + TxnModeWriteWithSharedBuffer: {Default: true, PreRelease: featuregate.Beta}, + LeaseCheckpoint: {Default: false, PreRelease: featuregate.Alpha}, + LeaseCheckpointPersist: {Default: false, PreRelease: featuregate.Alpha}, + SetMemberLocalAddr: {Default: false, PreRelease: featuregate.Alpha}, +} func NewDefaultServerFeatureGate(name string, lg *zap.Logger) featuregate.FeatureGate { fg := featuregate.New(fmt.Sprintf("%sServerFeatureGate", name), lg) diff --git a/tests/e2e/corrupt_test.go b/tests/e2e/corrupt_test.go index d9e7b07704f9..f18f094cdb47 100644 --- a/tests/e2e/corrupt_test.go +++ b/tests/e2e/corrupt_test.go @@ -188,24 +188,13 @@ func TestInPlaceRecovery(t *testing.T) { } func TestPeriodicCheckDetectsCorruption(t *testing.T) { - testPeriodicCheckDetectsCorruption(t, false) -} - -func TestPeriodicCheckDetectsCorruptionWithExperimentalFlag(t *testing.T) { - testPeriodicCheckDetectsCorruption(t, true) -} - -func testPeriodicCheckDetectsCorruption(t *testing.T, useExperimentalFlag bool) { checkTime := time.Second e2e.BeforeTest(t) ctx, cancel := context.WithCancel(t.Context()) defer cancel() - var corruptCheckTime e2e.EPClusterOption - if useExperimentalFlag { - corruptCheckTime = e2e.WithExperimentalCorruptCheckTime(time.Second) - } else { - corruptCheckTime = e2e.WithCorruptCheckTime(time.Second) - } + + corruptCheckTime := e2e.WithCorruptCheckTime(time.Second) + epc, err := e2e.NewEtcdProcessCluster(ctx, t, e2e.WithKeepDataDir(true), corruptCheckTime, @@ -294,18 +283,14 @@ func testCompactHashCheckDetectCorruption(t *testing.T, useFeatureGate bool) { } func TestCompactHashCheckDetectCorruptionInterrupt(t *testing.T) { - testCompactHashCheckDetectCorruptionInterrupt(t, false, false) + testCompactHashCheckDetectCorruptionInterrupt(t, false) } func TestCompactHashCheckDetectCorruptionInterruptWithFeatureGate(t *testing.T) { - testCompactHashCheckDetectCorruptionInterrupt(t, true, false) -} - -func TestCompactHashCheckDetectCorruptionInterruptWithExperimentalFlag(t *testing.T) { - testCompactHashCheckDetectCorruptionInterrupt(t, true, true) + testCompactHashCheckDetectCorruptionInterrupt(t, true) } -func testCompactHashCheckDetectCorruptionInterrupt(t *testing.T, useFeatureGate bool, useExperimentalFlag bool) { +func testCompactHashCheckDetectCorruptionInterrupt(t *testing.T, useFeatureGate bool) { checkTime := time.Second e2e.BeforeTest(t) ctx, cancel := context.WithTimeout(t.Context(), 60*time.Second) @@ -329,12 +314,8 @@ func testCompactHashCheckDetectCorruptionInterrupt(t *testing.T, useFeatureGate } else { opts = append(opts, e2e.WithCompactHashCheckEnabled(true)) } - var compactionBatchLimit e2e.EPClusterOption - if useExperimentalFlag { - compactionBatchLimit = e2e.WithExperimentalCompactionBatchLimit(1) - } else { - compactionBatchLimit = e2e.WithCompactionBatchLimit(1) - } + + compactionBatchLimit := e2e.WithCompactionBatchLimit(1) cfg := e2e.NewConfig(opts...) epc, err := e2e.InitEtcdProcessCluster(t, cfg) diff --git a/tests/e2e/ctl_v3_test.go b/tests/e2e/ctl_v3_test.go index 9c5c2c857cea..51334915071d 100644 --- a/tests/e2e/ctl_v3_test.go +++ b/tests/e2e/ctl_v3_test.go @@ -27,6 +27,7 @@ import ( "go.etcd.io/etcd/api/v3/version" "go.etcd.io/etcd/client/pkg/v3/testutil" "go.etcd.io/etcd/pkg/v3/expect" + "go.etcd.io/etcd/pkg/v3/featuregate" "go.etcd.io/etcd/pkg/v3/flags" "go.etcd.io/etcd/tests/v3/framework/e2e" ) @@ -225,7 +226,7 @@ func testCtlWithOffline(t *testing.T, testFunc func(ctlCtx), testOfflineFunc fun } ret.cfg.ServerConfig.StrictReconfigCheck = !ret.disableStrictReconfigCheck if ret.initialCorruptCheck { - ret.cfg.ServerConfig.ExperimentalInitialCorruptCheck = ret.initialCorruptCheck + ret.cfg.ServerConfig.ServerFeatureGate.(featuregate.MutableFeatureGate).Set(fmt.Sprintf("InitialCorruptCheck=%t", ret.initialCorruptCheck)) } if testOfflineFunc != nil { ret.cfg.KeepDataDir = true diff --git a/tests/e2e/etcd_config_test.go b/tests/e2e/etcd_config_test.go index 51c5bb89094b..50e1aa50ab8c 100644 --- a/tests/e2e/etcd_config_test.go +++ b/tests/e2e/etcd_config_test.go @@ -568,7 +568,7 @@ func TestGrpcproxyAndListenCipherSuite(t *testing.T) { func TestBootstrapDefragFlag(t *testing.T) { e2e.SkipInShortMode(t) - proc, err := e2e.SpawnCmd([]string{e2e.BinPath.Etcd, "--experimental-bootstrap-defrag-threshold-megabytes", "1000"}, nil) + proc, err := e2e.SpawnCmd([]string{e2e.BinPath.Etcd, "--bootstrap-defrag-threshold-megabytes", "1000"}, nil) require.NoError(t, err) require.NoError(t, e2e.WaitReadyExpectProc(t.Context(), proc, []string{"Skipping defragmentation"})) require.NoError(t, proc.Stop()) @@ -585,7 +585,7 @@ func TestSnapshotCatchupEntriesFlag(t *testing.T) { ctx, cancel := context.WithTimeout(t.Context(), 10*time.Second) defer cancel() - proc, err := e2e.SpawnCmd([]string{e2e.BinPath.Etcd, "--experimental-snapshot-catchup-entries", "1000"}, nil) + proc, err := e2e.SpawnCmd([]string{e2e.BinPath.Etcd, "--snapshot-catchup-entries", "1000"}, nil) require.NoError(t, err) require.NoError(t, e2e.WaitReadyExpectProc(ctx, proc, []string{"\"snapshot-catchup-entries\":1000"})) require.NoError(t, e2e.WaitReadyExpectProc(ctx, proc, []string{"serving client traffic"})) diff --git a/tests/e2e/failover_test.go b/tests/e2e/failover_test.go index 58ee806cabd7..22411f5c8a8c 100644 --- a/tests/e2e/failover_test.go +++ b/tests/e2e/failover_test.go @@ -59,7 +59,7 @@ func TestFailoverOnDefrag(t *testing.T) { name: "defrag failover happy case", clusterOptions: []e2e.EPClusterOption{ e2e.WithClusterSize(3), - e2e.WithExperimentalStopGRPCServiceOnDefrag(true), + e2e.WithServerFeatureGate("StopGRPCServiceOnDefrag", true), e2e.WithGoFailEnabled(true), }, gRPCDialOptions: []grpc.DialOption{ @@ -73,7 +73,7 @@ func TestFailoverOnDefrag(t *testing.T) { name: "defrag blocks one-third of requests with stopGRPCServiceOnDefrag set to false", clusterOptions: []e2e.EPClusterOption{ e2e.WithClusterSize(3), - e2e.WithExperimentalStopGRPCServiceOnDefrag(false), + e2e.WithServerFeatureGate("StopGRPCServiceOnDefrag", false), e2e.WithGoFailEnabled(true), }, gRPCDialOptions: []grpc.DialOption{ @@ -87,7 +87,7 @@ func TestFailoverOnDefrag(t *testing.T) { name: "defrag blocks one-third of requests with stopGRPCServiceOnDefrag set to true and client health check disabled", clusterOptions: []e2e.EPClusterOption{ e2e.WithClusterSize(3), - e2e.WithExperimentalStopGRPCServiceOnDefrag(true), + e2e.WithServerFeatureGate("StopGRPCServiceOnDefrag", true), e2e.WithGoFailEnabled(true), }, expectedMinQPS: 20, diff --git a/tests/e2e/promote_experimental_flag_test.go b/tests/e2e/promote_experimental_flag_test.go index 18fb0bd3bdf7..76992f811f29 100644 --- a/tests/e2e/promote_experimental_flag_test.go +++ b/tests/e2e/promote_experimental_flag_test.go @@ -47,43 +47,3 @@ func TestWarningApplyDuration(t *testing.T) { // verify warning e2e.AssertProcessLogs(t, epc.Procs[0], "request stats") } - -// TestExperimentalWarningApplyDuration tests the experimental warning apply duration -// TODO: this test is a duplicate of TestWarningApplyDuration except it uses --experimental-warning-unary-request-duration -// Remove this test after --experimental-warning-unary-request-duration flag is removed. -func TestExperimentalWarningApplyDuration(t *testing.T) { - e2e.BeforeTest(t) - - epc, err := e2e.NewEtcdProcessCluster(t.Context(), t, - e2e.WithClusterSize(1), - e2e.WithExperimentalWarningUnaryRequestDuration(time.Microsecond), - ) - if err != nil { - t.Fatalf("could not start etcd process cluster (%v)", err) - } - t.Cleanup(func() { - if errC := epc.Close(); errC != nil { - t.Fatalf("error closing etcd processes (%v)", errC) - } - }) - - cc := epc.Etcdctl() - err = cc.Put(t.Context(), "foo", "bar", config.PutOptions{}) - require.NoErrorf(t, err, "error on put") - - // verify warning - e2e.AssertProcessLogs(t, epc.Procs[0], "request stats") -} - -func TestBothWarningApplyDurationFlagsFail(t *testing.T) { - e2e.BeforeTest(t) - - _, err := e2e.NewEtcdProcessCluster(t.Context(), t, - e2e.WithClusterSize(1), - e2e.WithWarningUnaryRequestDuration(time.Second), - e2e.WithExperimentalWarningUnaryRequestDuration(time.Second), - ) - if err == nil { - t.Fatal("Expected process to fail") - } -} diff --git a/tests/framework/e2e/cluster.go b/tests/framework/e2e/cluster.go index 87e96491a7f4..f32b51671a1d 100644 --- a/tests/framework/e2e/cluster.go +++ b/tests/framework/e2e/cluster.go @@ -314,20 +314,20 @@ func WithCorruptCheckTime(time time.Duration) EPClusterOption { return func(c *EtcdProcessClusterConfig) { c.ServerConfig.CorruptCheckTime = time } } -func WithExperimentalCorruptCheckTime(time time.Duration) EPClusterOption { - return func(c *EtcdProcessClusterConfig) { c.ServerConfig.ExperimentalCorruptCheckTime = time } -} - func WithInitialClusterToken(token string) EPClusterOption { return func(c *EtcdProcessClusterConfig) { c.ServerConfig.InitialClusterToken = token } } func WithInitialCorruptCheck(enabled bool) EPClusterOption { - return func(c *EtcdProcessClusterConfig) { c.ServerConfig.ExperimentalInitialCorruptCheck = enabled } + return func(c *EtcdProcessClusterConfig) { + c.ServerConfig.ServerFeatureGate.(featuregate.MutableFeatureGate).Set(fmt.Sprintf("InitialCorruptCheck=%t", enabled)) + } } func WithCompactHashCheckEnabled(enabled bool) EPClusterOption { - return func(c *EtcdProcessClusterConfig) { c.ServerConfig.ExperimentalCompactHashCheckEnabled = enabled } + return func(c *EtcdProcessClusterConfig) { + c.ServerConfig.ServerFeatureGate.(featuregate.MutableFeatureGate).Set(fmt.Sprintf("CompactHashCheck=%t", enabled)) + } } func WithCompactHashCheckTime(time time.Duration) EPClusterOption { @@ -350,18 +350,6 @@ func WithWarningUnaryRequestDuration(time time.Duration) EPClusterOption { return func(c *EtcdProcessClusterConfig) { c.ServerConfig.WarningUnaryRequestDuration = time } } -// WithExperimentalWarningUnaryRequestDuration sets a value for `-experimental-warning-unary-request-duration`. -// TODO(ahrtr): remove this function when the corresponding experimental flag is decommissioned. -func WithExperimentalWarningUnaryRequestDuration(time time.Duration) EPClusterOption { - return func(c *EtcdProcessClusterConfig) { c.ServerConfig.ExperimentalWarningUnaryRequestDuration = time } -} - -func WithExperimentalStopGRPCServiceOnDefrag(stopGRPCServiceOnDefrag bool) EPClusterOption { - return func(c *EtcdProcessClusterConfig) { - c.ServerConfig.ExperimentalStopGRPCServiceOnDefrag = stopGRPCServiceOnDefrag - } -} - func WithServerFeatureGate(featureName string, val bool) EPClusterOption { return func(c *EtcdProcessClusterConfig) { if err := c.ServerConfig.ServerFeatureGate.(featuregate.MutableFeatureGate).Set(fmt.Sprintf("%s=%v", featureName, val)); err != nil { @@ -374,22 +362,14 @@ func WithCompactionBatchLimit(limit int) EPClusterOption { return func(c *EtcdProcessClusterConfig) { c.ServerConfig.CompactionBatchLimit = limit } } -func WithExperimentalCompactionBatchLimit(limit int) EPClusterOption { - return func(c *EtcdProcessClusterConfig) { c.ServerConfig.ExperimentalCompactionBatchLimit = limit } -} - func WithCompactionSleepInterval(time time.Duration) EPClusterOption { - return func(c *EtcdProcessClusterConfig) { c.ServerConfig.ExperimentalCompactionSleepInterval = time } + return func(c *EtcdProcessClusterConfig) { c.ServerConfig.CompactionSleepInterval = time } } func WithWatchProcessNotifyInterval(interval time.Duration) EPClusterOption { return func(c *EtcdProcessClusterConfig) { c.ServerConfig.WatchProgressNotifyInterval = interval } } -func WithExperimentalWatchProcessNotifyInterval(interval time.Duration) EPClusterOption { - return func(c *EtcdProcessClusterConfig) { c.ServerConfig.ExperimentalWatchProgressNotifyInterval = interval } -} - func WithEnvVars(ev map[string]string) EPClusterOption { return func(c *EtcdProcessClusterConfig) { c.EnvVars = ev } } @@ -633,7 +613,6 @@ func (cfg *EtcdProcessClusterConfig) EtcdServerProcessConfig(tb testing.TB, i in if cfg.ServerConfig.SnapshotCatchUpEntries != etcdserver.DefaultSnapshotCatchUpEntries { if !IsSnapshotCatchupEntriesFlagAvailable(execPath) { - cfg.ServerConfig.ExperimentalSnapshotCatchUpEntries = cfg.ServerConfig.SnapshotCatchUpEntries cfg.ServerConfig.SnapshotCatchUpEntries = etcdserver.DefaultSnapshotCatchUpEntries } } diff --git a/tests/framework/e2e/cluster_test.go b/tests/framework/e2e/cluster_test.go index f5ff967203ae..5880bd38726e 100644 --- a/tests/framework/e2e/cluster_test.go +++ b/tests/framework/e2e/cluster_test.go @@ -67,7 +67,7 @@ func TestEtcdServerProcessConfig(t *testing.T) { name: "CorruptCheck", config: NewConfig(WithInitialCorruptCheck(true)), expectArgsContain: []string{ - "--experimental-initial-corrupt-check=true", + "--feature-gates=InitialCorruptCheck=true", }, }, { diff --git a/tests/robustness/failpoint/trigger.go b/tests/robustness/failpoint/trigger.go index 9ae9a8084819..a75feb71d2cc 100644 --- a/tests/robustness/failpoint/trigger.go +++ b/tests/robustness/failpoint/trigger.go @@ -75,7 +75,7 @@ func (t triggerCompact) Trigger(ctx context.Context, _ *testing.T, member e2e.Et } rev = resp.Header.Revision - if !t.multiBatchCompaction || rev > int64(clus.Cfg.ServerConfig.ExperimentalCompactionBatchLimit) { + if !t.multiBatchCompaction || rev > int64(clus.Cfg.ServerConfig.CompactionBatchLimit) { break } time.Sleep(50 * time.Millisecond) @@ -97,9 +97,9 @@ func (t triggerCompact) Available(config e2e.EtcdProcessClusterConfig, _ e2e.Etc return false } // For multiBatchCompaction we need to guarantee that there are enough revisions between two compaction requests. - // With addition of compaction requests to traffic this might be hard if experimental-compaction-batch-limit is too high. + // With addition of compaction requests to traffic this might be hard if -compaction-batch-limit is too high. if t.multiBatchCompaction { - return config.ServerConfig.ExperimentalCompactionBatchLimit <= 10 + return config.ServerConfig.CompactionBatchLimit <= 10 } return true } diff --git a/tests/robustness/main_test.go b/tests/robustness/main_test.go index 1cc35f571b74..55879cabe9af 100644 --- a/tests/robustness/main_test.go +++ b/tests/robustness/main_test.go @@ -111,7 +111,7 @@ func testRobustness(ctx context.Context, t *testing.T, lg *zap.Logger, s scenari failpointImpactingWatch := s.Failpoint == failpoint.SleepBeforeSendWatchResponse if !failpointImpactingWatch { - watchProgressNotifyEnabled := c.Cfg.ServerConfig.ExperimentalWatchProgressNotifyInterval != 0 + watchProgressNotifyEnabled := c.Cfg.ServerConfig.WatchProgressNotifyInterval != 0 client.ValidateGotAtLeastOneProgressNotify(t, r.Client, s.Watch.RequestProgress || watchProgressNotifyEnabled) } validateConfig := validate.Config{ExpectRevisionUnique: s.Traffic.ExpectUniqueRevision()} diff --git a/tests/robustness/options/server_config_options.go b/tests/robustness/options/server_config_options.go index ade51592cd1c..a0a6b5d5a875 100644 --- a/tests/robustness/options/server_config_options.go +++ b/tests/robustness/options/server_config_options.go @@ -26,9 +26,9 @@ func WithSnapshotCount(input ...uint64) e2e.EPClusterOption { } } -func WithExperimentalCompactionBatchLimit(input ...int) e2e.EPClusterOption { +func WithCompactionBatchLimit(input ...int) e2e.EPClusterOption { return func(c *e2e.EtcdProcessClusterConfig) { - c.ServerConfig.ExperimentalCompactionBatchLimit = input[internalRand.Intn(len(input))] + c.ServerConfig.CompactionBatchLimit = input[internalRand.Intn(len(input))] } } @@ -50,9 +50,9 @@ func WithElectionMs(input ...uint) e2e.EPClusterOption { } } -func WithExperimentalWatchProgressNotifyInterval(input ...time.Duration) e2e.EPClusterOption { +func WithWatchProgressNotifyInterval(input ...time.Duration) e2e.EPClusterOption { return func(c *e2e.EtcdProcessClusterConfig) { - c.ServerConfig.ExperimentalWatchProgressNotifyInterval = input[internalRand.Intn(len(input))] + c.ServerConfig.WatchProgressNotifyInterval = input[internalRand.Intn(len(input))] } } diff --git a/tests/robustness/scenarios/scenarios.go b/tests/robustness/scenarios/scenarios.go index ba33add20c2e..9be207f82e01 100644 --- a/tests/robustness/scenarios/scenarios.go +++ b/tests/robustness/scenarios/scenarios.go @@ -97,8 +97,8 @@ func Exploratory(_ *testing.T) []TestScenario { options.WithSubsetOptions(randomizableOptions...), e2e.WithGoFailEnabled(true), // Set low minimal compaction batch limit to allow for triggering multi batch compaction failpoints. - options.WithExperimentalCompactionBatchLimit(10, 100, 1000), - e2e.WithExperimentalWatchProcessNotifyInterval(100 * time.Millisecond), + options.WithCompactionBatchLimit(10, 100, 1000), + e2e.WithWatchProcessNotifyInterval(100 * time.Millisecond), } if e2e.CouldSetSnapshotCatchupEntries(e2e.BinPath.Etcd) { @@ -219,7 +219,7 @@ func Regression(t *testing.T) []TestScenario { Traffic: traffic.Kubernetes, Cluster: *e2e.NewConfig( e2e.WithClusterSize(1), - e2e.WithExperimentalCompactionBatchLimit(300), + e2e.WithCompactionBatchLimit(300), e2e.WithSnapshotCount(1000), e2e.WithGoFailEnabled(true), ), @@ -250,7 +250,7 @@ func Regression(t *testing.T) []TestScenario { Traffic: traffic.KubernetesCreateDelete, Cluster: *e2e.NewConfig( e2e.WithClusterSize(1), - e2e.WithExperimentalCompactionBatchLimit(50), + e2e.WithCompactionBatchLimit(50), e2e.WithSnapshotCount(1000), e2e.WithGoFailEnabled(true), ),