fixes auto_join for mDNS provider (#25080)

* fixes auto_join for mDNS provider

* adds a function to format addresses returned by go-discover

* adds copyright header in raft_rest.go

* Adds changelog file for PR #25080, godoc for TestFormatDiscoveredAddr

---------

Co-authored-by: Violet Hynes <violet.hynes@hashicorp.com>
This commit is contained in:
aubrich
2024-06-10 15:22:03 +02:00
committed by GitHub
parent f7c16796ed
commit d64856c6c9
3 changed files with 57 additions and 6 deletions

3
changelog/25080.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:bug
storage/raft: Fix auto_join not working with mDNS provider.
```

View File

@@ -8,6 +8,7 @@ import (
"encoding/base64"
"errors"
"fmt"
"net"
"net/http"
"net/url"
"strings"
@@ -1227,17 +1228,15 @@ func (c *Core) raftLeaderInfo(leaderInfo *raft.LeaderJoinInfo, disco *discover.D
// default to 8200 when no port is provided
port = 8200
}
// Addrs returns either IPv4 or IPv6 address, without scheme or port
// Addrs returns either IPv4 or IPv6 address, without scheme and most of them without port
// IPv6 can be explicit such as "[::1]" or implicit "::1"
clusterIPs, err := disco.Addrs(leaderInfo.AutoJoin, c.logger.StandardLogger(nil))
if err != nil {
return nil, fmt.Errorf("failed to parse addresses from auto-join metadata: %w", err)
}
for _, ip := range clusterIPs {
if strings.Count(ip, ":") >= 2 && !strings.HasPrefix(ip, "[") {
// An IPv6 address in implicit form, however we need it in explicit form to use in a URL.
ip = fmt.Sprintf("[%s]", ip)
}
u := fmt.Sprintf("%s://%s:%d", scheme, ip, port)
addr := formatDiscoveredAddr(ip, port)
u := fmt.Sprintf("%s://%s", scheme, addr)
info := *leaderInfo
info.LeaderAPIAddr = u
ret = append(ret, &info)
@@ -1459,3 +1458,19 @@ func newDiscover() (*discover.Discover, error) {
discover.WithProviders(providers),
)
}
// formatDiscoveredAddr joins ip and port if addr does not already contain a port
func formatDiscoveredAddr(addr string, defaultPort uint) string {
// addr is an implicit IPv6 address
if !strings.HasPrefix(addr, "[") && strings.Count(addr, ":") > 1 {
return fmt.Sprintf("[%s]:%d", addr, defaultPort)
}
ip, port, err := net.SplitHostPort(addr)
if err != nil {
return fmt.Sprintf("%s:%d", addr, defaultPort)
}
if strings.ContainsRune(ip, ':') {
ip = fmt.Sprintf("[%s]", ip)
}
return fmt.Sprintf("%s:%s", ip, port)
}

33
vault/raft_test.go Normal file
View File

@@ -0,0 +1,33 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package vault
import (
"testing"
)
// TestFormatDiscoveredAddr validates that the string returned by formatDiscoveredAddr always respect the format `host:port`.
func TestFormatDiscoveredAddr(t *testing.T) {
type TestCase struct {
addr string
port uint
res string
}
cases := []TestCase{
{addr: "127.0.0.1", port: uint(8200), res: "127.0.0.1:8200"},
{addr: "192.168.137.1:8201", port: uint(8200), res: "192.168.137.1:8201"},
{addr: "fe80::aa5e:45ff:fe54:c6ce", port: uint(8200), res: "[fe80::aa5e:45ff:fe54:c6ce]:8200"},
{addr: "::1", port: uint(8200), res: "[::1]:8200"},
{addr: "[::1]", port: uint(8200), res: "[::1]:8200"},
{addr: "[::1]:8201", port: uint(8200), res: "[::1]:8201"},
{addr: "[fe80::aa5e:45ff:fe54:c6ce]", port: uint(8200), res: "[fe80::aa5e:45ff:fe54:c6ce]:8200"},
{addr: "[fe80::aa5e:45ff:fe54:c6ce]:8201", port: uint(8200), res: "[fe80::aa5e:45ff:fe54:c6ce]:8201"},
}
for i, c := range cases {
res := formatDiscoveredAddr(c.addr, c.port)
if res != c.res {
t.Errorf("case %d result shoud be \"%s\" but is \"%s\"", i, c.res, res)
}
}
}