github.com/cilium/cilium@v1.16.2/pkg/endpointmanager/manager_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package endpointmanager 5 6 import ( 7 "context" 8 "net/netip" 9 "sync" 10 "testing" 11 "time" 12 13 "github.com/cilium/hive/cell" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 apiv1 "github.com/cilium/cilium/api/v1/models" 18 datapath "github.com/cilium/cilium/pkg/datapath/types" 19 "github.com/cilium/cilium/pkg/endpoint" 20 endpointid "github.com/cilium/cilium/pkg/endpoint/id" 21 "github.com/cilium/cilium/pkg/fqdn/restore" 22 "github.com/cilium/cilium/pkg/labels" 23 "github.com/cilium/cilium/pkg/labelsfilter" 24 monitorAPI "github.com/cilium/cilium/pkg/monitor/api" 25 "github.com/cilium/cilium/pkg/node" 26 "github.com/cilium/cilium/pkg/node/types" 27 "github.com/cilium/cilium/pkg/option" 28 "github.com/cilium/cilium/pkg/policy" 29 testidentity "github.com/cilium/cilium/pkg/testutils/identity" 30 testipcache "github.com/cilium/cilium/pkg/testutils/ipcache" 31 ) 32 33 func (mgr *endpointManager) waitEndpointRemoved(ep *endpoint.Endpoint, conf endpoint.DeleteConfig) []error { 34 mgr.unexpose(ep) 35 ep.Stop() 36 return nil 37 } 38 39 // RemoveAll removes all endpoints from the global maps. 40 func (mgr *endpointManager) RemoveAll(t testing.TB) { 41 mgr.mutex.Lock() 42 defer mgr.mutex.Unlock() 43 mgr.epIDAllocator.reallocatePool(t) 44 mgr.endpoints = map[uint16]*endpoint.Endpoint{} 45 mgr.endpointsAux = map[string]*endpoint.Endpoint{} 46 } 47 48 // WaitEndpointRemoved waits until all operations associated with Remove of 49 // the endpoint have been completed. 50 // Note: only used for unit tests, to avoid ep.Delete() 51 func (mgr *endpointManager) WaitEndpointRemoved(ep *endpoint.Endpoint) { 52 mgr.waitEndpointRemoved(ep, endpoint.DeleteConfig{}) 53 } 54 55 type EndpointManagerSuite struct { 56 repo *policy.Repository 57 } 58 59 func setupEndpointManagerSuite(tb testing.TB) *EndpointManagerSuite { 60 s := &EndpointManagerSuite{} 61 s.repo = policy.NewPolicyRepository(nil, nil, nil) 62 63 return s 64 } 65 66 func (s *EndpointManagerSuite) GetPolicyRepository() *policy.Repository { 67 return s.repo 68 } 69 70 func (s *EndpointManagerSuite) QueueEndpointBuild(ctx context.Context, epID uint64) (func(), error) { 71 return nil, nil 72 } 73 74 func (s *EndpointManagerSuite) GetCompilationLock() datapath.CompilationLock { 75 return nil 76 } 77 78 func (s *EndpointManagerSuite) GetCIDRPrefixLengths() (s6, s4 []int) { 79 return nil, nil 80 } 81 82 func (s *EndpointManagerSuite) SendNotification(msg monitorAPI.AgentNotifyMessage) error { 83 return nil 84 } 85 86 func (s *EndpointManagerSuite) Datapath() datapath.Datapath { 87 return nil 88 } 89 90 func (s *EndpointManagerSuite) GetDNSRules(epID uint16) restore.DNSRules { 91 return nil 92 } 93 94 func (s *EndpointManagerSuite) RemoveRestoredDNSRules(epID uint16) { 95 } 96 97 type DummyRuleCacheOwner struct{} 98 99 func (d *DummyRuleCacheOwner) ClearPolicyConsumers(id uint16) *sync.WaitGroup { 100 return &sync.WaitGroup{} 101 } 102 103 type dummyEpSyncher struct{} 104 105 func (epSync *dummyEpSyncher) RunK8sCiliumEndpointSync(e *endpoint.Endpoint, hr cell.Health) { 106 } 107 108 func (epSync *dummyEpSyncher) DeleteK8sCiliumEndpointSync(e *endpoint.Endpoint) { 109 } 110 111 func TestLookup(t *testing.T) { 112 s := setupEndpointManagerSuite(t) 113 114 type args struct { 115 id string 116 } 117 type want struct { 118 ep bool 119 err error 120 errCheck assert.ComparisonAssertionFunc 121 } 122 tests := []struct { 123 name string 124 setupArgs func() args 125 setupWant func() want 126 cm *apiv1.EndpointChangeRequest 127 }{ 128 { 129 name: "endpoint does not exist", 130 setupArgs: func() args { 131 return args{ 132 "1234", 133 } 134 }, 135 setupWant: func() want { 136 return want{ 137 ep: false, 138 err: nil, 139 errCheck: assert.EqualValues, 140 } 141 }, 142 }, 143 { 144 name: "endpoint by cilium local ID", 145 cm: &apiv1.EndpointChangeRequest{ 146 ID: 1234, 147 }, 148 setupArgs: func() args { 149 return args{ 150 endpointid.NewCiliumID(1234), 151 } 152 }, 153 setupWant: func() want { 154 return want{ 155 ep: true, 156 err: nil, 157 errCheck: assert.EqualValues, 158 } 159 }, 160 }, 161 { 162 name: "endpoint by cilium global ID", 163 cm: &apiv1.EndpointChangeRequest{ 164 ID: 1234, 165 }, 166 setupArgs: func() args { 167 return args{ 168 endpointid.NewID(endpointid.CiliumGlobalIdPrefix, "1234"), 169 } 170 }, 171 setupWant: func() want { 172 return want{ 173 err: ErrUnsupportedID, 174 errCheck: assert.EqualValues, 175 } 176 }, 177 }, 178 { 179 name: "endpoint by CNI attachment ID", 180 cm: &apiv1.EndpointChangeRequest{ 181 ContainerID: "1234", 182 ContainerInterfaceName: "eth0", 183 }, 184 setupArgs: func() args { 185 return args{ 186 endpointid.NewCNIAttachmentID("1234", "eth0"), 187 } 188 }, 189 setupWant: func() want { 190 return want{ 191 ep: true, 192 err: nil, 193 errCheck: assert.EqualValues, 194 } 195 }, 196 }, 197 { 198 name: "endpoint by CNI attachment ID without interface", 199 cm: &apiv1.EndpointChangeRequest{ 200 ContainerID: "1234", 201 }, 202 setupArgs: func() args { 203 return args{ 204 endpointid.NewCNIAttachmentID("1234", ""), 205 } 206 }, 207 setupWant: func() want { 208 return want{ 209 ep: true, 210 err: nil, 211 errCheck: assert.EqualValues, 212 } 213 }, 214 }, 215 { 216 name: "endpoint by container ID (deprecated)", 217 cm: &apiv1.EndpointChangeRequest{ 218 ContainerID: "1234", 219 }, 220 setupArgs: func() args { 221 return args{ 222 endpointid.NewID(endpointid.ContainerIdPrefix, "1234"), 223 } 224 }, 225 setupWant: func() want { 226 return want{ 227 ep: true, 228 err: nil, 229 errCheck: assert.EqualValues, 230 } 231 }, 232 }, 233 { 234 name: "endpoint by docker endpoint ID", 235 cm: &apiv1.EndpointChangeRequest{ 236 DockerEndpointID: "1234", 237 }, 238 setupArgs: func() args { 239 return args{ 240 endpointid.NewID(endpointid.DockerEndpointPrefix, "1234"), 241 } 242 }, 243 setupWant: func() want { 244 return want{ 245 ep: true, 246 err: nil, 247 errCheck: assert.EqualValues, 248 } 249 }, 250 }, 251 { 252 name: "endpoint by container name (deprecated)", 253 cm: &apiv1.EndpointChangeRequest{ 254 ContainerName: "foo", 255 }, 256 setupArgs: func() args { 257 return args{ 258 endpointid.NewID(endpointid.ContainerNamePrefix, "foo"), 259 } 260 }, 261 setupWant: func() want { 262 return want{ 263 ep: true, 264 err: nil, 265 errCheck: assert.EqualValues, 266 } 267 }, 268 }, 269 { 270 name: "endpoint by pod name", 271 cm: &apiv1.EndpointChangeRequest{ 272 K8sNamespace: "default", 273 K8sPodName: "foo", 274 }, 275 setupArgs: func() args { 276 return args{ 277 endpointid.NewID(endpointid.PodNamePrefix, "default/foo"), 278 } 279 }, 280 setupWant: func() want { 281 return want{ 282 ep: true, 283 err: nil, 284 errCheck: assert.EqualValues, 285 } 286 }, 287 }, 288 { 289 name: "endpoint by cep name", 290 cm: &apiv1.EndpointChangeRequest{ 291 K8sNamespace: "default", 292 K8sPodName: "foo", 293 }, 294 setupArgs: func() args { 295 return args{ 296 endpointid.NewID(endpointid.CEPNamePrefix, "default/foo"), 297 } 298 }, 299 setupWant: func() want { 300 return want{ 301 ep: true, 302 err: nil, 303 errCheck: assert.EqualValues, 304 } 305 }, 306 }, 307 { 308 name: "endpoint by cep name with interface", 309 cm: &apiv1.EndpointChangeRequest{ 310 K8sNamespace: "default", 311 K8sPodName: "foo", 312 ContainerInterfaceName: "net1", 313 }, 314 setupArgs: func() args { 315 return args{ 316 endpointid.NewID(endpointid.CEPNamePrefix, "default/foo"), 317 } 318 }, 319 setupWant: func() want { 320 return want{ 321 ep: true, 322 err: nil, 323 errCheck: assert.EqualValues} 324 }, 325 }, 326 { 327 name: "endpoint by cep name with interface and disabled legacy identifers", 328 cm: &apiv1.EndpointChangeRequest{ 329 K8sNamespace: "default", 330 K8sPodName: "foo", 331 ContainerInterfaceName: "net1", 332 DisableLegacyIdentifiers: true, 333 }, 334 setupArgs: func() args { 335 return args{ 336 endpointid.NewID(endpointid.CEPNamePrefix, "default/foo-net1"), 337 } 338 }, 339 setupWant: func() want { 340 return want{ 341 ep: true, 342 err: nil, 343 errCheck: assert.EqualValues, 344 } 345 }, 346 }, 347 { 348 name: "endpoint by ipv4", 349 cm: &apiv1.EndpointChangeRequest{ 350 Addressing: &apiv1.AddressPair{ 351 IPV4: "127.0.0.1", 352 }, 353 }, 354 setupArgs: func() args { 355 return args{ 356 endpointid.NewID(endpointid.IPv4Prefix, "127.0.0.1"), 357 } 358 }, 359 setupWant: func() want { 360 return want{ 361 ep: true, 362 err: nil, 363 errCheck: assert.EqualValues, 364 } 365 }, 366 }, 367 { 368 name: "invalid ID", 369 setupArgs: func() args { 370 return args{ 371 endpointid.NewID("foo", "bar"), 372 } 373 }, 374 setupWant: func() want { 375 return want{ 376 err: nil, 377 errCheck: assert.NotEqualValues, 378 } 379 }, 380 }, 381 { 382 name: "invalid cilium ID", 383 setupArgs: func() args { 384 return args{ 385 endpointid.NewID(endpointid.CiliumLocalIdPrefix, "bar"), 386 } 387 }, 388 setupWant: func() want { 389 return want{ 390 err: nil, 391 errCheck: assert.NotEqualValues, 392 } 393 }, 394 }, 395 { 396 name: "invalid lookup with container id with disabled legacy identifiers", 397 cm: &apiv1.EndpointChangeRequest{ 398 ContainerID: "1234", 399 DisableLegacyIdentifiers: true, 400 }, 401 setupArgs: func() args { 402 return args{ 403 endpointid.NewID(endpointid.ContainerIdPrefix, "1234"), 404 } 405 }, 406 setupWant: func() want { 407 return want{ 408 ep: false, 409 err: nil, 410 errCheck: assert.EqualValues, 411 } 412 }, 413 }, 414 } 415 for _, tt := range tests { 416 t.Run(tt.name, func(t *testing.T) { 417 var ep *endpoint.Endpoint 418 var err error 419 mgr := New(&dummyEpSyncher{}, nil, nil) 420 if tt.cm != nil { 421 ep, err = endpoint.NewEndpointFromChangeModel(context.Background(), s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), tt.cm) 422 require.NoErrorf(t, err, "Test Name: %s", tt.name) 423 err = mgr.expose(ep) 424 require.NoErrorf(t, err, "Test Name: %s", tt.name) 425 } 426 427 args := tt.setupArgs() 428 want := tt.setupWant() 429 got, err := mgr.Lookup(args.id) 430 want.errCheck(t, want.err, err, "Test Name: %s", tt.name) 431 if want.ep { 432 require.EqualValuesf(t, ep, got, "Test Name: %s", tt.name) 433 } else { 434 require.Nilf(t, got, "Test Name: %s", tt.name) 435 } 436 }) 437 } 438 } 439 440 func TestLookupCiliumID(t *testing.T) { 441 s := setupEndpointManagerSuite(t) 442 443 mgr := New(&dummyEpSyncher{}, nil, nil) 444 ep := endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 2, endpoint.StateReady) 445 type args struct { 446 id uint16 447 } 448 type want struct { 449 ep *endpoint.Endpoint 450 } 451 tests := []struct { 452 name string 453 setupArgs func() args 454 setupWant func() want 455 preTestRun func() 456 postTestRun func() 457 }{ 458 { 459 name: "existing cilium ID", 460 preTestRun: func() { 461 ep.ID = 1 462 require.Nil(t, mgr.expose(ep)) 463 }, 464 setupArgs: func() args { 465 return args{ 466 1, 467 } 468 }, 469 setupWant: func() want { 470 return want{ 471 ep: ep, 472 } 473 }, 474 postTestRun: func() { 475 mgr.WaitEndpointRemoved(ep) 476 ep.ID = 0 477 }, 478 }, 479 { 480 name: "non-existing cilium ID", 481 preTestRun: func() { 482 }, 483 setupArgs: func() args { 484 return args{ 485 1, 486 } 487 }, 488 setupWant: func() want { 489 return want{ 490 ep: nil, 491 } 492 }, 493 postTestRun: func() { 494 }, 495 }, 496 } 497 for _, tt := range tests { 498 tt.preTestRun() 499 args := tt.setupArgs() 500 want := tt.setupWant() 501 got := mgr.LookupCiliumID(args.id) 502 exists := mgr.EndpointExists(args.id) 503 require.EqualValuesf(t, want.ep, got, "Test Name: %s", tt.name) 504 require.Equal(t, want.ep != nil, exists, "Test Name: %s", tt.name) 505 tt.postTestRun() 506 } 507 } 508 509 func TestLookupCNIAttachmentID(t *testing.T) { 510 s := setupEndpointManagerSuite(t) 511 512 mgr := New(&dummyEpSyncher{}, nil, nil) 513 ep, err := endpoint.NewEndpointFromChangeModel(context.Background(), s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), &apiv1.EndpointChangeRequest{ 514 ContainerID: "foo", 515 ContainerInterfaceName: "bar", 516 }) 517 require.Nil(t, err) 518 require.Nil(t, mgr.expose(ep)) 519 520 good := mgr.LookupCNIAttachmentID("foo:bar") 521 require.EqualValues(t, ep, good) 522 523 bad := mgr.LookupCNIAttachmentID("foo") 524 require.Nil(t, bad) 525 526 bad = mgr.LookupCNIAttachmentID("asdf") 527 require.Nil(t, bad) 528 } 529 530 func TestLookupIPv4(t *testing.T) { 531 s := setupEndpointManagerSuite(t) 532 533 mgr := New(&dummyEpSyncher{}, nil, nil) 534 ep := endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 4, endpoint.StateReady) 535 type args struct { 536 ip string 537 } 538 type want struct { 539 ep *endpoint.Endpoint 540 } 541 tests := []struct { 542 name string 543 setupArgs func() args 544 setupWant func() want 545 preTestRun func() 546 postTestRun func() 547 }{ 548 { 549 name: "existing LookupIPv4", 550 preTestRun: func() { 551 ep.IPv4 = netip.MustParseAddr("127.0.0.1") 552 require.Nil(t, mgr.expose(ep)) 553 }, 554 setupArgs: func() args { 555 return args{ 556 "127.0.0.1", 557 } 558 }, 559 setupWant: func() want { 560 return want{ 561 ep: ep, 562 } 563 }, 564 postTestRun: func() { 565 mgr.WaitEndpointRemoved(ep) 566 ep.IPv4 = netip.Addr{} 567 }, 568 }, 569 { 570 name: "non-existing LookupIPv4", 571 preTestRun: func() { 572 }, 573 setupArgs: func() args { 574 return args{ 575 "127.0.0.1", 576 } 577 }, 578 setupWant: func() want { 579 return want{ 580 ep: nil, 581 } 582 }, 583 postTestRun: func() { 584 }, 585 }, 586 } 587 for _, tt := range tests { 588 tt.preTestRun() 589 args := tt.setupArgs() 590 want := tt.setupWant() 591 got := mgr.LookupIPv4(args.ip) 592 require.EqualValuesf(t, want.ep, got, "Test Name: %s", tt.name) 593 tt.postTestRun() 594 } 595 } 596 597 func TestLookupCEPName(t *testing.T) { 598 s := setupEndpointManagerSuite(t) 599 mgr := New(&dummyEpSyncher{}, nil, nil) 600 type args struct { 601 podName string 602 } 603 type want struct { 604 ep *endpoint.Endpoint 605 } 606 tests := []struct { 607 name string 608 cm apiv1.EndpointChangeRequest 609 setupArgs func() args 610 setupWant func(*endpoint.Endpoint) want 611 preTestRun func(*endpoint.Endpoint) 612 postTestRun func(*endpoint.Endpoint) 613 }{ 614 { 615 name: "existing pod name", 616 cm: apiv1.EndpointChangeRequest{ 617 K8sNamespace: "default", 618 K8sPodName: "foo", 619 }, 620 preTestRun: func(ep *endpoint.Endpoint) { 621 require.Nil(t, mgr.expose(ep)) 622 }, 623 setupArgs: func() args { 624 return args{ 625 "default/foo", 626 } 627 }, 628 setupWant: func(ep *endpoint.Endpoint) want { 629 return want{ 630 ep: ep, 631 } 632 }, 633 postTestRun: func(ep *endpoint.Endpoint) { 634 mgr.WaitEndpointRemoved(ep) 635 }, 636 }, 637 { 638 name: "existing pod name with container interface name", 639 cm: apiv1.EndpointChangeRequest{ 640 K8sNamespace: "default", 641 K8sPodName: "bar", 642 ContainerInterfaceName: "eth1", 643 DisableLegacyIdentifiers: true, 644 }, 645 preTestRun: func(ep *endpoint.Endpoint) { 646 require.Nil(t, mgr.expose(ep)) 647 }, 648 setupArgs: func() args { 649 return args{ 650 "default/bar-eth1", 651 } 652 }, 653 setupWant: func(ep *endpoint.Endpoint) want { 654 return want{ 655 ep: ep, 656 } 657 }, 658 postTestRun: func(ep *endpoint.Endpoint) { 659 mgr.WaitEndpointRemoved(ep) 660 }, 661 }, 662 { 663 name: "non-existing PodName", 664 preTestRun: func(ep *endpoint.Endpoint) { 665 }, 666 setupArgs: func() args { 667 return args{ 668 "default/foo", 669 } 670 }, 671 setupWant: func(ep *endpoint.Endpoint) want { 672 return want{ 673 ep: nil, 674 } 675 }, 676 postTestRun: func(ep *endpoint.Endpoint) { 677 }, 678 }, 679 } 680 for _, tt := range tests { 681 ep, err := endpoint.NewEndpointFromChangeModel(context.Background(), s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), &tt.cm) 682 require.NoErrorf(t, err, "Test Name: %s", tt.name) 683 tt.preTestRun(ep) 684 args := tt.setupArgs() 685 want := tt.setupWant(ep) 686 got := mgr.LookupCEPName(args.podName) 687 require.EqualValues(t, want.ep, got, "Test Name: %s", tt.name) 688 tt.postTestRun(ep) 689 } 690 } 691 692 func TestUpdateReferences(t *testing.T) { 693 s := setupEndpointManagerSuite(t) 694 var ep *endpoint.Endpoint 695 type want struct { 696 ep *endpoint.Endpoint 697 } 698 tests := []struct { 699 name string 700 cm apiv1.EndpointChangeRequest 701 setupWant func() want 702 }{ 703 { 704 name: "Updating all references", 705 cm: apiv1.EndpointChangeRequest{ 706 K8sNamespace: "default", 707 K8sPodName: "foo", 708 ContainerID: "container", 709 DockerEndpointID: "dockerendpointID", 710 Addressing: &apiv1.AddressPair{ 711 IPV4: "127.0.0.1", 712 }, 713 ContainerName: "containername", 714 }, 715 setupWant: func() want { 716 return want{ 717 ep: ep, 718 } 719 }, 720 }, 721 } 722 for _, tt := range tests { 723 var err error 724 ep, err = endpoint.NewEndpointFromChangeModel(context.Background(), s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), &tt.cm) 725 require.NoErrorf(t, err, "Test Name: %s", tt.name) 726 mgr := New(&dummyEpSyncher{}, nil, nil) 727 728 err = mgr.expose(ep) 729 require.NoErrorf(t, err, "Test Name: %s", tt.name) 730 want := tt.setupWant() 731 mgr.updateReferencesLocked(ep, ep.Identifiers()) 732 733 ep = mgr.LookupCNIAttachmentID(want.ep.GetCNIAttachmentID()) 734 require.EqualValues(t, want.ep, ep, "Test Name: %s", tt.name) 735 736 ep = mgr.lookupDockerEndpoint(want.ep.GetDockerEndpointID()) 737 require.EqualValues(t, want.ep, ep, "Test Name: %s", tt.name) 738 739 ep = mgr.LookupIPv4(want.ep.IPv4.String()) 740 require.EqualValues(t, want.ep, ep, "Test Name: %s", tt.name) 741 742 ep = mgr.lookupDockerContainerName(want.ep.GetContainerName()) 743 require.EqualValues(t, want.ep, ep, "Test Name: %s", tt.name) 744 745 ep = mgr.LookupCEPName(want.ep.GetK8sNamespaceAndCEPName()) 746 require.EqualValues(t, want.ep, ep, "Test Name: %s", tt.name) 747 748 eps := mgr.GetEndpointsByPodName(want.ep.GetK8sNamespaceAndPodName()) 749 require.Len(t, eps, 1) 750 require.EqualValues(t, want.ep, eps[0], "Test Name: %s", tt.name) 751 } 752 } 753 754 func TestRemove(t *testing.T) { 755 s := setupEndpointManagerSuite(t) 756 mgr := New(&dummyEpSyncher{}, nil, nil) 757 ep := endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 7, endpoint.StateReady) 758 type args struct{} 759 type want struct{} 760 tests := []struct { 761 name string 762 setupArgs func() args 763 setupWant func() want 764 preTestRun func() 765 postTestRun func() 766 }{ 767 { 768 name: "Updating all references", 769 preTestRun: func() { 770 ep.ID = 1 771 require.Nil(t, mgr.expose(ep)) 772 }, 773 setupArgs: func() args { 774 return args{} 775 }, 776 setupWant: func() want { 777 return want{} 778 }, 779 postTestRun: func() { 780 }, 781 }, 782 } 783 for _, tt := range tests { 784 tt.preTestRun() 785 786 mgr.RemoveAll(t) 787 require.Equal(t, 0, len(mgr.endpoints), "Test Name: %s", tt.name) 788 require.Equal(t, 0, len(mgr.endpointsAux), "Test Name: %s", tt.name) 789 tt.postTestRun() 790 } 791 } 792 793 func TestHasGlobalCT(t *testing.T) { 794 s := setupEndpointManagerSuite(t) 795 796 mgr := New(&dummyEpSyncher{}, nil, nil) 797 ep := endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 1, endpoint.StateReady) 798 type want struct { 799 result bool 800 } 801 tests := []struct { 802 name string 803 setupWant func() want 804 preTestRun func() 805 postTestRun func() 806 }{ 807 { 808 name: "Endpoint with Conntrack global", 809 preTestRun: func() { 810 ep.ID = 1 811 ep.Options = option.NewIntOptions(&endpoint.EndpointMutableOptionLibrary) 812 require.Nil(t, mgr.expose(ep)) 813 }, 814 setupWant: func() want { 815 return want{ 816 result: true, 817 } 818 }, 819 postTestRun: func() { 820 mgr.WaitEndpointRemoved(ep) 821 ep = endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 1, endpoint.StateReady) 822 ep.ID = 0 823 ep.Options = nil 824 }, 825 }, 826 { 827 name: "Endpoint with Conntrack local", 828 preTestRun: func() { 829 ep.ID = 1 830 ep.Options = option.NewIntOptions(&endpoint.EndpointMutableOptionLibrary) 831 ep.Options.SetIfUnset(option.ConntrackLocal, option.OptionEnabled) 832 require.Nil(t, mgr.expose(ep)) 833 }, 834 setupWant: func() want { 835 return want{ 836 result: false, 837 } 838 }, 839 postTestRun: func() { 840 mgr.WaitEndpointRemoved(ep) 841 ep = endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 1, endpoint.StateReady) 842 ep.ID = 0 843 ep.Options = nil 844 }, 845 }, 846 } 847 for _, tt := range tests { 848 tt.preTestRun() 849 want := tt.setupWant() 850 got := mgr.HasGlobalCT() 851 require.EqualValues(t, want.result, got, "Test Name: %s", tt.name) 852 tt.postTestRun() 853 } 854 } 855 856 func TestWaitForEndpointsAtPolicyRev(t *testing.T) { 857 s := setupEndpointManagerSuite(t) 858 mgr := New(&dummyEpSyncher{}, nil, nil) 859 ep := endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 1, endpoint.StateReady) 860 type args struct { 861 ctx context.Context 862 rev uint64 863 cancel context.CancelFunc 864 } 865 type want struct { 866 err error 867 errCheck assert.ComparisonAssertionFunc 868 } 869 tests := []struct { 870 name string 871 setupArgs func() args 872 setupWant func() want 873 preTestRun func() 874 postTestRun func() 875 }{ 876 { 877 name: "Endpoint with revision already set", 878 preTestRun: func() { 879 ep.ID = 1 880 ep.SetPolicyRevision(5) 881 require.Nil(t, mgr.expose(ep)) 882 }, 883 setupArgs: func() args { 884 return args{ 885 ctx: context.Background(), 886 rev: 5, 887 } 888 }, 889 setupWant: func() want { 890 return want{ 891 err: nil, 892 errCheck: assert.EqualValues, 893 } 894 }, 895 postTestRun: func() { 896 mgr.WaitEndpointRemoved(ep) 897 ep = endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 1, endpoint.StateReady) 898 }, 899 }, 900 { 901 name: "Context already timed out", 902 preTestRun: func() { 903 ep.ID = 1 904 ep.SetPolicyRevision(5) 905 require.Nil(t, mgr.expose(ep)) 906 }, 907 setupArgs: func() args { 908 ctx, cancel := context.WithTimeout(context.Background(), 0) 909 return args{ 910 ctx: ctx, 911 rev: 5, 912 cancel: cancel, 913 } 914 }, 915 setupWant: func() want { 916 return want{ 917 err: nil, 918 errCheck: assert.NotEqualValues, 919 } 920 }, 921 postTestRun: func() { 922 mgr.WaitEndpointRemoved(ep) 923 ep = endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 1, endpoint.StateReady) 924 }, 925 }, 926 { 927 name: "Revision is will never be set to the waiting revision", 928 preTestRun: func() { 929 ep.ID = 1 930 ep.SetPolicyRevision(4) 931 require.Nil(t, mgr.expose(ep)) 932 }, 933 setupArgs: func() args { 934 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 935 return args{ 936 ctx: ctx, 937 rev: 5, 938 cancel: cancel, 939 } 940 }, 941 setupWant: func() want { 942 return want{ 943 err: nil, 944 errCheck: assert.NotEqualValues, 945 } 946 }, 947 postTestRun: func() { 948 mgr.WaitEndpointRemoved(ep) 949 ep = endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 1, endpoint.StateReady) 950 }, 951 }, 952 } 953 for _, tt := range tests { 954 tt.preTestRun() 955 args := tt.setupArgs() 956 want := tt.setupWant() 957 got := mgr.WaitForEndpointsAtPolicyRev(args.ctx, args.rev) 958 want.errCheck(t, want.err, got, "Test Name: %s", tt.name) 959 if args.cancel != nil { 960 args.cancel() 961 } 962 tt.postTestRun() 963 } 964 } 965 966 func TestMissingNodeLabelsUpdate(t *testing.T) { 967 // Initialize label filter config. 968 labelsfilter.ParseLabelPrefixCfg(nil, nil, "") 969 s := setupEndpointManagerSuite(t) 970 mgr := New(&dummyEpSyncher{}, nil, nil) 971 hostEPID := uint16(17) 972 973 // Initialize the local node watcher before the host endpoint is created. 974 // These labels are not propagated to the endpoint manager. 975 mgr.localNodeStore = node.NewTestLocalNodeStore(node.LocalNode{Node: types.Node{}}) 976 mgr.startNodeLabelsObserver(nil) 977 mgr.localNodeStore.Update(func(ln *node.LocalNode) { ln.Labels = map[string]string{"k1": "v1"} }) 978 _, ok := mgr.endpoints[hostEPID] 979 require.EqualValues(t, ok, false) 980 981 // Create host endpoint and expose it in the endpoint manager. 982 ep := endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 1, endpoint.StateReady) 983 ep.SetIsHost(true) 984 ep.ID = hostEPID 985 require.Nil(t, mgr.expose(ep)) 986 987 // Update node labels and verify that the node labels are updated correctly even if the old 988 // labels {k1=v1} are not present in the endpoint manager's state. 989 mgr.localNodeStore.Update(func(ln *node.LocalNode) { ln.Labels = map[string]string{"k2": "v2"} }) 990 hostEP, ok := mgr.endpoints[hostEPID] 991 require.EqualValues(t, ok, true) 992 got := hostEP.OpLabels.IdentityLabels().K8sStringMap() 993 require.EqualValues(t, map[string]string{"k2": "v2"}, got) 994 } 995 996 func TestUpdateHostEndpointLabels(t *testing.T) { 997 // Initialize label filter config. 998 labelsfilter.ParseLabelPrefixCfg([]string{"k8s:!ignore1", "k8s:!ignore2"}, nil, "") 999 s := setupEndpointManagerSuite(t) 1000 mgr := New(&dummyEpSyncher{}, nil, nil) 1001 hostEPID := uint16(17) 1002 type args struct { 1003 oldLabels, newLabels map[string]string 1004 } 1005 type want struct { 1006 labels map[string]string 1007 labelsCheck assert.ComparisonAssertionFunc 1008 } 1009 tests := []struct { 1010 name string 1011 setupArgs func() args 1012 setupWant func() want 1013 preTestRun func() 1014 postTestRun func() 1015 }{ 1016 { 1017 name: "Add labels", 1018 preTestRun: func() { 1019 ep := endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 1, endpoint.StateReady) 1020 ep.SetIsHost(true) 1021 ep.ID = hostEPID 1022 require.Nil(t, mgr.expose(ep)) 1023 }, 1024 setupArgs: func() args { 1025 return args{ 1026 newLabels: map[string]string{"k1": "v1"}, 1027 } 1028 }, 1029 setupWant: func() want { 1030 return want{ 1031 labels: map[string]string{"k1": "v1"}, 1032 labelsCheck: assert.EqualValues, 1033 } 1034 }, 1035 postTestRun: func() { 1036 if hostEP, ok := mgr.endpoints[hostEPID]; ok { 1037 mgr.WaitEndpointRemoved(hostEP) 1038 } 1039 }, 1040 }, 1041 { 1042 name: "Update labels", 1043 preTestRun: func() { 1044 ep := endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 1, endpoint.StateReady) 1045 ep.SetIsHost(true) 1046 ep.ID = hostEPID 1047 ep.OpLabels.Custom = labels.Labels{"k1": labels.NewLabel("k1", "v1", labels.LabelSourceK8s)} 1048 require.Nil(t, mgr.expose(ep)) 1049 }, 1050 setupArgs: func() args { 1051 return args{ 1052 oldLabels: map[string]string{"k1": "v1"}, 1053 newLabels: map[string]string{"k2": "v2"}, 1054 } 1055 }, 1056 setupWant: func() want { 1057 return want{ 1058 labels: map[string]string{"k2": "v2"}, 1059 labelsCheck: assert.EqualValues, 1060 } 1061 }, 1062 postTestRun: func() { 1063 if hostEP, ok := mgr.endpoints[hostEPID]; ok { 1064 mgr.WaitEndpointRemoved(hostEP) 1065 } 1066 }, 1067 }, 1068 { 1069 name: "Ignore labels", 1070 preTestRun: func() { 1071 ep := endpoint.NewTestEndpointWithState(t, s, s, testipcache.NewMockIPCache(), &endpoint.FakeEndpointProxy{}, testidentity.NewMockIdentityAllocator(nil), 1, endpoint.StateReady) 1072 ep.SetIsHost(true) 1073 ep.ID = hostEPID 1074 ep.OpLabels.Custom = labels.Labels{"k1": labels.NewLabel("k1", "v1", labels.LabelSourceK8s)} 1075 require.Nil(t, mgr.expose(ep)) 1076 }, 1077 setupArgs: func() args { 1078 return args{ 1079 oldLabels: map[string]string{"k1": "v1"}, 1080 newLabels: map[string]string{"k1": "v1", "ignore1": "v2", "ignore2": "v2"}, 1081 } 1082 }, 1083 setupWant: func() want { 1084 return want{ 1085 labels: map[string]string{"k1": "v1"}, 1086 labelsCheck: assert.EqualValues, 1087 } 1088 }, 1089 postTestRun: func() { 1090 if hostEP, ok := mgr.endpoints[hostEPID]; ok { 1091 mgr.WaitEndpointRemoved(hostEP) 1092 } 1093 }, 1094 }, 1095 } 1096 for _, tt := range tests { 1097 tt.preTestRun() 1098 args := tt.setupArgs() 1099 want := tt.setupWant() 1100 mgr.localNodeStore = node.NewTestLocalNodeStore(node.LocalNode{Node: types.Node{ 1101 Labels: args.oldLabels, 1102 }}) 1103 mgr.startNodeLabelsObserver(args.oldLabels) 1104 mgr.localNodeStore.Update(func(ln *node.LocalNode) { ln.Labels = args.newLabels }) 1105 1106 hostEP, ok := mgr.endpoints[hostEPID] 1107 require.EqualValues(t, ok, true) 1108 got := hostEP.OpLabels.IdentityLabels().K8sStringMap() 1109 want.labelsCheck(t, want.labels, got, "Test Name: %s", tt.name) 1110 tt.postTestRun() 1111 } 1112 }