From 4b94ddcda154f04611d6976fe5e6800a6f07276c Mon Sep 17 00:00:00 2001 From: Chun-Hung Tseng Date: Thu, 13 Feb 2025 14:58:40 +0000 Subject: [PATCH] Migrate --experimental-set-member-localaddr to using feature flag Signed-off-by: Chun-Hung Tseng Co-authored-by: Benjamin Wang --- CHANGELOG/CHANGELOG-3.6.md | 2 +- server/embed/config.go | 8 +--- server/embed/config_test.go | 66 ++++++++++++++++++++++---------- server/embed/etcd.go | 1 - server/etcdmain/help.go | 2 - server/features/etcd_features.go | 7 ++++ tests/e2e/etcd_config_test.go | 6 +-- 7 files changed, 57 insertions(+), 35 deletions(-) diff --git a/CHANGELOG/CHANGELOG-3.6.md b/CHANGELOG/CHANGELOG-3.6.md index 7e3267adeded..5421e1324263 100644 --- a/CHANGELOG/CHANGELOG-3.6.md +++ b/CHANGELOG/CHANGELOG-3.6.md @@ -78,7 +78,7 @@ See [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0...v3.6.0). - Decreased [`--snapshot-count` default value from 100,000 to 10,000](https://github.com/etcd-io/etcd/pull/15408) - Add [`etcd --tls-min-version --tls-max-version`](https://github.com/etcd-io/etcd/pull/15156) to enable support for TLS 1.3. - Add [quota to endpoint status response](https://github.com/etcd-io/etcd/pull/17877) -- Add ['etcd --experimental-set-member-localaddr'](https://github.com/etcd-io/etcd/pull/17661) to enable using the first specified and non-loopback local address from initial-advertise-peer-urls as the local address when communicating with a peer. +- Add [feature gate `SetMemberLocalAddr`](https://github.com/etcd-io/etcd/pull/19413) to [enable using the first specified and non-loopback local address from initial-advertise-peer-urls as the local address when communicating with a peer]((https://github.com/etcd-io/etcd/pull/17661)) - Add [Support multiple values for allowed client and peer TLS identities](https://github.com/etcd-io/etcd/pull/18015) - Add [`embed.Config.GRPCAdditionalServerOptions`](https://github.com/etcd-io/etcd/pull/14066) to support updating the default internal gRPC configuration for embedded use cases. diff --git a/server/embed/config.go b/server/embed/config.go index d1d2729a2e5a..6cc9f1c78477 100644 --- a/server/embed/config.go +++ b/server/embed/config.go @@ -285,11 +285,6 @@ type Config struct { PeerTLSInfo transport.TLSInfo PeerAutoTLS bool - // ExperimentalSetMemberLocalAddr enables using the first specified and - // non-loopback local address from initial-advertise-peer-urls as the local - // address when communicating with a peer. - ExperimentalSetMemberLocalAddr bool `json:"experimental-set-member-localaddr"` - // SelfSignedCertValidity specifies the validity period of the client and peer certificates // that are automatically generated by etcd when you specify ClientAutoTLS and PeerAutoTLS, // the unit is year, and the default is 1 @@ -814,7 +809,6 @@ func (cfg *Config) AddFlags(fs *flag.FlagSet) { "initial-advertise-peer-urls", "List of this member's peer URLs to advertise to the rest of the cluster.", ) - fs.BoolVar(&cfg.ExperimentalSetMemberLocalAddr, "experimental-set-member-localaddr", false, "Enable to have etcd use the first specified and non-loopback host from initial-advertise-peer-urls as the local address when communicating with a peer.") fs.Var( flags.NewUniqueURLsWithExceptions(DefaultAdvertiseClientURLs, ""), @@ -1475,7 +1469,7 @@ func (cfg *Config) InitialClusterFromName(name string) (ret string) { // non-loopback address. Otherwise, it defaults to empty string and the // LocalAddr used will be the default for the Golang HTTP client. func (cfg *Config) InferLocalAddr() string { - if !cfg.ExperimentalSetMemberLocalAddr { + if !cfg.ServerFeatureGate.Enabled(features.SetMemberLocalAddr) { return "" } diff --git a/server/embed/config_test.go b/server/embed/config_test.go index bb098719c924..54247382f05a 100644 --- a/server/embed/config_test.go +++ b/server/embed/config_test.go @@ -149,7 +149,7 @@ func TestConfigFileFeatureGates(t *testing.T) { }, { name: "ok to set different multiple experimental flags and feature gate flags", - serverFeatureGatesJSON: "StopGRPCServiceOnDefrag=true,TxnModeWriteWithSharedBuffer=true,LeaseCheckpoint=true", + serverFeatureGatesJSON: "StopGRPCServiceOnDefrag=true,TxnModeWriteWithSharedBuffer=true,LeaseCheckpoint=true,SetMemberLocalAddr=true", experimentalCompactHashCheckEnabled: "true", experimentalInitialCorruptCheck: "true", expectedFeatures: map[featuregate.Feature]bool{ @@ -158,6 +158,7 @@ func TestConfigFileFeatureGates(t *testing.T) { features.InitialCorruptCheck: true, features.TxnModeWriteWithSharedBuffer: true, features.LeaseCheckpoint: true, + features.SetMemberLocalAddr: true, }, }, { @@ -440,117 +441,117 @@ func TestInferLocalAddr(t *testing.T) { tests := []struct { name string advertisePeerURLs []string - setMemberLocalAddr bool + serverFeatureGates string expectedLocalAddr string }{ { "defaults, ExperimentalSetMemberLocalAddr=false ", []string{DefaultInitialAdvertisePeerURLs}, - false, + "SetMemberLocalAddr=false", "", }, { "IPv4 address, ExperimentalSetMemberLocalAddr=false ", []string{"https://192.168.100.110:2380"}, - false, + "SetMemberLocalAddr=false", "", }, { "defaults, ExperimentalSetMemberLocalAddr=true", []string{DefaultInitialAdvertisePeerURLs}, - true, + "SetMemberLocalAddr=true", "", }, { "IPv4 unspecified address, ExperimentalSetMemberLocalAddr=true", []string{"https://0.0.0.0:2380"}, - true, + "SetMemberLocalAddr=true", "", }, { "IPv6 unspecified address, ExperimentalSetMemberLocalAddr=true", []string{"https://[::]:2380"}, - true, + "SetMemberLocalAddr=true", "", }, { "IPv4 loopback address, ExperimentalSetMemberLocalAddr=true", []string{"https://127.0.0.1:2380"}, - true, + "SetMemberLocalAddr=true", "", }, { "IPv6 loopback address, ExperimentalSetMemberLocalAddr=true", []string{"https://[::1]:2380"}, - true, + "SetMemberLocalAddr=true", "", }, { "IPv4 address, ExperimentalSetMemberLocalAddr=true", []string{"https://192.168.100.110:2380"}, - true, + "SetMemberLocalAddr=true", "192.168.100.110", }, { "Hostname only, ExperimentalSetMemberLocalAddr=true", []string{"https://123-host-3.corp.internal:2380"}, - true, + "SetMemberLocalAddr=true", "", }, { "Hostname and IPv4 address, ExperimentalSetMemberLocalAddr=true", []string{"https://123-host-3.corp.internal:2380", "https://192.168.100.110:2380"}, - true, + "SetMemberLocalAddr=true", "192.168.100.110", }, { "IPv4 address and Hostname, ExperimentalSetMemberLocalAddr=true", []string{"https://192.168.100.110:2380", "https://123-host-3.corp.internal:2380"}, - true, + "SetMemberLocalAddr=true", "192.168.100.110", }, { "IPv4 and IPv6 addresses, ExperimentalSetMemberLocalAddr=true", []string{"https://192.168.100.110:2380", "https://[2001:db8:85a3::8a2e:370:7334]:2380"}, - true, + "SetMemberLocalAddr=true", "192.168.100.110", }, { "IPv6 and IPv4 addresses, ExperimentalSetMemberLocalAddr=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"}, - true, + "SetMemberLocalAddr=true", "192.168.100.110", }, { "Hostname, IPv4 and IPv6 addresses, ExperimentalSetMemberLocalAddr=true", []string{"https://123-host-3.corp.internal:2380", "https://192.168.100.110:2380", "https://[2001:db8:85a3::8a2e:370:7334]:2380"}, - true, + "SetMemberLocalAddr=true", "192.168.100.110", }, { "Hostname, IPv6 and IPv4 addresses, ExperimentalSetMemberLocalAddr=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"}, - true, + "SetMemberLocalAddr=true", "192.168.100.110", }, { "IPv6 address, ExperimentalSetMemberLocalAddr=true", []string{"https://[2001:db8:85a3::8a2e:370:7334]:2380"}, - true, + "SetMemberLocalAddr=true", "2001:db8:85a3::8a2e:370:7334", }, { "Hostname and IPv6 address, ExperimentalSetMemberLocalAddr=true", []string{"https://123-host-3.corp.internal:2380", "https://[2001:db8:85a3::8a2e:370:7334]:2380"}, - true, + "SetMemberLocalAddr=true", "2001:db8:85a3::8a2e:370:7334", }, { "IPv6 address and Hostname, ExperimentalSetMemberLocalAddr=true", []string{"https://[2001:db8:85a3::8a2e:370:7334]:2380", "https://123-host-3.corp.internal:2380"}, - true, + "SetMemberLocalAddr=true", "2001:db8:85a3::8a2e:370:7334", }, } @@ -559,7 +560,7 @@ func TestInferLocalAddr(t *testing.T) { t.Run(tt.name, func(t *testing.T) { cfg := NewConfig() cfg.AdvertisePeerUrls = types.MustNewURLs(tt.advertisePeerURLs) - cfg.ExperimentalSetMemberLocalAddr = tt.setMemberLocalAddr + cfg.ServerFeatureGate.(featuregate.MutableFeatureGate).Set(tt.serverFeatureGates) require.NoError(t, cfg.Validate()) require.Equal(t, tt.expectedLocalAddr, cfg.InferLocalAddr()) @@ -567,6 +568,29 @@ func TestInferLocalAddr(t *testing.T) { } } +func TestSetMemberLocalAddrValidate(t *testing.T) { + tcs := []struct { + name string + serverFeatureGates string + }{ + { + name: "Default config should pass", + }, + { + name: "Enabling SetMemberLocalAddr should pass", + serverFeatureGates: "SetMemberLocalAddr=true", + }, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + cfg := *NewConfig() + cfg.ServerFeatureGate.(featuregate.MutableFeatureGate).Set(tc.serverFeatureGates) + err := cfg.Validate() + require.NoError(t, err) + }) + } +} + func (s *securityConfig) equals(t *transport.TLSInfo) bool { return s.CertFile == t.CertFile && s.CertAuth == t.ClientCertAuth && diff --git a/server/embed/etcd.go b/server/embed/etcd.go index dae44d8ca95d..95c0d6d92f97 100644 --- a/server/embed/etcd.go +++ b/server/embed/etcd.go @@ -348,7 +348,6 @@ 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.Bool("experimental-set-member-localaddr", ec.ExperimentalSetMemberLocalAddr), zap.String("experimental-local-address", sc.ExperimentalLocalAddress), zap.Strings("cors", cors), zap.Strings("host-whitelist", hss), diff --git a/server/etcdmain/help.go b/server/etcdmain/help.go index 9f34c07e96a1..8763875d185e 100644 --- a/server/etcdmain/help.go +++ b/server/etcdmain/help.go @@ -113,8 +113,6 @@ Member: Clustering: --initial-advertise-peer-urls 'http://localhost:2380' List of this member's peer URLs to advertise to the rest of the cluster. - --experimental-set-member-localaddr 'false' - Enable using the first specified and non-loopback local address from initial-advertise-peer-urls as the local address when communicating with a peer. --initial-cluster 'default=http://localhost:2380' Initial cluster configuration for bootstrapping. --initial-cluster-state 'new' diff --git a/server/features/etcd_features.go b/server/features/etcd_features.go index 9e68e1b85625..80a2d455c845 100644 --- a/server/features/etcd_features.go +++ b/server/features/etcd_features.go @@ -73,6 +73,12 @@ const ( // main PR: https://github.com/etcd-io/etcd/pull/13508 // Deprecated: Enabled by default in v3.6, to be removed in v3.7. LeaseCheckpointPersist featuregate.Feature = "LeaseCheckpointPersist" + // SetMemberLocalAddr enables using the first specified and non-loopback local address from initial-advertise-peer-urls as the local address when communicating with a peer. + // Requires SetMemberLocalAddr featuragate to be enabled. + // owner: @flawedmatrix + // alpha: v3.6 + // main PR: https://github.com/etcd-io/etcd/pull/17661 + SetMemberLocalAddr featuregate.Feature = "SetMemberLocalAddr" ) var ( @@ -84,6 +90,7 @@ var ( 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. diff --git a/tests/e2e/etcd_config_test.go b/tests/e2e/etcd_config_test.go index 21d587623daf..1a8415d2d9f0 100644 --- a/tests/e2e/etcd_config_test.go +++ b/tests/e2e/etcd_config_test.go @@ -427,7 +427,7 @@ func TestEtcdPeerLocalAddr(t *testing.T) { os.RemoveAll(tempDir) }() - // node 0 (127.0.0.1) does not set `--experimental-set-member-localaddr`, + // node 0 (127.0.0.1) does not set `--feature-gates=SetMemberLocalAddr=true`, // while nodes 1 and nodes 2 do. // // node 0's peer certificate is signed for 127.0.0.1, but it uses the host @@ -437,7 +437,7 @@ func TestEtcdPeerLocalAddr(t *testing.T) { // Both node 1 and node 2's peer certificates are signed for the host IP, // and they also communicate with peers using the host IP (explicitly set // with --initial-advertise-peer-urls and - // --experimental-set-member-localaddr), so node 0 has no issue connecting + // --feature-gates=SetMemberLocalAddr=true), so node 0 has no issue connecting // to them. // // Refer to https://github.com/etcd-io/etcd/issues/17068. @@ -472,7 +472,7 @@ func TestEtcdPeerLocalAddr(t *testing.T) { "--peer-key-file", keyFiles[1], "--peer-trusted-ca-file", caFile, "--peer-client-cert-auth", - "--experimental-set-member-localaddr", + "--feature-gates=SetMemberLocalAddr=true", } }