Skip to content

Commit e23b733

Browse files
chore: support IPv6 fallback in IP autodetection (#423)
1 parent 67416fc commit e23b733

13 files changed

Lines changed: 83 additions & 34 deletions

File tree

server/internal/api/http.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import (
66
"crypto/x509"
77
"errors"
88
"fmt"
9+
"net"
910
"net/http"
1011
"os"
12+
"strconv"
1113

1214
"github.com/pgEdge/control-plane/server/internal/config"
1315
"github.com/rs/zerolog"
@@ -31,7 +33,7 @@ func newHTTPServer(
3133
errCh: make(chan error, 1),
3234
server: &http.Server{
3335
Handler: handler,
34-
Addr: fmt.Sprintf("%s:%d", cfg.BindAddr, cfg.Port),
36+
Addr: net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.Port)),
3537
},
3638
}
3739
}

server/internal/config/config.go

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -161,19 +161,15 @@ func (h HTTP) validate() []error {
161161
return nil
162162
}
163163
var errs []error
164-
if h.BindAddr == "" {
165-
errs = append(errs, errors.New("bind_addr cannot be empty"))
166-
}
167164
if h.Port == 0 {
168165
errs = append(errs, errors.New("port cannot be empty"))
169166
}
170167
return errs
171168
}
172169

173170
var httpDefault = HTTP{
174-
Enabled: true,
175-
BindAddr: "0.0.0.0",
176-
Port: 3000,
171+
Enabled: true,
172+
Port: 3000,
177173
}
178174

179175
type EtcdServer struct {
@@ -443,12 +439,13 @@ func defaultAddresses() ([]string, error) {
443439
return []string{ip.String()}, nil
444440
}
445441

446-
// getFirstIP gets the first non-loopback IPv4 address
442+
// getFirstIP gets the first non-loopback IP address, preferring IPv4.
447443
func getFirstIP() (net.IP, error) {
448444
interfaces, err := net.Interfaces()
449445
if err != nil {
450446
return net.IPv4zero, fmt.Errorf("failed to list interfaces: %w", err)
451447
}
448+
var ipv6 net.IP
452449
for _, iface := range interfaces {
453450
// Skip loopback and down interfaces
454451
if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
@@ -458,7 +455,6 @@ func getFirstIP() (net.IP, error) {
458455
if err != nil {
459456
continue
460457
}
461-
462458
for _, addr := range addrs {
463459
var ip net.IP
464460
switch v := addr.(type) {
@@ -468,21 +464,24 @@ func getFirstIP() (net.IP, error) {
468464
ip = v.IP
469465
}
470466

471-
// Check if it is a valid IPv4 address and not a loopback address
472-
if ip == nil || ip.IsLoopback() {
467+
// Check if it is a valid, routable address
468+
if ip == nil || ip.IsLoopback() || ip.IsLinkLocalUnicast() {
473469
continue
474470
}
475471

476472
// To4() returns nil if the IP is not an IPv4 address
477-
ip = ip.To4()
478-
if ip == nil {
479-
continue
473+
if v4 := ip.To4(); v4 != nil {
474+
return v4, nil
475+
}
476+
// Store first IPv6 address found, keep searching for IPv4
477+
if ipv6 == nil {
478+
ipv6 = ip.To16()
480479
}
481-
482-
// Return the first valid IPv4 address found
483-
return ip, nil
484480
}
485481
}
482+
if ipv6 != nil {
483+
return ipv6, nil
484+
}
486485

487486
return net.IPv4zero, fmt.Errorf("could not find a valid network interface")
488487
}

server/internal/etcd/embedded.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -669,12 +669,19 @@ func embedConfig(cfg config.Config, logger zerolog.Logger) (*embed.Config, error
669669

670670
clientPort := cfg.EtcdServer.ClientPort
671671
peerPort := cfg.EtcdServer.PeerPort
672+
673+
wildcard, err := utils.GetBindAddr()
674+
if err != nil {
675+
return nil, fmt.Errorf("failed to detect bind address: %w", err)
676+
}
677+
672678
c.ListenClientUrls = []url.URL{
673-
{Scheme: "https", Host: fmt.Sprintf("0.0.0.0:%d", clientPort)},
679+
{Scheme: "https", Host: net.JoinHostPort(wildcard, strconv.Itoa(clientPort))},
674680
}
675681
c.ListenPeerUrls = []url.URL{
676-
{Scheme: "https", Host: fmt.Sprintf("0.0.0.0:%d", peerPort)},
682+
{Scheme: "https", Host: net.JoinHostPort(wildcard, strconv.Itoa(peerPort))},
677683
}
684+
678685
clientURLs := make([]url.URL, len(cfg.PeerAddresses))
679686
peerURLs := make([]url.URL, len(cfg.PeerAddresses))
680687
for i, address := range cfg.PeerAddresses {
@@ -714,22 +721,25 @@ func initializationConfig(cfg config.Config, logger zerolog.Logger) (*embed.Conf
714721
// Only bind/advertise localhost for initialization
715722
clientPort := cfg.EtcdServer.ClientPort
716723
peerPort := cfg.EtcdServer.PeerPort
724+
loopback := "127.0.0.1"
725+
717726
c.ListenClientUrls = []url.URL{
718-
{Scheme: "http", Host: fmt.Sprintf("127.0.0.1:%d", clientPort)},
727+
{Scheme: "http", Host: net.JoinHostPort(loopback, strconv.Itoa(clientPort))},
719728
}
720729
c.AdvertiseClientUrls = []url.URL{
721-
{Scheme: "http", Host: fmt.Sprintf("127.0.0.1:%d", clientPort)},
730+
{Scheme: "http", Host: net.JoinHostPort(loopback, strconv.Itoa(clientPort))},
722731
}
732+
723733
c.ListenPeerUrls = []url.URL{
724-
{Scheme: "http", Host: fmt.Sprintf("127.0.0.1:%d", peerPort)},
734+
{Scheme: "http", Host: net.JoinHostPort(loopback, strconv.Itoa(peerPort))},
725735
}
726736
c.AdvertisePeerUrls = []url.URL{
727-
{Scheme: "http", Host: fmt.Sprintf("127.0.0.1:%d", peerPort)},
737+
{Scheme: "http", Host: net.JoinHostPort(loopback, strconv.Itoa(peerPort))},
728738
}
729739
c.InitialCluster = fmt.Sprintf(
730-
"%s=http://127.0.0.1:%d",
740+
"%s=http://%s",
731741
cfg.HostID,
732-
cfg.EtcdServer.PeerPort,
742+
net.JoinHostPort(loopback, strconv.Itoa(cfg.EtcdServer.PeerPort)),
733743
)
734744
c.QuotaBackendBytes = quotaBackendBytes
735745

server/internal/etcd/rbac.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ func addEtcdServerCredentials(
365365
) error {
366366
// Ensure that localhost is included in the addresses
367367
combined := ds.NewSet(addresses...)
368-
combined.Add("127.0.0.1", "localhost")
368+
combined.Add("127.0.0.1", "localhost", "::1")
369369

370370
// Create a cert for the peer server
371371
serverPrincipal, err := certSvc.EtcdServer(ctx,

server/internal/orchestrator/common/golden_test/TestPatroniConfigGenerator/enable_fast_basebackup.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ postgresql:
115115
- checkpoint: fast
116116
restapi:
117117
connect_address: storefront-n1-689qacsi.storefront-database:8888
118-
listen: 0.0.0.0:8888
118+
listen: :8888
119119
allowlist:
120120
- 10.10.0.2
121121
- 10.10.0.3

server/internal/orchestrator/common/golden_test/TestPatroniConfigGenerator/in-place_restore.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ postgresql:
118118
remove_data_directory_on_diverged_timelines: true
119119
restapi:
120120
connect_address: storefront-n1-689qacsi.storefront-database:8888
121-
listen: 0.0.0.0:8888
121+
listen: :8888
122122
allowlist:
123123
- 172.17.0.1/32
124124
- 10.128.165.128/26

server/internal/orchestrator/common/golden_test/TestPatroniConfigGenerator/minimal_swarm.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ postgresql:
113113
remove_data_directory_on_diverged_timelines: true
114114
restapi:
115115
connect_address: storefront-n1-689qacsi.storefront-database:8888
116-
listen: 0.0.0.0:8888
116+
listen: :8888
117117
allowlist:
118118
- 172.17.0.1/32
119119
- 10.128.165.128/26

server/internal/orchestrator/common/golden_test/TestPatroniConfigGenerator/minimal_systemd.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ postgresql:
113113
remove_data_directory_on_diverged_timelines: true
114114
restapi:
115115
connect_address: storefront-n1-689qacsi.storefront-database:8888
116-
listen: 0.0.0.0:8888
116+
listen: :8888
117117
allowlist:
118118
- 10.10.0.2
119119
- 10.10.0.3

server/internal/orchestrator/common/golden_test/TestPatroniConfigGenerator/user_pg_hba_pg_ident_and_scram.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ postgresql:
115115
remove_data_directory_on_diverged_timelines: true
116116
restapi:
117117
connect_address: pghba-n1-689qacsi.pghba-database:8888
118-
listen: 0.0.0.0:8888
118+
listen: :8888
119119
allowlist:
120120
- 172.17.0.1/32
121121
- 10.128.165.128/26

server/internal/orchestrator/common/golden_test/TestPatroniConfigGenerator/with_backup_config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ postgresql:
113113
remove_data_directory_on_diverged_timelines: true
114114
restapi:
115115
connect_address: storefront-n1-689qacsi.storefront-database:8888
116-
listen: 0.0.0.0:8888
116+
listen: :8888
117117
allowlist:
118118
- 172.17.0.1/32
119119
- 10.128.165.128/26

0 commit comments

Comments
 (0)