Improve detecting duplicate backend URLs in etcd configuration.

This commit is contained in:
Joachim Bauch 2025-07-17 12:51:04 +02:00
commit 8375b985e8
No known key found for this signature in database
GPG key ID: 77C1D22D53E15F02
2 changed files with 125 additions and 4 deletions

View file

@ -454,7 +454,7 @@ type BackendInformationEtcd struct {
SessionLimit uint64 `json:"sessionlimit,omitempty"`
}
func (p *BackendInformationEtcd) CheckValid() error {
func (p *BackendInformationEtcd) CheckValid() (err error) {
if p.Secret == "" {
return fmt.Errorf("secret missing")
}
@ -462,17 +462,31 @@ func (p *BackendInformationEtcd) CheckValid() error {
if len(p.Urls) > 0 {
slices.Sort(p.Urls)
p.Urls = slices.Compact(p.Urls)
for idx, u := range p.Urls {
seen := make(map[string]bool)
outIdx := 0
for _, u := range p.Urls {
parsedUrl, err := url.Parse(u)
if err != nil {
return fmt.Errorf("invalid url %s: %w", u, err)
}
if strings.Contains(parsedUrl.Host, ":") && hasStandardPort(parsedUrl) {
parsedUrl.Host = parsedUrl.Hostname()
p.Urls[idx] = parsedUrl.String()
u = parsedUrl.String()
p.Urls[outIdx] = u
} else {
p.Urls[outIdx] = u
}
if seen[u] {
continue
}
seen[u] = true
p.parsedUrls = append(p.parsedUrls, parsedUrl)
outIdx++
}
if len(p.Urls) != outIdx {
clear(p.Urls[outIdx:])
p.Urls = p.Urls[:outIdx]
}
} else if p.Url != "" {
parsedUrl, err := url.Parse(p.Url)

View file

@ -72,3 +72,110 @@ func TestValidNumbers(t *testing.T) {
assert.False(isValidNumber(number), "number %s should not be valid", number)
}
}
func TestValidateBackendInformationEtcd(t *testing.T) {
t.Parallel()
assert := assert.New(t)
testcases := []struct {
b BackendInformationEtcd
expectedError string
expectedUrls []string
}{
{
b: BackendInformationEtcd{},
expectedError: "secret missing",
},
{
b: BackendInformationEtcd{
Secret: "verysecret",
},
expectedError: "urls missing",
},
{
b: BackendInformationEtcd{
Secret: "verysecret",
Url: "https://foo\n",
},
expectedError: "invalid url",
},
{
b: BackendInformationEtcd{
Secret: "verysecret",
Urls: []string{"https://foo\n"},
},
expectedError: "invalid url",
},
{
b: BackendInformationEtcd{
Secret: "verysecret",
Urls: []string{"https://foo", "https://foo\n"},
},
expectedError: "invalid url",
},
{
b: BackendInformationEtcd{
Secret: "verysecret",
Url: "https://foo:443",
},
expectedUrls: []string{"https://foo"},
},
{
b: BackendInformationEtcd{
Secret: "verysecret",
Urls: []string{"https://foo:443"},
},
expectedUrls: []string{"https://foo"},
},
{
b: BackendInformationEtcd{
Secret: "verysecret",
Url: "https://foo:8443",
},
expectedUrls: []string{"https://foo:8443"},
},
{
b: BackendInformationEtcd{
Secret: "verysecret",
Urls: []string{"https://foo:8443"},
},
expectedUrls: []string{"https://foo:8443"},
},
{
b: BackendInformationEtcd{
Secret: "verysecret",
Urls: []string{"https://foo", "https://bar", "https://foo"},
},
expectedUrls: []string{"https://bar", "https://foo"},
},
{
b: BackendInformationEtcd{
Secret: "verysecret",
Urls: []string{"https://foo", "https://bar", "https://foo:443", "https://zaz"},
},
expectedUrls: []string{"https://bar", "https://foo", "https://zaz"},
},
{
b: BackendInformationEtcd{
Secret: "verysecret",
Urls: []string{"https://foo:443", "https://bar", "https://foo", "https://zaz"},
},
expectedUrls: []string{"https://bar", "https://foo", "https://zaz"},
},
}
for idx, tc := range testcases {
if tc.expectedError == "" {
if assert.NoError(tc.b.CheckValid(), "failed for testcase %d", idx) {
assert.Equal(tc.expectedUrls, tc.b.Urls, "failed for testcase %d", idx)
var urls []string
for _, u := range tc.b.parsedUrls {
urls = append(urls, u.String())
}
assert.Equal(tc.expectedUrls, urls, "failed for testcase %d", idx)
}
} else {
assert.ErrorContains(tc.b.CheckValid(), tc.expectedError, "failed for testcase %d, got %+v", idx, tc.b.parsedUrls)
}
}
}