github.com/cilium/cilium@v1.16.2/pkg/ipam/crd_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package ipam 5 6 import ( 7 "errors" 8 "fmt" 9 "net" 10 "net/netip" 11 "testing" 12 "time" 13 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 fakeTypes "github.com/cilium/cilium/pkg/datapath/fake/types" 18 ipamOption "github.com/cilium/cilium/pkg/ipam/option" 19 ipamTypes "github.com/cilium/cilium/pkg/ipam/types" 20 "github.com/cilium/cilium/pkg/lock" 21 "github.com/cilium/cilium/pkg/node" 22 "github.com/cilium/cilium/pkg/option" 23 "github.com/cilium/cilium/pkg/trigger" 24 ) 25 26 func TestIPNotAvailableInPoolError(t *testing.T) { 27 err := NewIPNotAvailableInPoolError(net.ParseIP("1.1.1.1")) 28 err2 := NewIPNotAvailableInPoolError(net.ParseIP("1.1.1.1")) 29 assert.Equal(t, err, err2) 30 assert.True(t, errors.Is(err, err2)) 31 32 err = NewIPNotAvailableInPoolError(net.ParseIP("2.1.1.1")) 33 err2 = NewIPNotAvailableInPoolError(net.ParseIP("1.1.1.1")) 34 assert.NotEqual(t, err, err2) 35 assert.False(t, errors.Is(err, err2)) 36 37 err = NewIPNotAvailableInPoolError(net.ParseIP("2.1.1.1")) 38 err2 = errors.New("another error") 39 assert.NotEqual(t, err, err2) 40 assert.False(t, errors.Is(err, err2)) 41 42 err = errors.New("another error") 43 err2 = NewIPNotAvailableInPoolError(net.ParseIP("2.1.1.1")) 44 assert.NotEqual(t, err, err2) 45 assert.False(t, errors.Is(err, err2)) 46 47 err = NewIPNotAvailableInPoolError(net.ParseIP("1.1.1.1")) 48 err2 = nil 49 assert.False(t, errors.Is(err, err2)) 50 51 err = nil 52 err2 = NewIPNotAvailableInPoolError(net.ParseIP("1.1.1.1")) 53 assert.False(t, errors.Is(err, err2)) 54 55 // We don't match against strings. It must be the sentinel value. 56 err = errors.New("IP 2.1.1.1 is not available") 57 err2 = NewIPNotAvailableInPoolError(net.ParseIP("2.1.1.1")) 58 assert.NotEqual(t, err, err2) 59 assert.False(t, errors.Is(err, err2)) 60 } 61 62 var testConfigurationCRD = &option.DaemonConfig{ 63 ConfigPatchMutex: new(lock.RWMutex), 64 EnableIPv4: true, 65 EnableIPv6: false, 66 EnableHealthChecking: true, 67 EnableUnreachableRoutes: false, 68 IPAM: ipamOption.IPAMCRD, 69 } 70 71 func newFakeNodeStore(conf *option.DaemonConfig, t *testing.T) *nodeStore { 72 tr, err := trigger.NewTrigger(trigger.Parameters{ 73 Name: "fake-crd-allocator-node-refresher", 74 MinInterval: 3 * time.Second, 75 TriggerFunc: func(reasons []string) {}, 76 }) 77 if err != nil { 78 log.WithError(err).Fatal("Unable to initialize CiliumNode synchronization trigger") 79 } 80 store := &nodeStore{ 81 allocators: []*crdAllocator{}, 82 allocationPoolSize: map[Family]int{}, 83 conf: conf, 84 refreshTrigger: tr, 85 } 86 return store 87 } 88 89 func TestMarkForReleaseNoAllocate(t *testing.T) { 90 cn := newCiliumNode("node1", 4, 4, 0) 91 dummyResource := ipamTypes.AllocationIP{Resource: "foo"} 92 for i := 1; i <= 4; i++ { 93 cn.Spec.IPAM.Pool[fmt.Sprintf("1.1.1.%d", i)] = dummyResource 94 } 95 96 fakeAddressing := fakeTypes.NewNodeAddressing() 97 conf := testConfigurationCRD 98 initNodeStore.Do(func() { 99 sharedNodeStore = newFakeNodeStore(conf, t) 100 sharedNodeStore.ownNode = cn 101 }) 102 localNodeStore := node.NewTestLocalNodeStore(node.LocalNode{}) 103 ipam := NewIPAM(fakeAddressing, conf, &ownerMock{}, localNodeStore, &ownerMock{}, &resourceMock{}, &mtuMock, nil, nil) 104 ipam.ConfigureAllocator() 105 sharedNodeStore.updateLocalNodeResource(cn) 106 107 // Allocate the first 3 IPs 108 for i := 1; i <= 3; i++ { 109 epipv4 := netip.MustParseAddr(fmt.Sprintf("1.1.1.%d", i)) 110 _, err := ipam.IPv4Allocator.Allocate(epipv4.AsSlice(), fmt.Sprintf("test%d", i), PoolDefault()) 111 require.Nil(t, err) 112 } 113 114 // Update 1.1.1.4 as marked for release like operator would. 115 cn.Status.IPAM.ReleaseIPs["1.1.1.4"] = ipamOption.IPAMMarkForRelease 116 // Attempts to allocate 1.1.1.4 should fail, since it's already marked for release 117 epipv4 := netip.MustParseAddr("1.1.1.4") 118 _, err := ipam.IPv4Allocator.Allocate(epipv4.AsSlice(), "test", PoolDefault()) 119 require.Error(t, err) 120 // Call agent's CRD update function. status for 1.1.1.4 should change from marked for release to ready for release 121 sharedNodeStore.updateLocalNodeResource(cn) 122 require.Equal(t, ipamOption.IPAMReadyForRelease, string(cn.Status.IPAM.ReleaseIPs["1.1.1.4"])) 123 124 // Verify that 1.1.1.3 is denied for release, since it's already in use 125 cn.Status.IPAM.ReleaseIPs["1.1.1.3"] = ipamOption.IPAMMarkForRelease 126 sharedNodeStore.updateLocalNodeResource(cn) 127 require.Equal(t, ipamOption.IPAMDoNotRelease, string(cn.Status.IPAM.ReleaseIPs["1.1.1.3"])) 128 }