Merge pull request #13011 from lilic/socket-options-file

WIP: client,server: Expose reuse-port and reuse-address so they can be configured via a config file
This commit is contained in:
Piotr Tabor 2021-05-20 13:50:21 +02:00 committed by GitHub
commit e299264cf3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 38 additions and 27 deletions

View File

@ -29,10 +29,11 @@ func AssertEqual(t *testing.T, e, a interface{}, msg ...string) {
return return
} }
s := "" s := ""
if len(msg) > 1 { if len(msg) > 0 {
s = msg[0] + ": " s = msg[0] + ": "
} }
s = fmt.Sprintf("%sexpected %+v, got %+v", s, e, a)
s = fmt.Sprintf("%s:expected %+v, got %+v", s, e, a)
FatalStack(t, s) FatalStack(t, s)
} }

View File

@ -21,12 +21,12 @@ type SocketOpts struct {
// in which case lock on data file could result in unexpected // in which case lock on data file could result in unexpected
// condition. User should take caution to protect against lock race. // condition. User should take caution to protect against lock race.
// [1] https://man7.org/linux/man-pages/man7/socket.7.html // [1] https://man7.org/linux/man-pages/man7/socket.7.html
ReusePort bool ReusePort bool `json:"reuse-port"`
// ReuseAddress enables a socket option SO_REUSEADDR which allows // ReuseAddress enables a socket option SO_REUSEADDR which allows
// binding to an address in `TIME_WAIT` state. Useful to improve MTTR // binding to an address in `TIME_WAIT` state. Useful to improve MTTR
// in cases where etcd slow to restart due to excessive `TIME_WAIT`. // in cases where etcd slow to restart due to excessive `TIME_WAIT`.
// [1] https://man7.org/linux/man-pages/man7/socket.7.html // [1] https://man7.org/linux/man-pages/man7/socket.7.html
ReuseAddress bool ReuseAddress bool `json:"reuse-address"`
} }
func getControls(sopts *SocketOpts) Controls { func getControls(sopts *SocketOpts) Controls {

View File

@ -252,7 +252,7 @@ type Config struct {
GRPCKeepAliveTimeout time.Duration `json:"grpc-keepalive-timeout"` GRPCKeepAliveTimeout time.Duration `json:"grpc-keepalive-timeout"`
// SocketOpts are socket options passed to listener config. // SocketOpts are socket options passed to listener config.
SocketOpts transport.SocketOpts SocketOpts transport.SocketOpts `json:"socket-options"`
// PreVote is true to enable Raft Pre-Vote. // PreVote is true to enable Raft Pre-Vote.
// If enabled, Raft runs an additional election phase // If enabled, Raft runs an additional election phase
@ -449,7 +449,10 @@ func NewConfig() *Config {
GRPCKeepAliveInterval: DefaultGRPCKeepAliveInterval, GRPCKeepAliveInterval: DefaultGRPCKeepAliveInterval,
GRPCKeepAliveTimeout: DefaultGRPCKeepAliveTimeout, GRPCKeepAliveTimeout: DefaultGRPCKeepAliveTimeout,
SocketOpts: transport.SocketOpts{}, SocketOpts: transport.SocketOpts{
ReusePort: false,
ReuseAddress: false,
},
TickMs: 100, TickMs: 100,
ElectionMs: 1000, ElectionMs: 1000,

View File

@ -25,6 +25,7 @@ import (
"time" "time"
"go.etcd.io/etcd/client/pkg/v3/srv" "go.etcd.io/etcd/client/pkg/v3/srv"
"go.etcd.io/etcd/client/pkg/v3/testutil"
"go.etcd.io/etcd/client/pkg/v3/transport" "go.etcd.io/etcd/client/pkg/v3/transport"
"go.etcd.io/etcd/client/pkg/v3/types" "go.etcd.io/etcd/client/pkg/v3/types"
@ -40,12 +41,13 @@ func TestConfigFileOtherFields(t *testing.T) {
ctls := securityConfig{TrustedCAFile: "cca", CertFile: "ccert", KeyFile: "ckey"} ctls := securityConfig{TrustedCAFile: "cca", CertFile: "ccert", KeyFile: "ckey"}
ptls := securityConfig{TrustedCAFile: "pca", CertFile: "pcert", KeyFile: "pkey"} ptls := securityConfig{TrustedCAFile: "pca", CertFile: "pcert", KeyFile: "pkey"}
yc := struct { yc := struct {
ClientSecurityCfgFile securityConfig `json:"client-transport-security"` ClientSecurityCfgFile securityConfig `json:"client-transport-security"`
PeerSecurityCfgFile securityConfig `json:"peer-transport-security"` PeerSecurityCfgFile securityConfig `json:"peer-transport-security"`
ForceNewCluster bool `json:"force-new-cluster"` ForceNewCluster bool `json:"force-new-cluster"`
Logger string `json:"logger"` Logger string `json:"logger"`
LogOutputs []string `json:"log-outputs"` LogOutputs []string `json:"log-outputs"`
Debug bool `json:"debug"` Debug bool `json:"debug"`
SocketOpts transport.SocketOpts `json:"socket-options"`
}{ }{
ctls, ctls,
ptls, ptls,
@ -53,6 +55,9 @@ func TestConfigFileOtherFields(t *testing.T) {
"zap", "zap",
[]string{"/dev/null"}, []string{"/dev/null"},
false, false,
transport.SocketOpts{
ReusePort: true,
},
} }
b, err := yaml.Marshal(&yc) b, err := yaml.Marshal(&yc)
@ -68,16 +73,18 @@ func TestConfigFileOtherFields(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if !cfg.ForceNewCluster {
t.Errorf("ForceNewCluster = %v, want %v", cfg.ForceNewCluster, true)
}
if !ctls.equals(&cfg.ClientTLSInfo) { if !ctls.equals(&cfg.ClientTLSInfo) {
t.Errorf("ClientTLS = %v, want %v", cfg.ClientTLSInfo, ctls) t.Errorf("ClientTLS = %v, want %v", cfg.ClientTLSInfo, ctls)
} }
if !ptls.equals(&cfg.PeerTLSInfo) { if !ptls.equals(&cfg.PeerTLSInfo) {
t.Errorf("PeerTLS = %v, want %v", cfg.PeerTLSInfo, ptls) t.Errorf("PeerTLS = %v, want %v", cfg.PeerTLSInfo, ptls)
} }
testutil.AssertEqual(t, true, cfg.ForceNewCluster, "ForceNewCluster does not match")
testutil.AssertEqual(t, true, cfg.SocketOpts.ReusePort, "ReusePort does not match")
testutil.AssertEqual(t, false, cfg.SocketOpts.ReuseAddress, "ReuseAddress does not match")
} }
// TestUpdateDefaultClusterFromName ensures that etcd can start with 'etcd --name=abc'. // TestUpdateDefaultClusterFromName ensures that etcd can start with 'etcd --name=abc'.

22
test.sh
View File

@ -1,35 +1,35 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Run all etcd tests # Run all etcd tests
# ./test # ./test.sh
# ./test -v # ./test.sh -v
# #
# #
# Run specified test pass # Run specified test pass
# #
# $ PASSES=unit ./test # $ PASSES=unit ./test.sh
# $ PASSES=integration ./test # $ PASSES=integration ./test.sh
# #
# #
# Run tests for one package # Run tests for one package
# Each pass has different default timeout, if you just run tests in one package or 1 test case then you can set TIMEOUT # Each pass has different default timeout, if you just run tests in one package or 1 test case then you can set TIMEOUT
# flag for different expectation # flag for different expectation
# #
# $ PASSES=unit PKG=./wal TIMEOUT=1m ./test # $ PASSES=unit PKG=./wal TIMEOUT=1m ./test.sh
# $ PASSES=integration PKG=./clientv3 TIMEOUT=1m ./test # $ PASSES=integration PKG=./clientv3 TIMEOUT=1m ./test.sh
# #
# Run specified unit tests in one package # Run specified unit tests in one package
# To run all the tests with prefix of "TestNew", set "TESTCASE=TestNew "; # To run all the tests with prefix of "TestNew", set "TESTCASE=TestNew ";
# to run only "TestNew", set "TESTCASE="\bTestNew\b"" # to run only "TestNew", set "TESTCASE="\bTestNew\b""
# #
# $ PASSES=unit PKG=./wal TESTCASE=TestNew TIMEOUT=1m ./test # $ PASSES=unit PKG=./wal TESTCASE=TestNew TIMEOUT=1m ./test.sh
# $ PASSES=unit PKG=./wal TESTCASE="\bTestNew\b" TIMEOUT=1m ./test # $ PASSES=unit PKG=./wal TESTCASE="\bTestNew\b" TIMEOUT=1m ./test.sh
# $ PASSES=integration PKG=./client/integration TESTCASE="\bTestV2NoRetryEOF\b" TIMEOUT=1m ./test # $ PASSES=integration PKG=./client/integration TESTCASE="\bTestV2NoRetryEOF\b" TIMEOUT=1m ./test.sh
# #
# #
# Run code coverage # Run code coverage
# COVERDIR must either be a absolute path or a relative path to the etcd root # COVERDIR must either be a absolute path or a relative path to the etcd root
# $ COVERDIR=coverage PASSES="build build_cov cov" ./test # $ COVERDIR=coverage PASSES="build build_cov cov" ./test.sh
# $ go tool cover -html ./coverage/cover.out # $ go tool cover -html ./coverage/cover.out
set -e set -e
set -o pipefail set -o pipefail
@ -290,7 +290,7 @@ function cov_pass {
fi fi
if [ ! -f "bin/etcd_test" ]; then if [ ! -f "bin/etcd_test" ]; then
log_error "etcd_test binary not found. Call: PASSES='build_cov' ./test" log_error "etcd_test binary not found. Call: PASSES='build_cov' ./test.sh"
return 255 return 255
fi fi