github.com/cilium/cilium@v1.16.2/pkg/ipam/metadata/manager_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package metadata 5 6 import ( 7 "errors" 8 "testing" 9 10 "github.com/stretchr/testify/require" 11 "k8s.io/client-go/tools/cache" 12 13 "github.com/cilium/cilium/pkg/annotation" 14 "github.com/cilium/cilium/pkg/ipam" 15 "github.com/cilium/cilium/pkg/k8s/resource" 16 slim_core_v1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1" 17 slim_meta_v1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1" 18 ) 19 20 type mockStore[T comparable] map[resource.Key]T 21 22 func (m mockStore[T]) GetByKey(key resource.Key) (item T, exists bool, err error) { 23 item, exists = m[key] 24 return item, exists, nil 25 } 26 27 func (m mockStore[T]) Get(obj T) (item T, exists bool, err error) { 28 panic("not implemented") 29 } 30 31 func (m mockStore[T]) List() []T { 32 panic("not implemented") 33 } 34 35 func (m mockStore[T]) IterKeys() resource.KeyIter { 36 panic("not implemented") 37 } 38 39 func (m mockStore[T]) IndexKeys(indexName, indexedValue string) ([]string, error) { 40 panic("not implemented") 41 } 42 43 func (m mockStore[T]) ByIndex(indexName, indexedValue string) ([]T, error) { 44 panic("not implemented") 45 } 46 47 func (m mockStore[T]) CacheStore() cache.Store { 48 panic("not implemented") 49 } 50 51 func (m mockStore[T]) Release() { 52 panic("not implemented") 53 } 54 55 func podKey(ns, name string) resource.Key { 56 return resource.Key{ 57 Namespace: ns, 58 Name: name, 59 } 60 } 61 62 func namespaceKey(name string) resource.Key { 63 return resource.Key{ 64 Name: name, 65 } 66 } 67 68 func TestManager_GetIPPoolForPod(t *testing.T) { 69 m := &manager{ 70 namespaceStore: mockStore[*slim_core_v1.Namespace]{ 71 namespaceKey("default"): &slim_core_v1.Namespace{}, 72 namespaceKey("special"): &slim_core_v1.Namespace{ 73 ObjectMeta: slim_meta_v1.ObjectMeta{ 74 Annotations: map[string]string{ 75 annotation.IPAMPoolKey: "namespace-pool", 76 }, 77 }, 78 }, 79 }, 80 podStore: mockStore[*slim_core_v1.Pod]{ 81 podKey("default", "client"): &slim_core_v1.Pod{}, 82 podKey("default", "custom-workload"): &slim_core_v1.Pod{ 83 ObjectMeta: slim_meta_v1.ObjectMeta{ 84 Annotations: map[string]string{ 85 annotation.IPAMPoolKey: "custom-pool", 86 }, 87 }, 88 }, 89 podKey("default", "custom-workload2"): &slim_core_v1.Pod{ 90 ObjectMeta: slim_meta_v1.ObjectMeta{ 91 Annotations: map[string]string{ 92 annotation.IPAMIPv4PoolKey: "ipv4-pool", 93 }, 94 }, 95 }, 96 podKey("default", "custom-workload3"): &slim_core_v1.Pod{ 97 ObjectMeta: slim_meta_v1.ObjectMeta{ 98 Annotations: map[string]string{ 99 annotation.IPAMIPv4PoolKey: "ipv4-pool", 100 annotation.IPAMPoolKey: "custom-pool", 101 }, 102 }, 103 }, 104 podKey("default", "custom-workload4"): &slim_core_v1.Pod{ 105 ObjectMeta: slim_meta_v1.ObjectMeta{ 106 Annotations: map[string]string{ 107 annotation.IPAMIPv4PoolKey: "ipv4-pool", 108 annotation.IPAMIPv6PoolKey: "ipv6-pool", 109 }, 110 }, 111 }, 112 podKey("default", "custom-workload5"): &slim_core_v1.Pod{ 113 ObjectMeta: slim_meta_v1.ObjectMeta{ 114 Annotations: map[string]string{ 115 annotation.IPAMIPv4PoolKey: "ipv4-pool", 116 annotation.IPAMIPv6PoolKey: "ipv6-pool", 117 annotation.IPAMPoolKey: "custom-pool", 118 }, 119 }, 120 }, 121 122 podKey("special", "server"): &slim_core_v1.Pod{}, 123 podKey("special", "server2"): &slim_core_v1.Pod{ 124 ObjectMeta: slim_meta_v1.ObjectMeta{ 125 Annotations: map[string]string{ 126 annotation.IPAMPoolKey: "pod-pool", 127 }, 128 }, 129 }, 130 131 podKey("missing-ns", "pod"): &slim_core_v1.Pod{}, 132 }, 133 } 134 135 tests := []struct { 136 name string 137 owner string 138 ipfamily ipam.Family 139 wantPool string 140 wantErr error 141 }{ 142 { 143 name: "no annotations", 144 owner: "default/client", 145 ipfamily: ipam.IPv4, 146 wantPool: ipam.PoolDefault().String(), 147 }, 148 { 149 name: "not a pod name", 150 owner: "router", 151 ipfamily: ipam.IPv4, 152 wantPool: ipam.PoolDefault().String(), 153 }, 154 { 155 name: "also not a pod name (due to underline)", 156 owner: "default/xwing_net2", 157 ipfamily: ipam.IPv4, 158 wantPool: ipam.PoolDefault().String(), 159 }, 160 { 161 name: "pod annotation", 162 owner: "default/custom-workload", 163 ipfamily: ipam.IPv4, 164 wantPool: "custom-pool", 165 }, 166 { 167 name: "pod annotation only ipv4 pool request ipv4", 168 owner: "default/custom-workload2", 169 ipfamily: ipam.IPv4, 170 wantPool: "ipv4-pool", 171 }, 172 { 173 name: "pod annotation only ipv4 pool request ipv6", 174 owner: "default/custom-workload2", 175 ipfamily: ipam.IPv6, 176 wantPool: ipam.PoolDefault().String(), 177 }, 178 { 179 name: "pod annotation ipv4 and custom pool request ipv4", 180 owner: "default/custom-workload3", 181 ipfamily: ipam.IPv4, 182 wantPool: "ipv4-pool", 183 }, 184 { 185 name: "pod annotation ipv4 and custom pool request ipv6", 186 owner: "default/custom-workload3", 187 ipfamily: ipam.IPv6, 188 wantPool: "custom-pool", 189 }, 190 { 191 name: "pod annotation ipv4 and ipv6 pool request ipv4", 192 owner: "default/custom-workload4", 193 ipfamily: ipam.IPv4, 194 wantPool: "ipv4-pool", 195 }, 196 { 197 name: "pod annotation ipv4 and ipv6 pool request ipv6", 198 owner: "default/custom-workload4", 199 ipfamily: ipam.IPv6, 200 wantPool: "ipv6-pool", 201 }, 202 { 203 name: "pod annotation ipv4, ipv6 and custom pool request ipv4", 204 owner: "default/custom-workload3", 205 ipfamily: ipam.IPv4, 206 wantPool: "ipv4-pool", 207 }, 208 { 209 name: "pod annotation ipv4, ipv6 and custom pool request ipv6", 210 owner: "default/custom-workload5", 211 ipfamily: ipam.IPv6, 212 wantPool: "ipv6-pool", 213 }, 214 { 215 name: "missing pod", 216 owner: "does-not/exist", 217 ipfamily: ipam.IPv4, 218 wantErr: &ResourceNotFound{Resource: "Pod"}, 219 }, 220 { 221 name: "missing namespace", 222 owner: "missing-ns/pod", 223 ipfamily: ipam.IPv4, 224 wantErr: &ResourceNotFound{Resource: "Namespace"}, 225 }, 226 } 227 228 for _, tt := range tests { 229 t.Run(tt.name, func(t *testing.T) { 230 gotPool, err := m.GetIPPoolForPod(tt.owner, tt.ipfamily) 231 if !errors.Is(err, tt.wantErr) { 232 t.Errorf("GetIPPoolForPod() error = %v, wantErr %v", err, tt.wantErr) 233 return 234 } 235 if gotPool != tt.wantPool { 236 t.Errorf("GetIPPoolForPod() gotPool = %v, want %v", gotPool, tt.wantPool) 237 } 238 }) 239 } 240 } 241 242 func TestDefaultManager_DefaultPool(t *testing.T) { 243 defaultPoolManager := defaultIPPoolManager{} 244 245 ipv4Pool, err := defaultPoolManager.GetIPPoolForPod("", ipam.IPv4) 246 require.Nil(t, err) 247 require.Equal(t, ipam.PoolDefault(), ipam.Pool(ipv4Pool)) 248 249 ipv6Pool, err := defaultPoolManager.GetIPPoolForPod("", ipam.IPv6) 250 require.Nil(t, err) 251 require.Equal(t, ipam.PoolDefault(), ipam.Pool(ipv6Pool)) 252 }