diff --git a/server/config/config.go b/server/config/config.go index 3feb7d1e52..0c67c18c69 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -18,7 +18,6 @@ import ( "crypto/tls" "encoding/json" "fmt" - "net/url" "os" "path/filepath" "strings" @@ -391,8 +390,12 @@ func (c *Config) Adjust(meta *toml.MetaData, reloading bool) error { configutil.AdjustString(&c.InitialClusterState, defaultInitialClusterState) configutil.AdjustString(&c.InitialClusterToken, defaultInitialClusterToken) + // Join is a comma-separated list of endpoints (see the field comment and + // server/join, which splits it on ","), so validate it per endpoint rather + // than passing the whole list to a single url.Parse, which accepts it as + // one malformed URL with a host of "pd-0:2379,http:". if len(c.Join) > 0 { - if _, err := url.Parse(c.Join); err != nil { + if _, err := parseUrls(c.Join); err != nil { return errors.Errorf("failed to parse join addr:%s, err:%v", c.Join, err) } } diff --git a/server/config/config_test.go b/server/config/config_test.go index b66eb8c130..a7d2232753 100644 --- a/server/config/config_test.go +++ b/server/config/config_test.go @@ -62,6 +62,51 @@ func TestBadFormatJoinAddr(t *testing.T) { re.Error(cfg.Adjust(nil, false)) } +// TestJoinAddr covers that --join accepts the comma-separated endpoint list it +// is documented to take, and still rejects a list containing a bad endpoint. +func TestJoinAddr(t *testing.T) { + testCases := []struct { + name string + join string + wantErr bool + }{ + { + name: "single endpoint", + join: "http://127.0.0.1:2379", + }, + { + name: "two endpoints", + join: "http://127.0.0.1:2379,http://127.0.0.1:2381", + }, + { + name: "three endpoints with mixed schemes", + join: "http://pd-0.pd-peer:2379,https://pd-1.pd-peer:2379,http://[::1]:2379", + }, + { + name: "peer service endpoints", + join: "http://demo-pd-0.demo-pd-peer.demo.svc:2380,http://demo-pd-1.demo-pd-peer.demo.svc:2380", + }, + { + name: "second endpoint has no scheme", + join: "http://127.0.0.1:2379,127.0.0.1:2381", + wantErr: true, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + re := require.New(t) + cfg := NewConfig() + cfg.Join = testCase.join + err := cfg.Adjust(nil, false) + if testCase.wantErr { + re.Error(err) + return + } + re.NoError(err) + }) + } +} + func TestReloadConfig(t *testing.T) { re := require.New(t) opt, err := newTestScheduleOption()