github.com/cilium/cilium@v1.16.2/pkg/node/manager/manager_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package manager 5 6 import ( 7 "context" 8 "encoding/json" 9 "fmt" 10 "io/fs" 11 "net" 12 "net/netip" 13 "os" 14 "path/filepath" 15 "strings" 16 "sync" 17 "testing" 18 "time" 19 20 "github.com/cilium/hive/cell" 21 "github.com/cilium/hive/hivetest" 22 "github.com/cilium/statedb" 23 "github.com/stretchr/testify/assert" 24 "github.com/stretchr/testify/require" 25 26 fakeTypes "github.com/cilium/cilium/pkg/datapath/fake/types" 27 "github.com/cilium/cilium/pkg/datapath/iptables/ipset" 28 datapath "github.com/cilium/cilium/pkg/datapath/types" 29 "github.com/cilium/cilium/pkg/hive" 30 "github.com/cilium/cilium/pkg/hive/health" 31 "github.com/cilium/cilium/pkg/hive/health/types" 32 "github.com/cilium/cilium/pkg/identity" 33 "github.com/cilium/cilium/pkg/inctimer" 34 "github.com/cilium/cilium/pkg/ipcache" 35 ipcacheTypes "github.com/cilium/cilium/pkg/ipcache/types" 36 "github.com/cilium/cilium/pkg/labels" 37 "github.com/cilium/cilium/pkg/lock" 38 "github.com/cilium/cilium/pkg/node" 39 "github.com/cilium/cilium/pkg/node/addressing" 40 nodeTypes "github.com/cilium/cilium/pkg/node/types" 41 "github.com/cilium/cilium/pkg/option" 42 "github.com/cilium/cilium/pkg/source" 43 testidentity "github.com/cilium/cilium/pkg/testutils/identity" 44 ) 45 46 type nodeEvent struct { 47 event string 48 prefix netip.Prefix 49 } 50 51 type ipcacheMock struct { 52 events chan nodeEvent 53 } 54 55 func newIPcacheMock() *ipcacheMock { 56 return &ipcacheMock{ 57 events: make(chan nodeEvent, 1024), 58 } 59 } 60 61 func AddrOrPrefixToIP(ip string) (netip.Prefix, error) { 62 prefix, err := netip.ParsePrefix(ip) 63 if err != nil { 64 addr, err := netip.ParseAddr(ip) 65 if err != nil { 66 return netip.Prefix{}, err 67 } 68 return addr.Prefix(prefix.Bits()) 69 } 70 71 return prefix, err 72 } 73 74 func (i *ipcacheMock) Upsert(ip string, hostIP net.IP, hostKey uint8, k8sMeta *ipcache.K8sMetadata, newIdentity ipcache.Identity) (bool, error) { 75 addr, err := AddrOrPrefixToIP(ip) 76 if err != nil { 77 i.events <- nodeEvent{fmt.Sprintf("upsert failed: %s", err), addr} 78 return false, err 79 } 80 i.events <- nodeEvent{"upsert", addr} 81 return false, nil 82 } 83 84 func (i *ipcacheMock) Delete(ip string, source source.Source) bool { 85 addr, err := AddrOrPrefixToIP(ip) 86 if err != nil { 87 i.events <- nodeEvent{fmt.Sprintf("delete failed: %s", err), addr} 88 return false 89 } 90 i.events <- nodeEvent{"delete", addr} 91 return false 92 } 93 94 func (i *ipcacheMock) GetMetadataSourceByPrefix(prefix netip.Prefix) source.Source { 95 return source.Unspec 96 } 97 func (i *ipcacheMock) UpsertMetadata(prefix netip.Prefix, src source.Source, resource ipcacheTypes.ResourceID, aux ...ipcache.IPMetadata) { 98 i.Upsert(prefix.String(), nil, 0, nil, ipcache.Identity{}) 99 } 100 func (i *ipcacheMock) OverrideIdentity(prefix netip.Prefix, identityLabels labels.Labels, src source.Source, resource ipcacheTypes.ResourceID) { 101 i.UpsertMetadata(prefix, src, resource) 102 } 103 104 func (i *ipcacheMock) RemoveMetadata(prefix netip.Prefix, resource ipcacheTypes.ResourceID, aux ...ipcache.IPMetadata) { 105 i.Delete(prefix.String(), source.CustomResource) 106 } 107 108 func (i *ipcacheMock) RemoveIdentityOverride(prefix netip.Prefix, identityLabels labels.Labels, resource ipcacheTypes.ResourceID) { 109 i.Delete(prefix.String(), source.CustomResource) 110 } 111 112 type ipsetMock struct { 113 v4 map[string]struct{} 114 v6 map[string]struct{} 115 } 116 117 func newIPSetMock() *ipsetMock { 118 return &ipsetMock{ 119 v4: make(map[string]struct{}), 120 v6: make(map[string]struct{}), 121 } 122 } 123 124 type ipsetInitializerMock struct{} 125 126 func (i *ipsetInitializerMock) InitDone() { 127 } 128 129 func (i *ipsetMock) NewInitializer() ipset.Initializer { 130 return &ipsetInitializerMock{} 131 } 132 133 func (i *ipsetMock) AddToIPSet(name string, family ipset.Family, addrs ...netip.Addr) { 134 for _, addr := range addrs { 135 if name == ipset.CiliumNodeIPSetV4 && family == ipset.INetFamily { 136 i.v4[addr.String()] = struct{}{} 137 } else if name == ipset.CiliumNodeIPSetV6 && family == ipset.INet6Family { 138 i.v6[addr.String()] = struct{}{} 139 } 140 } 141 } 142 143 func (i *ipsetMock) RemoveFromIPSet(name string, addrs ...netip.Addr) { 144 for _, addr := range addrs { 145 if name == ipset.CiliumNodeIPSetV4 { 146 delete(i.v4, addr.String()) 147 } else if name == ipset.CiliumNodeIPSetV6 { 148 delete(i.v6, addr.String()) 149 } 150 } 151 } 152 153 func ipsetContains(ipsetMgr *ipsetMock, setName string, addr string) (bool, error) { 154 switch setName { 155 case ipset.CiliumNodeIPSetV4: 156 _, found := ipsetMgr.v4[addr] 157 return found, nil 158 case ipset.CiliumNodeIPSetV6: 159 _, found := ipsetMgr.v6[addr] 160 return found, nil 161 default: 162 return false, fmt.Errorf("unexpected ipset name %s", setName) 163 } 164 } 165 166 type signalNodeHandler struct { 167 EnableNodeAddEvent bool 168 NodeAddEvent chan nodeTypes.Node 169 NodeAddEventError error 170 NodeUpdateEvent chan nodeTypes.Node 171 NodeUpdateEventError error 172 EnableNodeUpdateEvent bool 173 NodeDeleteEvent chan nodeTypes.Node 174 NodeDeleteEventError error 175 EnableNodeDeleteEvent bool 176 NodeValidateImplementationEvent chan nodeTypes.Node 177 NodeValidateImplementationEventError error 178 EnableNodeValidateImplementationEvent bool 179 } 180 181 func newSignalNodeHandler() *signalNodeHandler { 182 return &signalNodeHandler{ 183 NodeAddEvent: make(chan nodeTypes.Node, 10), 184 NodeUpdateEvent: make(chan nodeTypes.Node, 10), 185 NodeDeleteEvent: make(chan nodeTypes.Node, 10), 186 NodeValidateImplementationEvent: make(chan nodeTypes.Node, 4096), 187 } 188 } 189 190 func (s *signalNodeHandler) Name() string { 191 return "manager_test:signalNodeHandler" 192 } 193 194 func (n *signalNodeHandler) NodeAdd(newNode nodeTypes.Node) error { 195 if n.EnableNodeAddEvent { 196 n.NodeAddEvent <- newNode 197 } 198 return n.NodeAddEventError 199 } 200 201 func (n *signalNodeHandler) NodeUpdate(oldNode, newNode nodeTypes.Node) error { 202 if n.EnableNodeUpdateEvent { 203 n.NodeUpdateEvent <- newNode 204 } 205 return n.NodeUpdateEventError 206 } 207 208 func (n *signalNodeHandler) NodeDelete(node nodeTypes.Node) error { 209 if n.EnableNodeDeleteEvent { 210 n.NodeDeleteEvent <- node 211 } 212 return n.NodeDeleteEventError 213 } 214 215 func (n *signalNodeHandler) AllNodeValidateImplementation() { 216 } 217 218 func (n *signalNodeHandler) NodeValidateImplementation(node nodeTypes.Node) error { 219 if n.EnableNodeValidateImplementationEvent { 220 n.NodeValidateImplementationEvent <- node 221 } 222 return n.NodeValidateImplementationEventError 223 } 224 225 func (n *signalNodeHandler) NodeConfigurationChanged(config datapath.LocalNodeConfiguration) error { 226 return nil 227 } 228 229 func setup(tb testing.TB) { 230 node.SetTestLocalNodeStore() 231 232 tb.Cleanup(func() { 233 node.UnsetTestLocalNodeStore() 234 }) 235 } 236 237 func TestNodeLifecycle(t *testing.T) { 238 setup(t) 239 240 dp := newSignalNodeHandler() 241 dp.EnableNodeAddEvent = true 242 dp.EnableNodeUpdateEvent = true 243 dp.EnableNodeDeleteEvent = true 244 ipcacheMock := newIPcacheMock() 245 h, _ := cell.NewSimpleHealth() 246 mngr, err := New(&option.DaemonConfig{ConfigPatchMutex: new(lock.RWMutex)}, ipcacheMock, newIPSetMock(), nil, NewNodeMetrics(), h) 247 mngr.Subscribe(dp) 248 require.NoError(t, err) 249 250 n1 := nodeTypes.Node{Name: "node1", Cluster: "c1", IPAddresses: []nodeTypes.Address{ 251 { 252 Type: addressing.NodeInternalIP, 253 IP: net.ParseIP("10.0.0.1"), 254 }, 255 }} 256 mngr.NodeUpdated(n1) 257 258 select { 259 case nodeEvent := <-dp.NodeAddEvent: 260 require.Equal(t, n1, nodeEvent) 261 case nodeEvent := <-dp.NodeUpdateEvent: 262 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 263 case nodeEvent := <-dp.NodeDeleteEvent: 264 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 265 case <-time.After(3 * time.Second): 266 t.Errorf("timeout while waiting for NodeAdd() event for node1") 267 } 268 269 n2 := nodeTypes.Node{Name: "node2", Cluster: "c1", IPAddresses: []nodeTypes.Address{ 270 { 271 Type: addressing.NodeInternalIP, 272 IP: net.ParseIP("10.0.0.2"), 273 }, 274 }} 275 mngr.NodeUpdated(n2) 276 277 select { 278 case nodeEvent := <-dp.NodeAddEvent: 279 require.Equal(t, n2, nodeEvent) 280 case nodeEvent := <-dp.NodeUpdateEvent: 281 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 282 case nodeEvent := <-dp.NodeDeleteEvent: 283 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 284 case <-time.After(3 * time.Second): 285 t.Errorf("timeout while waiting for NodeUpdate() event for node2") 286 } 287 288 nodes := mngr.GetNodes() 289 n, ok := nodes[n1.Identity()] 290 require.True(t, ok) 291 require.Equal(t, n1, n) 292 293 mngr.NodeDeleted(n1) 294 select { 295 case nodeEvent := <-dp.NodeDeleteEvent: 296 require.Equal(t, n1, nodeEvent) 297 case nodeEvent := <-dp.NodeAddEvent: 298 t.Errorf("Unexpected NodeAdd() event %#v", nodeEvent) 299 case nodeEvent := <-dp.NodeUpdateEvent: 300 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 301 case <-time.After(3 * time.Second): 302 t.Errorf("timeout while waiting for NodeDelete() event for node1") 303 } 304 nodes = mngr.GetNodes() 305 _, ok = nodes[n1.Identity()] 306 require.False(t, ok) 307 308 err = mngr.Stop(context.TODO()) 309 require.NoError(t, err) 310 } 311 312 func TestMultipleSources(t *testing.T) { 313 setup(t) 314 315 dp := newSignalNodeHandler() 316 dp.EnableNodeAddEvent = true 317 dp.EnableNodeUpdateEvent = true 318 dp.EnableNodeDeleteEvent = true 319 ipcacheMock := newIPcacheMock() 320 h, _ := cell.NewSimpleHealth() 321 mngr, err := New(&option.DaemonConfig{ConfigPatchMutex: new(lock.RWMutex)}, ipcacheMock, newIPSetMock(), nil, NewNodeMetrics(), h) 322 require.NoError(t, err) 323 mngr.Subscribe(dp) 324 defer mngr.Stop(context.TODO()) 325 326 n1k8s := nodeTypes.Node{Name: "node1", Cluster: "c1", Source: source.Kubernetes, IPAddresses: []nodeTypes.Address{ 327 { 328 Type: addressing.NodeInternalIP, 329 IP: net.ParseIP("10.0.0.1"), 330 }, 331 }} 332 mngr.NodeUpdated(n1k8s) 333 select { 334 case nodeEvent := <-dp.NodeAddEvent: 335 require.Equal(t, n1k8s, nodeEvent) 336 case nodeEvent := <-dp.NodeUpdateEvent: 337 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 338 case nodeEvent := <-dp.NodeDeleteEvent: 339 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 340 case <-time.After(3 * time.Second): 341 t.Errorf("timeout while waiting for NodeAdd() event for node1") 342 } 343 344 // agent can overwrite kubernetes 345 n1agent := nodeTypes.Node{Name: "node1", Cluster: "c1", Source: source.Local, IPAddresses: []nodeTypes.Address{ 346 { 347 Type: addressing.NodeInternalIP, 348 IP: net.ParseIP("10.0.0.1"), 349 }, 350 }} 351 mngr.NodeUpdated(n1agent) 352 select { 353 case nodeEvent := <-dp.NodeUpdateEvent: 354 require.Equal(t, n1agent, nodeEvent) 355 case nodeEvent := <-dp.NodeAddEvent: 356 t.Errorf("Unexpected NodeAdd() event %#v", nodeEvent) 357 case nodeEvent := <-dp.NodeDeleteEvent: 358 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 359 case <-time.After(3 * time.Second): 360 t.Errorf("timeout while waiting for NodeUpdate() event for node1") 361 } 362 363 // kubernetes cannot overwrite local node 364 mngr.NodeUpdated(n1k8s) 365 select { 366 case nodeEvent := <-dp.NodeAddEvent: 367 t.Errorf("Unexpected NodeAdd() event %#v", nodeEvent) 368 case nodeEvent := <-dp.NodeUpdateEvent: 369 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 370 case nodeEvent := <-dp.NodeDeleteEvent: 371 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 372 case <-time.After(100 * time.Millisecond): 373 } 374 375 // delete from kubernetes, should not remove local node 376 mngr.NodeDeleted(n1k8s) 377 select { 378 case nodeEvent := <-dp.NodeAddEvent: 379 t.Errorf("Unexpected NodeAdd() event %#v", nodeEvent) 380 case nodeEvent := <-dp.NodeUpdateEvent: 381 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 382 case nodeEvent := <-dp.NodeDeleteEvent: 383 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 384 case <-time.After(100 * time.Millisecond): 385 } 386 387 mngr.NodeDeleted(n1agent) 388 select { 389 case nodeEvent := <-dp.NodeAddEvent: 390 t.Errorf("Unexpected NodeAdd() event %#v", nodeEvent) 391 case nodeEvent := <-dp.NodeUpdateEvent: 392 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 393 case nodeEvent := <-dp.NodeDeleteEvent: 394 require.Equal(t, n1agent, nodeEvent) 395 case <-time.After(3 * time.Second): 396 t.Errorf("timeout while waiting for NodeDelete() event for node1") 397 } 398 } 399 400 func BenchmarkUpdateAndDeleteCycle(b *testing.B) { 401 ipcacheMock := newIPcacheMock() 402 dp := fakeTypes.NewNodeHandler() 403 h, _ := cell.NewSimpleHealth() 404 mngr, err := New(&option.DaemonConfig{ConfigPatchMutex: new(lock.RWMutex)}, ipcacheMock, newIPSetMock(), nil, NewNodeMetrics(), h) 405 require.NoError(b, err) 406 mngr.Subscribe(dp) 407 defer mngr.Stop(context.TODO()) 408 409 b.ResetTimer() 410 for i := 0; i < b.N; i++ { 411 n := nodeTypes.Node{Name: fmt.Sprintf("%d", i), Source: source.Local} 412 mngr.NodeUpdated(n) 413 } 414 415 for i := 0; i < b.N; i++ { 416 n := nodeTypes.Node{Name: fmt.Sprintf("%d", i), Source: source.Local} 417 mngr.NodeDeleted(n) 418 } 419 b.StopTimer() 420 } 421 422 func TestClusterSizeDependantInterval(t *testing.T) { 423 setup(t) 424 425 ipcacheMock := newIPcacheMock() 426 dp := fakeTypes.NewNodeHandler() 427 h, _ := cell.NewSimpleHealth() 428 mngr, err := New(&option.DaemonConfig{ConfigPatchMutex: new(lock.RWMutex)}, ipcacheMock, newIPSetMock(), nil, NewNodeMetrics(), h) 429 require.NoError(t, err) 430 mngr.Subscribe(dp) 431 defer mngr.Stop(context.TODO()) 432 433 prevInterval := time.Nanosecond 434 435 for i := 0; i < 1000; i++ { 436 n := nodeTypes.Node{Name: fmt.Sprintf("%d", i), Source: source.Local, IPAddresses: []nodeTypes.Address{ 437 { 438 Type: addressing.NodeInternalIP, 439 IP: net.ParseIP("10.0.0.1"), 440 }, 441 }} 442 mngr.NodeUpdated(n) 443 newInterval := mngr.ClusterSizeDependantInterval(time.Minute) 444 assert.Greater(t, newInterval, prevInterval) 445 } 446 } 447 448 func TestBackgroundSync(t *testing.T) { 449 signalNodeHandler := newSignalNodeHandler() 450 signalNodeHandler.EnableNodeValidateImplementationEvent = true 451 ipcacheMock := newIPcacheMock() 452 h, _ := cell.NewSimpleHealth() 453 mngr, err := New(&option.DaemonConfig{ConfigPatchMutex: new(lock.RWMutex)}, ipcacheMock, newIPSetMock(), nil, NewNodeMetrics(), h) 454 mngr.Subscribe(signalNodeHandler) 455 require.NoError(t, err) 456 defer mngr.Stop(context.TODO()) 457 458 numNodes := 128 459 460 allNodeValidateCallsReceived := &sync.WaitGroup{} 461 allNodeValidateCallsReceived.Add(1) 462 463 go func() { 464 nodeValidationsReceived := 0 465 timer, timerDone := inctimer.New() 466 defer timerDone() 467 for { 468 select { 469 case <-signalNodeHandler.NodeValidateImplementationEvent: 470 nodeValidationsReceived++ 471 if nodeValidationsReceived >= numNodes { 472 allNodeValidateCallsReceived.Done() 473 return 474 } 475 case <-timer.After(time.Second * 1): 476 t.Errorf("Timeout while waiting for NodeValidateImplementation() to be called") 477 allNodeValidateCallsReceived.Done() 478 return 479 } 480 } 481 }() 482 483 for i := 0; i < numNodes; i++ { 484 n := nodeTypes.Node{Name: fmt.Sprintf("%d", i), Source: source.Kubernetes, IPAddresses: []nodeTypes.Address{ 485 { 486 Type: addressing.NodeInternalIP, 487 IP: net.ParseIP("10.0.0.1"), 488 }, 489 }} 490 mngr.NodeUpdated(n) 491 } 492 493 mngr.singleBackgroundLoop(context.Background(), time.Millisecond) 494 495 allNodeValidateCallsReceived.Wait() 496 } 497 498 func TestIpcache(t *testing.T) { 499 ipcacheMock := newIPcacheMock() 500 dp := newSignalNodeHandler() 501 h, _ := cell.NewSimpleHealth() 502 mngr, err := New(&option.DaemonConfig{ConfigPatchMutex: new(lock.RWMutex)}, ipcacheMock, newIPSetMock(), nil, NewNodeMetrics(), h) 503 require.NoError(t, err) 504 mngr.Subscribe(dp) 505 defer mngr.Stop(context.TODO()) 506 507 n1 := nodeTypes.Node{ 508 Name: "node1", 509 Cluster: "c1", 510 IPAddresses: []nodeTypes.Address{ 511 {Type: addressing.NodeCiliumInternalIP, IP: net.ParseIP("1.1.1.1")}, 512 {Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.0.2")}, 513 {Type: addressing.NodeExternalIP, IP: net.ParseIP("f00d::1")}, 514 }, 515 } 516 mngr.NodeUpdated(n1) 517 518 select { 519 case event := <-ipcacheMock.events: 520 require.Equal(t, nodeEvent{event: "upsert", prefix: netip.PrefixFrom(netip.MustParseAddr("1.1.1.1"), 32)}, event) 521 case <-time.After(5 * time.Second): 522 t.Errorf("timeout while waiting for ipcache upsert for IP 1.1.1.1") 523 } 524 525 select { 526 case event := <-ipcacheMock.events: 527 require.Equal(t, nodeEvent{event: "upsert", prefix: netip.PrefixFrom(netip.MustParseAddr("10.0.0.2"), 32)}, event) 528 case <-time.After(5 * time.Second): 529 t.Errorf("timeout while waiting for ipcache upsert for IP 10.0.0.2") 530 } 531 532 select { 533 case event := <-ipcacheMock.events: 534 require.Equal(t, nodeEvent{event: "upsert", prefix: netip.PrefixFrom(netip.MustParseAddr("f00d::1"), 128)}, event) 535 case <-time.After(5 * time.Second): 536 t.Errorf("timeout while waiting for ipcache upsert for IP f00d::1") 537 } 538 539 select { 540 case event := <-ipcacheMock.events: 541 t.Errorf("unexected ipcache interaction %+v", event) 542 default: 543 } 544 545 mngr.NodeDeleted(n1) 546 547 select { 548 case event := <-ipcacheMock.events: 549 require.Equal(t, nodeEvent{event: "delete", prefix: netip.PrefixFrom(netip.MustParseAddr("1.1.1.1"), 32)}, event) 550 case <-time.After(5 * time.Second): 551 t.Errorf("timeout while waiting for ipcache delete for IP 1.1.1.1") 552 } 553 554 select { 555 case event := <-ipcacheMock.events: 556 require.Equal(t, nodeEvent{event: "delete", prefix: netip.PrefixFrom(netip.MustParseAddr("10.0.0.2"), 32)}, event) 557 case <-time.After(5 * time.Second): 558 t.Errorf("timeout while waiting for ipcache delete for IP 10.0.0.2") 559 } 560 561 select { 562 case event := <-ipcacheMock.events: 563 require.Equal(t, nodeEvent{event: "delete", prefix: netip.PrefixFrom(netip.MustParseAddr("f00d::1"), 128)}, event) 564 case <-time.After(5 * time.Second): 565 t.Errorf("timeout while waiting for ipcache delete for IP f00d::1") 566 } 567 568 select { 569 case event := <-ipcacheMock.events: 570 t.Errorf("unexected ipcache interaction %+v", event) 571 default: 572 } 573 } 574 575 func TestIpcacheHealthIP(t *testing.T) { 576 ipcacheMock := newIPcacheMock() 577 dp := newSignalNodeHandler() 578 h, _ := cell.NewSimpleHealth() 579 mngr, err := New(&option.DaemonConfig{ConfigPatchMutex: new(lock.RWMutex)}, ipcacheMock, newIPSetMock(), nil, NewNodeMetrics(), h) 580 require.NoError(t, err) 581 mngr.Subscribe(dp) 582 defer mngr.Stop(context.TODO()) 583 584 n1 := nodeTypes.Node{ 585 Name: "node1", 586 Cluster: "c1", 587 IPAddresses: []nodeTypes.Address{ 588 {Type: addressing.NodeCiliumInternalIP, IP: net.ParseIP("1.1.1.1").To4()}, 589 }, 590 IPv4HealthIP: net.ParseIP("10.0.0.4"), 591 IPv6HealthIP: net.ParseIP("f00d::4"), 592 } 593 mngr.NodeUpdated(n1) 594 595 select { 596 case event := <-ipcacheMock.events: 597 require.Equal(t, nodeEvent{event: "upsert", prefix: netip.PrefixFrom(netip.MustParseAddr("1.1.1.1"), 32)}, event) 598 case <-time.After(5 * time.Second): 599 t.Errorf("timeout while waiting for ipcache upsert for IP 1.1.1.1") 600 } 601 602 select { 603 case event := <-ipcacheMock.events: 604 require.Equal(t, nodeEvent{event: "upsert", prefix: netip.PrefixFrom(netip.MustParseAddr("10.0.0.4"), 32)}, event) 605 case <-time.After(5 * time.Second): 606 t.Errorf("timeout while waiting for ipcache upsert for IP 10.0.0.4") 607 } 608 609 select { 610 case event := <-ipcacheMock.events: 611 require.Equal(t, nodeEvent{event: "upsert", prefix: netip.PrefixFrom(netip.MustParseAddr("f00d::4"), 128)}, event) 612 case <-time.After(5 * time.Second): 613 t.Errorf("timeout while waiting for ipcache upsert for IP f00d::4") 614 } 615 616 select { 617 case event := <-ipcacheMock.events: 618 t.Errorf("unexected ipcache interaction %+v", event) 619 default: 620 } 621 622 mngr.NodeDeleted(n1) 623 624 select { 625 case event := <-ipcacheMock.events: 626 require.Equal(t, nodeEvent{event: "delete", prefix: netip.PrefixFrom(netip.MustParseAddr("1.1.1.1"), 32)}, event) 627 case <-time.After(5 * time.Second): 628 t.Errorf("timeout while waiting for ipcache delete for IP 1.1.1.1") 629 } 630 631 select { 632 case event := <-ipcacheMock.events: 633 require.Equal(t, nodeEvent{event: "delete", prefix: netip.PrefixFrom(netip.MustParseAddr("10.0.0.4"), 32)}, event) 634 case <-time.After(5 * time.Second): 635 t.Errorf("timeout while waiting for ipcache delete for IP 10.0.0.4") 636 } 637 638 select { 639 case event := <-ipcacheMock.events: 640 require.Equal(t, nodeEvent{event: "delete", prefix: netip.PrefixFrom(netip.MustParseAddr("f00d::4"), 128)}, event) 641 case <-time.After(5 * time.Second): 642 t.Errorf("timeout while waiting for ipcache delete for IP f00d::4") 643 } 644 645 select { 646 case event := <-ipcacheMock.events: 647 t.Errorf("unexected ipcache interaction %+v", event) 648 default: 649 } 650 } 651 652 func TestNodeEncryption(t *testing.T) { 653 setup(t) 654 655 ipcacheMock := newIPcacheMock() 656 dp := newSignalNodeHandler() 657 h, _ := cell.NewSimpleHealth() 658 mngr, err := New(&option.DaemonConfig{ 659 ConfigPatchMutex: new(lock.RWMutex), 660 EncryptNode: true, 661 EnableIPSec: true, 662 }, ipcacheMock, newIPSetMock(), nil, NewNodeMetrics(), h) 663 require.NoError(t, err) 664 mngr.Subscribe(dp) 665 defer mngr.Stop(context.TODO()) 666 667 n1 := nodeTypes.Node{ 668 Name: "node1", 669 Cluster: "c1", 670 IPAddresses: []nodeTypes.Address{ 671 {Type: addressing.NodeCiliumInternalIP, IP: net.ParseIP("1.1.1.1")}, 672 {Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.0.2")}, 673 {Type: addressing.NodeExternalIP, IP: net.ParseIP("f00d::1")}, 674 }, 675 } 676 mngr.NodeUpdated(n1) 677 678 select { 679 case event := <-ipcacheMock.events: 680 require.Equal(t, nodeEvent{event: "upsert", prefix: netip.PrefixFrom(netip.MustParseAddr("1.1.1.1"), 32)}, event) 681 case <-time.After(5 * time.Second): 682 t.Errorf("timeout while waiting for ipcache upsert for IP 1.1.1.1") 683 } 684 685 select { 686 case event := <-ipcacheMock.events: 687 require.Equal(t, nodeEvent{event: "upsert", prefix: netip.PrefixFrom(netip.MustParseAddr("10.0.0.2"), 32)}, event) 688 case <-time.After(5 * time.Second): 689 t.Errorf("timeout while waiting for ipcache upsert for IP 10.0.0.2") 690 } 691 692 select { 693 case event := <-ipcacheMock.events: 694 require.Equal(t, nodeEvent{event: "upsert", prefix: netip.PrefixFrom(netip.MustParseAddr("f00d::1"), 128)}, event) 695 case <-time.After(5 * time.Second): 696 t.Errorf("timeout while waiting for ipcache upsert for IP f00d::1") 697 } 698 699 select { 700 case event := <-ipcacheMock.events: 701 t.Errorf("unexected ipcache interaction %+v", event) 702 default: 703 } 704 705 mngr.NodeDeleted(n1) 706 707 select { 708 case event := <-ipcacheMock.events: 709 require.Equal(t, nodeEvent{event: "delete", prefix: netip.PrefixFrom(netip.MustParseAddr("1.1.1.1"), 32)}, event) 710 case <-time.After(5 * time.Second): 711 t.Errorf("timeout while waiting for ipcache delete for IP 1.1.1.1") 712 } 713 714 select { 715 case event := <-ipcacheMock.events: 716 require.Equal(t, nodeEvent{event: "delete", prefix: netip.PrefixFrom(netip.MustParseAddr("10.0.0.2"), 32)}, event) 717 case <-time.After(5 * time.Second): 718 t.Errorf("timeout while waiting for ipcache delete for IP 10.0.0.2") 719 } 720 721 select { 722 case event := <-ipcacheMock.events: 723 require.Equal(t, nodeEvent{event: "delete", prefix: netip.PrefixFrom(netip.MustParseAddr("f00d::1"), 128)}, event) 724 case <-time.After(5 * time.Second): 725 t.Errorf("timeout while waiting for ipcache delete for IP f00d::1") 726 } 727 728 select { 729 case event := <-ipcacheMock.events: 730 t.Errorf("unexected ipcache interaction %+v", event) 731 default: 732 } 733 } 734 735 func TestNode(t *testing.T) { 736 ipcacheMock := newIPcacheMock() 737 ipcacheExpect := func(eventType, ipStr string) { 738 select { 739 case event := <-ipcacheMock.events: 740 b := 32 741 if strings.Contains(ipStr, ":") { 742 b = 128 743 } 744 require.Equal(t, nodeEvent{event: eventType, prefix: netip.PrefixFrom(netip.MustParseAddr(ipStr), b)}, event) 745 case <-time.After(5 * time.Second): 746 t.Errorf("timeout while waiting for ipcache upsert for IP %s", ipStr) 747 } 748 } 749 750 dp := newSignalNodeHandler() 751 dp.EnableNodeAddEvent = true 752 dp.EnableNodeUpdateEvent = true 753 dp.EnableNodeDeleteEvent = true 754 h, _ := cell.NewSimpleHealth() 755 mngr, err := New(&option.DaemonConfig{ConfigPatchMutex: new(lock.RWMutex)}, ipcacheMock, newIPSetMock(), nil, NewNodeMetrics(), h) 756 require.NoError(t, err) 757 mngr.Subscribe(dp) 758 defer mngr.Stop(context.TODO()) 759 760 n1 := nodeTypes.Node{ 761 Name: "node1", 762 Cluster: "c1", 763 IPAddresses: []nodeTypes.Address{ 764 { 765 Type: addressing.NodeCiliumInternalIP, 766 IP: net.ParseIP("192.0.2.1"), 767 }, 768 { 769 Type: addressing.NodeCiliumInternalIP, 770 IP: net.ParseIP("2001:DB8::1"), 771 }, 772 }, 773 IPv4HealthIP: net.ParseIP("192.0.2.2"), 774 IPv6HealthIP: net.ParseIP("2001:DB8::2"), 775 Source: source.KVStore, 776 } 777 mngr.NodeUpdated(n1) 778 779 select { 780 case nodeEvent := <-dp.NodeAddEvent: 781 require.Equal(t, n1, nodeEvent) 782 case nodeEvent := <-dp.NodeUpdateEvent: 783 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 784 case nodeEvent := <-dp.NodeDeleteEvent: 785 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 786 case <-time.After(3 * time.Second): 787 t.Errorf("timeout while waiting for NodeAdd() event for node1") 788 } 789 790 ipcacheExpect("upsert", "192.0.2.1") 791 ipcacheExpect("upsert", "2001:DB8::1") 792 ipcacheExpect("upsert", "192.0.2.2") 793 ipcacheExpect("upsert", "2001:DB8::2") 794 795 n1V2 := n1.DeepCopy() 796 n1V2.IPAddresses = []nodeTypes.Address{ 797 { 798 Type: addressing.NodeCiliumInternalIP, 799 IP: net.ParseIP("192.0.2.10"), 800 }, 801 { 802 // We will keep the IPv6 the same to make sure we will not delete it 803 Type: addressing.NodeCiliumInternalIP, 804 IP: net.ParseIP("2001:DB8::1"), 805 }, 806 } 807 n1V2.IPv4HealthIP = net.ParseIP("192.0.2.20") 808 n1V2.IPv6HealthIP = net.ParseIP("2001:DB8::20") 809 mngr.NodeUpdated(*n1V2) 810 811 select { 812 case nodeEvent := <-dp.NodeAddEvent: 813 t.Errorf("Unexpected NodeAdd() event %#v", nodeEvent) 814 case nodeEvent := <-dp.NodeUpdateEvent: 815 require.Equal(t, *n1V2, nodeEvent) 816 case nodeEvent := <-dp.NodeDeleteEvent: 817 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 818 case <-time.After(3 * time.Second): 819 t.Errorf("timeout while waiting for NodeUpdate() event for node2") 820 } 821 822 ipcacheExpect("upsert", "192.0.2.10") 823 ipcacheExpect("upsert", "2001:DB8::1") 824 ipcacheExpect("upsert", "192.0.2.20") 825 ipcacheExpect("upsert", "2001:DB8::20") 826 827 ipcacheExpect("delete", "192.0.2.1") 828 ipcacheExpect("delete", "192.0.2.2") 829 ipcacheExpect("delete", "2001:DB8::2") 830 831 select { 832 case event := <-ipcacheMock.events: 833 t.Errorf("Received unexpected event %+v", event) 834 case <-time.After(1 * time.Second): 835 } 836 837 nodes := mngr.GetNodes() 838 require.Len(t, nodes, 1) 839 n, ok := nodes[n1.Identity()] 840 require.True(t, ok) 841 // Needs to be the same as n2 842 require.Equal(t, *n1V2, n) 843 } 844 845 func TestNodeManagerEmitStatus(t *testing.T) { 846 // Tests health reporting on node manager. 847 assert := assert.New(t) 848 849 baseBackgroundSyncInterval = 1 * time.Millisecond 850 fn := func(m *manager, sh hive.Shutdowner, statusTable statedb.Table[types.Status], db *statedb.DB) { 851 defer sh.Shutdown() 852 m.nodes[nodeTypes.Identity{ 853 Name: "node1", 854 Cluster: "c1", 855 }] = &nodeEntry{node: nodeTypes.Node{Name: "node1", Cluster: "c1"}} 856 m.nodeHandlers = make(map[datapath.NodeHandler]struct{}) 857 nh1 := newSignalNodeHandler() 858 nh1.EnableNodeValidateImplementationEvent = true 859 // By default this is a buffered channel, by making it a non-buffered 860 // channel we can sync up iterations of background sync. 861 nh1.NodeValidateImplementationEvent = make(chan nodeTypes.Node) 862 nh1.NodeValidateImplementationEventError = fmt.Errorf("test error") 863 m.nodeHandlers[nh1] = struct{}{} 864 865 done := make(chan struct{}) 866 reattempt := make(chan struct{}) 867 checkStatus := func(old statedb.Revision) (types.Status, <-chan struct{}, statedb.Revision) { 868 tx := db.ReadTxn() 869 870 id := types.Identifier{ 871 Module: cell.FullModuleID{"node_manager"}, 872 Component: []string{"background-sync"}, 873 } 874 for { 875 ss, cur, watch, _ := statusTable.GetWatch(tx, health.PrimaryIndex.Query(id.HealthID())) 876 if cur != old { 877 return ss, watch, cur 878 } 879 <-watch 880 } 881 } 882 go func() { 883 status, watch, rev := checkStatus(99) 884 assert.Equal(types.Level(""), status.Level) 885 <-watch 886 status, watch, rev = checkStatus(rev) 887 assert.Equal(types.LevelDegraded, string(status.Level)) 888 close(reattempt) 889 <-watch 890 status, _, _ = checkStatus(rev) 891 assert.Equal(types.LevelOK, string(status.Level)) 892 }() 893 go func() { 894 <-nh1.NodeValidateImplementationEvent 895 <-reattempt 896 nh1.NodeValidateImplementationEventError = nil 897 <-nh1.NodeValidateImplementationEvent 898 close(done) 899 }() 900 // Start the manager 901 assert.NoError(m.Start(context.Background())) 902 <-done 903 } 904 ipcacheMock := newIPcacheMock() 905 config := &option.DaemonConfig{ConfigPatchMutex: new(lock.RWMutex)} 906 err := hive.New( 907 cell.Provide(func() testParams { 908 return testParams{ 909 Config: config, 910 IPCache: ipcacheMock, 911 IPSet: newIPSetMock(), 912 NodeMetrics: NewNodeMetrics(), 913 IPSetFilterFn: func(no *nodeTypes.Node) bool { return false }, 914 } 915 }), 916 cell.Module("node_manager", "Node Manager", cell.Provide(New)), 917 cell.Invoke(fn), 918 ).Run(hivetest.Logger(t)) 919 assert.NoError(err) 920 } 921 922 type testParams struct { 923 cell.Out 924 Config *option.DaemonConfig 925 IPCache IPCache 926 IPSet ipset.Manager 927 NodeMetrics *nodeMetrics 928 IPSetFilterFn IPSetFilterFn 929 } 930 931 type mockUpdater struct{} 932 933 func (m *mockUpdater) UpdateIdentities(_, _ identity.IdentityMap, _ *sync.WaitGroup) {} 934 935 type mockTriggerer struct{} 936 937 func (m *mockTriggerer) UpdatePolicyMaps(ctx context.Context, wg *sync.WaitGroup) *sync.WaitGroup { 938 return wg 939 } 940 941 func TestNodeWithSameInternalIP(t *testing.T) { 942 ctx, cancel := context.WithCancel(context.Background()) 943 allocator := testidentity.NewMockIdentityAllocator(nil) 944 ipcache := ipcache.NewIPCache(&ipcache.Configuration{ 945 Context: ctx, 946 IdentityAllocator: allocator, 947 PolicyHandler: &mockUpdater{}, 948 DatapathHandler: &mockTriggerer{}, 949 }) 950 defer cancel() 951 dp := newSignalNodeHandler() 952 dp.EnableNodeAddEvent = true 953 dp.EnableNodeUpdateEvent = true 954 dp.EnableNodeDeleteEvent = true 955 h, _ := cell.NewSimpleHealth() 956 mngr, err := New(&option.DaemonConfig{ 957 ConfigPatchMutex: new(lock.RWMutex), 958 LocalRouterIPv4: "169.254.4.6", 959 }, ipcache, newIPSetMock(), nil, NewNodeMetrics(), h) 960 require.NoError(t, err) 961 mngr.Subscribe(dp) 962 defer mngr.Stop(context.TODO()) 963 964 n1 := nodeTypes.Node{ 965 Name: "node1", 966 Cluster: "c1", 967 IPAddresses: []nodeTypes.Address{ 968 { 969 Type: addressing.NodeInternalIP, 970 IP: net.ParseIP("10.128.0.40"), 971 }, 972 { 973 Type: addressing.NodeExternalIP, 974 IP: net.ParseIP("34.171.135.203"), 975 }, 976 { 977 Type: addressing.NodeCiliumInternalIP, 978 IP: net.ParseIP("169.254.4.6"), 979 }, 980 }, 981 Source: source.Local, 982 } 983 mngr.NodeUpdated(n1) 984 985 select { 986 case nodeEvent := <-dp.NodeAddEvent: 987 require.Equal(t, n1, nodeEvent) 988 case nodeEvent := <-dp.NodeUpdateEvent: 989 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 990 case nodeEvent := <-dp.NodeDeleteEvent: 991 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 992 case <-time.After(3 * time.Second): 993 t.Errorf("timeout while waiting for NodeAdd() event for node1") 994 } 995 996 n2 := nodeTypes.Node{ 997 Name: "node2", 998 Cluster: "c1", 999 IPAddresses: []nodeTypes.Address{ 1000 { 1001 Type: addressing.NodeInternalIP, 1002 IP: net.ParseIP("10.128.0.110"), 1003 }, 1004 { 1005 Type: addressing.NodeExternalIP, 1006 IP: net.ParseIP("34.170.71.139"), 1007 }, 1008 { 1009 Type: addressing.NodeCiliumInternalIP, 1010 IP: net.ParseIP("169.254.4.6"), 1011 }, 1012 }, 1013 Source: source.CustomResource, 1014 } 1015 mngr.NodeUpdated(n2) 1016 1017 select { 1018 case nodeEvent := <-dp.NodeAddEvent: 1019 require.Equal(t, n2, nodeEvent) 1020 case nodeEvent := <-dp.NodeUpdateEvent: 1021 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 1022 case nodeEvent := <-dp.NodeDeleteEvent: 1023 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 1024 case <-time.After(3 * time.Second): 1025 t.Errorf("timeout while waiting for NodeAdd() event for node1") 1026 } 1027 } 1028 1029 // TestNodeIpset tests that the ipset entries on the node are updated correctly 1030 // when a node is updated or removed. 1031 // It is inspired from TestNode() in manager_test.go. 1032 func TestNodeIpset(t *testing.T) { 1033 ipsetExpect := func(ipsetMgr *ipsetMock, ip string, expected bool) { 1034 setName := ipset.CiliumNodeIPSetV6 1035 if v4 := net.ParseIP(ip).To4(); v4 != nil { 1036 setName = ipset.CiliumNodeIPSetV4 1037 } 1038 1039 found, err := ipsetContains(ipsetMgr, setName, strings.ToLower(ip)) 1040 require.NoError(t, err) 1041 1042 if found && !expected { 1043 t.Errorf("ipset %s contains IP %s but it should not", setName, ip) 1044 } 1045 if !found && expected { 1046 t.Errorf("ipset %s does not contain expected IP %s", setName, ip) 1047 } 1048 } 1049 1050 dp := newSignalNodeHandler() 1051 dp.EnableNodeAddEvent = true 1052 dp.EnableNodeUpdateEvent = true 1053 dp.EnableNodeDeleteEvent = true 1054 filter := func(no *nodeTypes.Node) bool { return no.Name != "node1" } 1055 h, _ := cell.NewSimpleHealth() 1056 mngr, err := New(&option.DaemonConfig{ 1057 ConfigPatchMutex: new(lock.RWMutex), 1058 RoutingMode: option.RoutingModeNative, 1059 EnableIPv4Masquerade: true, 1060 }, newIPcacheMock(), newIPSetMock(), filter, NewNodeMetrics(), h) 1061 mngr.Subscribe(dp) 1062 require.NoError(t, err) 1063 defer mngr.Stop(context.TODO()) 1064 1065 n1 := nodeTypes.Node{ 1066 Name: "node1", 1067 Cluster: "c1", 1068 IPAddresses: []nodeTypes.Address{ 1069 { 1070 Type: addressing.NodeCiliumInternalIP, 1071 IP: net.ParseIP("192.0.2.1"), 1072 }, 1073 { 1074 Type: addressing.NodeCiliumInternalIP, 1075 IP: net.ParseIP("2001:DB8::1"), 1076 }, 1077 { 1078 Type: addressing.NodeInternalIP, 1079 IP: net.ParseIP("10.0.0.1"), 1080 }, 1081 { 1082 Type: addressing.NodeInternalIP, 1083 IP: net.ParseIP("2001:ABCD::1"), 1084 }, 1085 }, 1086 IPv4HealthIP: net.ParseIP("192.0.2.2"), 1087 IPv6HealthIP: net.ParseIP("2001:DB8::2"), 1088 Source: source.KVStore, 1089 } 1090 mngr.NodeUpdated(n1) 1091 1092 select { 1093 case nodeEvent := <-dp.NodeAddEvent: 1094 require.Equal(t, n1, nodeEvent) 1095 case nodeEvent := <-dp.NodeUpdateEvent: 1096 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 1097 case nodeEvent := <-dp.NodeDeleteEvent: 1098 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 1099 case <-time.After(3 * time.Second): 1100 t.Errorf("timeout while waiting for NodeAdd() event") 1101 } 1102 1103 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "192.0.2.1", false) 1104 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "2001:DB8::1", false) 1105 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "10.0.0.1", true) 1106 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "2001:ABCD::1", true) 1107 1108 n2 := nodeTypes.Node{ 1109 Name: "node2", 1110 Cluster: "c1", 1111 IPAddresses: []nodeTypes.Address{ 1112 { 1113 Type: addressing.NodeInternalIP, 1114 IP: net.ParseIP("10.1.0.1"), 1115 }, 1116 { 1117 Type: addressing.NodeInternalIP, 1118 IP: net.ParseIP("2001:ABCE::1"), 1119 }, 1120 }, 1121 Source: source.CustomResource, 1122 } 1123 mngr.NodeUpdated(n2) 1124 1125 select { 1126 case nodeEvent := <-dp.NodeAddEvent: 1127 require.Equal(t, n2, nodeEvent) 1128 case nodeEvent := <-dp.NodeUpdateEvent: 1129 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 1130 case nodeEvent := <-dp.NodeDeleteEvent: 1131 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 1132 case <-time.After(3 * time.Second): 1133 t.Errorf("timeout while waiting for NodeAdd() event") 1134 } 1135 1136 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "10.0.0.1", true) 1137 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "2001:ABCD::1", true) 1138 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "10.1.0.1", false) 1139 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "2001:ABCE::1", false) 1140 1141 n1.IPv4HealthIP = net.ParseIP("192.0.2.20") 1142 mngr.NodeUpdated(n1) 1143 1144 select { 1145 case nodeEvent := <-dp.NodeAddEvent: 1146 t.Errorf("Unexpected NodeAdd() event %#v", nodeEvent) 1147 case nodeEvent := <-dp.NodeUpdateEvent: 1148 require.Equal(t, n1, nodeEvent) 1149 case nodeEvent := <-dp.NodeDeleteEvent: 1150 t.Errorf("Unexpected NodeDelete() event %#v", nodeEvent) 1151 case <-time.After(3 * time.Second): 1152 t.Errorf("timeout while waiting for NodeUpdate() event") 1153 } 1154 1155 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "192.0.2.1", false) 1156 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "2001:DB8::1", false) 1157 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "10.0.0.1", true) 1158 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "2001:ABCD::1", true) 1159 1160 mngr.NodeDeleted(n1) 1161 select { 1162 case nodeEvent := <-dp.NodeDeleteEvent: 1163 require.Equal(t, n1, nodeEvent) 1164 case nodeEvent := <-dp.NodeAddEvent: 1165 t.Errorf("Unexpected NodeAdd() event %#v", nodeEvent) 1166 case nodeEvent := <-dp.NodeUpdateEvent: 1167 t.Errorf("Unexpected NodeUpdate() event %#v", nodeEvent) 1168 case <-time.After(3 * time.Second): 1169 t.Errorf("timeout while waiting for NodeDelete() event") 1170 } 1171 1172 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "192.0.2.1", false) 1173 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "2001:DB8::1", false) 1174 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "10.0.0.1", false) 1175 ipsetExpect(mngr.ipsetMgr.(*ipsetMock), "2001:ABCD::1", false) 1176 } 1177 1178 // Tests that the node manager calls delete on nodes to be pruned. 1179 func TestNodesStartupPruning(t *testing.T) { 1180 n1 := nodeTypes.Node{Name: "node1", Cluster: "c1", IPAddresses: []nodeTypes.Address{ 1181 { 1182 Type: addressing.NodeInternalIP, 1183 IP: net.ParseIP("10.0.0.1"), 1184 }, 1185 }} 1186 1187 n2 := nodeTypes.Node{Name: "node2", Cluster: "c1", IPAddresses: []nodeTypes.Address{ 1188 { 1189 Type: addressing.NodeInternalIP, 1190 IP: net.ParseIP("10.0.0.2"), 1191 }, 1192 }} 1193 1194 n3 := nodeTypes.Node{Name: "node3", Cluster: "c2", IPAddresses: []nodeTypes.Address{ 1195 { 1196 Type: addressing.NodeInternalIP, 1197 IP: net.ParseIP("10.0.0.3"), 1198 }, 1199 }} 1200 1201 // Create a nodes.json file from the above two nodes, simulating a previous instance of the agent. 1202 tmp, err := os.MkdirTemp("", "nodes") 1203 require.NoError(t, err) 1204 path := filepath.Join(tmp, nodesFilename) 1205 nf, err := os.Create(path) 1206 require.NoError(t, err) 1207 t.Cleanup(func() { 1208 nf.Close() 1209 os.Remove(path) 1210 }) 1211 e := json.NewEncoder(nf) 1212 require.NoError(t, e.Encode([]nodeTypes.Node{n3, n2, n1})) 1213 require.NoError(t, nf.Sync()) 1214 require.NoError(t, nf.Close()) 1215 1216 checkNodeFileMatches := func(path string, node nodeTypes.Node) { 1217 // Wait until the file exists. The node deletion triggers the write, hence 1218 // this shouldn't take long. 1219 for range 10 { 1220 _, err := os.Stat(path) 1221 if err == nil { 1222 break 1223 } 1224 require.ErrorIs(t, err, fs.ErrNotExist) 1225 time.Sleep(time.Millisecond) 1226 } 1227 nwf, err := os.Open(path) 1228 require.NoError(t, err) 1229 t.Cleanup(func() { 1230 nwf.Close() 1231 }) 1232 var nl []nodeTypes.Node 1233 assert.NoError(t, json.NewDecoder(nwf).Decode(&nl)) 1234 assert.Len(t, nl, 1) 1235 assert.Equal(t, node, nl[0]) 1236 require.NoError(t, os.Remove(path)) 1237 } 1238 1239 // Create a node manager and add only node1. 1240 ipcacheMock := newIPcacheMock() 1241 dp := newSignalNodeHandler() 1242 dp.EnableNodeDeleteEvent = true 1243 h, _ := cell.NewSimpleHealth() 1244 mngr, err := New(&option.DaemonConfig{ 1245 StateDir: tmp, 1246 ClusterName: "c1", 1247 }, ipcacheMock, newIPSetMock(), nil, NewNodeMetrics(), h) 1248 require.NoError(t, err) 1249 t.Cleanup(func() { 1250 mngr.Stop(context.TODO()) 1251 }) 1252 mngr.Subscribe(dp) 1253 mngr.NodeUpdated(n1) 1254 1255 // Load the nodes from disk and initiate pruning. This should prune node 2 1256 // (since it's present in the file but not in our current view). 1257 mngr.restoreNodeCheckpoint() 1258 require.NoError(t, mngr.initNodeCheckpointer(time.Microsecond)) 1259 // We remove our test file here to be able to tell once the nodemanager has 1260 // written one itself. 1261 require.NoError(t, os.Remove(path)) 1262 // Declare cluster nodes synced (but not clustermesh nodes) 1263 mngr.NodeSync() 1264 1265 select { 1266 case dn := <-dp.NodeDeleteEvent: 1267 n2r := n2 1268 n2r.Source = source.Restored 1269 assert.Equal(t, n2r, dn, "should have deleted node 2 and (with source=Restored)") 1270 case <-time.After(time.Second * 5): 1271 t.Fatal("should have received a node deletion event for node 2") 1272 } 1273 1274 checkNodeFileMatches(path, n1) 1275 1276 // Allow pruning the clustermesh node. 1277 mngr.MeshNodeSync() 1278 1279 select { 1280 case dn := <-dp.NodeDeleteEvent: 1281 n3r := n3 1282 n3r.Source = source.Restored 1283 assert.Equal(t, n3r, dn, "should have deleted node 3 and (with source=Restored)") 1284 case <-time.After(time.Second * 5): 1285 t.Fatal("should have received a node deletion event for node 3") 1286 } 1287 1288 checkNodeFileMatches(path, n1) 1289 }