Skip to content

Commit 9dc2b7e

Browse files
fix(config-cache): use netip.Addr to unify the IPv6 (#4269)
1 parent f80b71c commit 9dc2b7e

File tree

2 files changed

+90
-4
lines changed

2 files changed

+90
-4
lines changed

Diff for: pkg/service/configcache/service.go

+22-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package configcache
44

55
import (
66
"context"
7+
"net/netip"
78
"sync"
89
"time"
910

@@ -80,7 +81,18 @@ func (svc *Service) Read(clusterID uuid.UUID, host string) (NodeConfig, error) {
8081
return emptyConfig, err
8182
}
8283

83-
rawHostConfig, ok := clusterConfig.Load(host)
84+
hostKey := host
85+
// Remove leading '[' and trailing ']' if present.
86+
// netip.ParseAddr(bracketedIP) leaves brackets.
87+
// Need to remove it.
88+
if host != "" && host[0] == '[' && host[len(host)-1] == ']' {
89+
host = host[1 : len(host)-1]
90+
}
91+
if addr, err := netip.ParseAddr(host); err == nil {
92+
hostKey = addr.String()
93+
}
94+
95+
rawHostConfig, ok := clusterConfig.Load(hostKey)
8496
if !ok {
8597
return emptyConfig, ErrNoHostConfig
8698
}
@@ -192,17 +204,23 @@ func (svc *Service) updateSingle(ctx context.Context, c *cluster.Cluster) bool {
192204

193205
for _, host := range client.Config().Hosts {
194206
hostsWg.Add(1)
207+
hostKey := host
208+
209+
parsedIP, err := netip.ParseAddr(host)
210+
if err == nil {
211+
hostKey = parsedIP.String()
212+
}
195213

196-
perHostLogger := logger.Named("Cluster host config update").With("host", host)
214+
perHostLogger := logger.Named("Cluster host config update").With("host", host, "hostKey", hostKey)
197215
go func() {
198216
defer hostsWg.Done()
199217

200-
config, err := svc.retrieveNodeConfig(ctx, host, client, c)
218+
config, err := svc.retrieveNodeConfig(ctx, hostKey, client, c)
201219
if err != nil {
202220
perHostLogger.Error(ctx, "Couldn't read cluster host config", "error", err)
203221
return
204222
}
205-
clusterConfig.Store(host, config)
223+
clusterConfig.Store(hostKey, config)
206224
}()
207225
}
208226
hostsWg.Wait()

Diff for: pkg/service/configcache/service_test.go

+68
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"context"
77
"crypto/sha256"
88
"encoding/json"
9+
"net/netip"
910
"sync"
1011
"testing"
1112
"time"
@@ -222,6 +223,73 @@ func TestServiceForceUpdateCluster(t *testing.T) {
222223
})
223224
}
224225

226+
func TestService_Read_IPv6Normalization(t *testing.T) {
227+
// Define a canonical IPv6 representation
228+
key := "2001:0db8:0000:0000:0000:0000:0000:0001"
229+
parsedKey, err := netip.ParseAddr(key)
230+
if err != nil {
231+
t.Fatal(err)
232+
}
233+
234+
// Assume that our system normalizes IPv6 addresses to the canonical form.
235+
// Create the configuration for the canonical IPv6 address.
236+
nodeConfig := NodeConfig{
237+
NodeInfo: &scyllaclient.NodeInfo{
238+
AgentVersion: "expectedVersion",
239+
},
240+
}
241+
configHash, err := nodeConfig.sha256hash()
242+
if err != nil {
243+
t.Fatal(err)
244+
}
245+
246+
clusterID := uuid.MustRandom()
247+
// Prepopulate the service config with the canonical representation as the key.
248+
initialState := convertMapToSyncMap(map[any]any{
249+
clusterID.String(): convertMapToSyncMap(map[any]any{
250+
parsedKey.String(): nodeConfig,
251+
}),
252+
})
253+
254+
// Define several valid IPv6 representations for the same host.
255+
testCases := []struct {
256+
name string
257+
hostKey string
258+
}{
259+
{"Fully Expanded", "2001:0db8:0000:0000:0000:0000:0000:0001"},
260+
{"Uncompressed", "2001:db8:0:0:0:0:0:1"},
261+
{"Compressed", "2001:db8::1"},
262+
{"Uppercase Variant", "2001:DB8::1"},
263+
{"Bracketed", "[2001:db8::1]"},
264+
}
265+
266+
svc := Service{
267+
svcConfig: DefaultConfig(),
268+
clusterSvc: &mockClusterServicer{},
269+
scyllaClient: mockProviderFunc,
270+
secretsStore: &mockStore{},
271+
configs: initialState,
272+
}
273+
274+
for _, tc := range testCases {
275+
t.Run(tc.name, func(t *testing.T) {
276+
// When
277+
conf, err := svc.Read(clusterID, tc.hostKey)
278+
// Then
279+
if err != nil {
280+
t.Fatalf("unexpected error: %v", err)
281+
}
282+
h, err := conf.sha256hash()
283+
if err != nil {
284+
t.Fatalf("error creating hash: %v", err)
285+
}
286+
if h != configHash {
287+
t.Fatalf("expected hash %v, got %v", configHash, h)
288+
}
289+
})
290+
}
291+
}
292+
225293
func (nc NodeConfig) sha256hash() (hash [32]byte, err error) {
226294
data, err := json.Marshal(nc)
227295
if err != nil {

0 commit comments

Comments
 (0)