github.com/cilium/cilium@v1.16.2/pkg/node/types/node_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package types 5 6 import ( 7 "fmt" 8 "net" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 15 "github.com/cilium/cilium/pkg/annotation" 16 "github.com/cilium/cilium/pkg/cidr" 17 ipamTypes "github.com/cilium/cilium/pkg/ipam/types" 18 ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" 19 "github.com/cilium/cilium/pkg/node/addressing" 20 "github.com/cilium/cilium/pkg/source" 21 ) 22 23 func TestGetNodeIP(t *testing.T) { 24 n := Node{ 25 Name: "node-1", 26 IPAddresses: []Address{ 27 {IP: net.ParseIP("192.0.2.3"), Type: addressing.NodeExternalIP}, 28 }, 29 } 30 ip := n.GetNodeIP(false) 31 // Return the only IP present 32 require.Equal(t, ip, net.ParseIP("192.0.2.3")) 33 34 n.IPAddresses = append(n.IPAddresses, Address{IP: net.ParseIP("192.0.2.3"), Type: addressing.NodeExternalIP}) 35 ip = n.GetNodeIP(false) 36 // The next priority should be NodeExternalIP 37 require.Equal(t, ip, net.ParseIP("192.0.2.3")) 38 39 n.IPAddresses = append(n.IPAddresses, Address{IP: net.ParseIP("198.51.100.2"), Type: addressing.NodeInternalIP}) 40 ip = n.GetNodeIP(false) 41 // The next priority should be NodeInternalIP 42 require.Equal(t, ip, net.ParseIP("198.51.100.2")) 43 44 n.IPAddresses = append(n.IPAddresses, Address{IP: net.ParseIP("2001:DB8::1"), Type: addressing.NodeExternalIP}) 45 ip = n.GetNodeIP(true) 46 // The next priority should be NodeExternalIP and IPv6 47 require.Equal(t, ip, net.ParseIP("2001:DB8::1")) 48 49 n.IPAddresses = append(n.IPAddresses, Address{IP: net.ParseIP("2001:DB8::2"), Type: addressing.NodeInternalIP}) 50 ip = n.GetNodeIP(true) 51 // The next priority should be NodeInternalIP and IPv6 52 require.Equal(t, ip, net.ParseIP("2001:DB8::2")) 53 54 n.IPAddresses = append(n.IPAddresses, Address{IP: net.ParseIP("198.51.100.2"), Type: addressing.NodeInternalIP}) 55 ip = n.GetNodeIP(false) 56 // Should still return NodeInternalIP and IPv4 57 require.Equal(t, ip, net.ParseIP("198.51.100.2")) 58 } 59 60 func TestGetIPByType(t *testing.T) { 61 n := Node{ 62 Name: "node-1", 63 IPAddresses: []Address{ 64 {IP: net.ParseIP("192.0.2.3"), Type: addressing.NodeExternalIP}, 65 }, 66 } 67 68 ip := n.GetIPByType(addressing.NodeInternalIP, false) 69 require.Nil(t, ip) 70 ip = n.GetIPByType(addressing.NodeInternalIP, true) 71 require.Nil(t, ip) 72 73 ip = n.GetIPByType(addressing.NodeExternalIP, false) 74 require.Equal(t, ip, net.ParseIP("192.0.2.3")) 75 ip = n.GetIPByType(addressing.NodeExternalIP, true) 76 require.Nil(t, ip) 77 78 n = Node{ 79 Name: "node-2", 80 IPAddresses: []Address{ 81 {IP: net.ParseIP("f00b::1"), Type: addressing.NodeCiliumInternalIP}, 82 }, 83 } 84 85 ip = n.GetIPByType(addressing.NodeExternalIP, false) 86 require.Nil(t, ip) 87 ip = n.GetIPByType(addressing.NodeExternalIP, true) 88 require.Nil(t, ip) 89 90 ip = n.GetIPByType(addressing.NodeCiliumInternalIP, false) 91 require.Nil(t, ip) 92 ip = n.GetIPByType(addressing.NodeCiliumInternalIP, true) 93 require.Equal(t, ip, net.ParseIP("f00b::1")) 94 95 n = Node{ 96 Name: "node-3", 97 IPAddresses: []Address{ 98 {IP: net.ParseIP("192.42.0.3"), Type: addressing.NodeExternalIP}, 99 {IP: net.ParseIP("f00d::1"), Type: addressing.NodeExternalIP}, 100 }, 101 } 102 103 ip = n.GetIPByType(addressing.NodeInternalIP, false) 104 require.Nil(t, ip) 105 ip = n.GetIPByType(addressing.NodeInternalIP, true) 106 require.Nil(t, ip) 107 108 ip = n.GetIPByType(addressing.NodeExternalIP, false) 109 require.Equal(t, ip, net.ParseIP("192.42.0.3")) 110 ip = n.GetIPByType(addressing.NodeExternalIP, true) 111 require.Equal(t, ip, net.ParseIP("f00d::1")) 112 } 113 114 func TestParseCiliumNode(t *testing.T) { 115 nodeResource := &ciliumv2.CiliumNode{ 116 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}, 117 Spec: ciliumv2.NodeSpec{ 118 Addresses: []ciliumv2.NodeAddress{ 119 {Type: addressing.NodeInternalIP, IP: "2.2.2.2"}, 120 {Type: addressing.NodeExternalIP, IP: "3.3.3.3"}, 121 {Type: addressing.NodeInternalIP, IP: "c0de::1"}, 122 {Type: addressing.NodeExternalIP, IP: "c0de::2"}, 123 }, 124 Encryption: ciliumv2.EncryptionSpec{ 125 Key: 10, 126 }, 127 IPAM: ipamTypes.IPAMSpec{ 128 PodCIDRs: []string{ 129 "10.10.0.0/16", 130 "c0de::/96", 131 "10.20.0.0/16", 132 "c0fe::/96", 133 }, 134 }, 135 HealthAddressing: ciliumv2.HealthAddressingSpec{ 136 IPv4: "1.1.1.1", 137 IPv6: "c0de::1", 138 }, 139 IngressAddressing: ciliumv2.AddressPair{ 140 IPV4: "1.1.1.2", 141 IPV6: "c0de::2", 142 }, 143 NodeIdentity: uint64(12345), 144 }, 145 } 146 147 n := ParseCiliumNode(nodeResource) 148 require.Equal(t, Node{ 149 Name: "foo", 150 Source: source.CustomResource, 151 IPAddresses: []Address{ 152 {Type: addressing.NodeInternalIP, IP: net.ParseIP("2.2.2.2")}, 153 {Type: addressing.NodeExternalIP, IP: net.ParseIP("3.3.3.3")}, 154 {Type: addressing.NodeInternalIP, IP: net.ParseIP("c0de::1")}, 155 {Type: addressing.NodeExternalIP, IP: net.ParseIP("c0de::2")}, 156 }, 157 EncryptionKey: uint8(10), 158 IPv4AllocCIDR: cidr.MustParseCIDR("10.10.0.0/16"), 159 IPv6AllocCIDR: cidr.MustParseCIDR("c0de::/96"), 160 IPv4SecondaryAllocCIDRs: []*cidr.CIDR{cidr.MustParseCIDR("10.20.0.0/16")}, 161 IPv6SecondaryAllocCIDRs: []*cidr.CIDR{cidr.MustParseCIDR("c0fe::/96")}, 162 IPv4HealthIP: net.ParseIP("1.1.1.1"), 163 IPv6HealthIP: net.ParseIP("c0de::1"), 164 IPv4IngressIP: net.ParseIP("1.1.1.2"), 165 IPv6IngressIP: net.ParseIP("c0de::2"), 166 NodeIdentity: uint32(12345), 167 }, n) 168 } 169 170 func TestNode_ToCiliumNode(t *testing.T) { 171 nodeResource := Node{ 172 Name: "foo", 173 Source: source.CustomResource, 174 IPAddresses: []Address{ 175 {Type: addressing.NodeInternalIP, IP: net.ParseIP("2.2.2.2")}, 176 {Type: addressing.NodeExternalIP, IP: net.ParseIP("3.3.3.3")}, 177 {Type: addressing.NodeInternalIP, IP: net.ParseIP("c0de::1")}, 178 {Type: addressing.NodeExternalIP, IP: net.ParseIP("c0de::2")}, 179 }, 180 EncryptionKey: uint8(10), 181 IPv4AllocCIDR: cidr.MustParseCIDR("10.10.0.0/16"), 182 IPv6AllocCIDR: cidr.MustParseCIDR("c0de::/96"), 183 IPv4SecondaryAllocCIDRs: []*cidr.CIDR{cidr.MustParseCIDR("10.20.0.0/16")}, 184 IPv6SecondaryAllocCIDRs: []*cidr.CIDR{cidr.MustParseCIDR("c0fe::/96")}, 185 IPv4HealthIP: net.ParseIP("1.1.1.1"), 186 IPv6HealthIP: net.ParseIP("c0de::1"), 187 IPv4IngressIP: net.ParseIP("1.1.1.2"), 188 IPv6IngressIP: net.ParseIP("c0de::2"), 189 NodeIdentity: uint32(12345), 190 WireguardPubKey: "6kiIGGPvMiadJ1brWTVfSGXheE3e3k5GjDTxfjMLYx8=", 191 Annotations: map[string]string{ 192 annotation.BGPVRouterAnnoPrefix + "64512": "router-id=172.0.0.3", 193 }, 194 } 195 196 n := nodeResource.ToCiliumNode() 197 require.Equal(t, &ciliumv2.CiliumNode{ 198 ObjectMeta: metav1.ObjectMeta{ 199 Name: "foo", 200 Namespace: "", 201 Annotations: map[string]string{ 202 annotation.BGPVRouterAnnoPrefix + "64512": "router-id=172.0.0.3", 203 }, 204 }, 205 Spec: ciliumv2.NodeSpec{ 206 Addresses: []ciliumv2.NodeAddress{ 207 {Type: addressing.NodeInternalIP, IP: "2.2.2.2"}, 208 {Type: addressing.NodeExternalIP, IP: "3.3.3.3"}, 209 {Type: addressing.NodeInternalIP, IP: "c0de::1"}, 210 {Type: addressing.NodeExternalIP, IP: "c0de::2"}, 211 }, 212 Encryption: ciliumv2.EncryptionSpec{ 213 Key: 10, 214 }, 215 IPAM: ipamTypes.IPAMSpec{ 216 PodCIDRs: []string{ 217 "10.10.0.0/16", 218 "c0de::/96", 219 "10.20.0.0/16", 220 "c0fe::/96", 221 }, 222 }, 223 HealthAddressing: ciliumv2.HealthAddressingSpec{ 224 IPv4: "1.1.1.1", 225 IPv6: "c0de::1", 226 }, 227 IngressAddressing: ciliumv2.AddressPair{ 228 IPV4: "1.1.1.2", 229 IPV6: "c0de::2", 230 }, 231 NodeIdentity: uint64(12345), 232 }, 233 }, n) 234 } 235 236 func TestNodeValidate(t *testing.T) { 237 tests := []struct { 238 name string 239 node Node 240 assert assert.ErrorAssertionFunc 241 }{ 242 { 243 name: "empty cluster", 244 node: Node{Name: "bar"}, 245 assert: assert.Error, 246 }, 247 { 248 name: "empty name", 249 node: Node{Cluster: "foo"}, 250 assert: assert.Error, 251 }, 252 { 253 name: "empty cluster ID", 254 node: Node{Cluster: "foo", Name: "bar"}, 255 assert: assert.NoError, 256 }, 257 { 258 name: "valid cluster ID", 259 node: Node{Cluster: "foo", Name: "bar", ClusterID: 99}, 260 assert: assert.NoError, 261 }, 262 { 263 name: "invalid cluster ID", 264 node: Node{Cluster: "foo", Name: "bar", ClusterID: 260}, 265 assert: assert.Error, 266 }, 267 } 268 269 for _, tt := range tests { 270 t.Run(tt.name, func(t *testing.T) { 271 tt.assert(t, tt.node.validate()) 272 }) 273 } 274 } 275 276 func TestGetIPv4AllocCIDRs(t *testing.T) { 277 var ( 278 cidr1 = cidr.MustParseCIDR("1.0.0.0/24") 279 cidr2 = cidr.MustParseCIDR("2.0.0.0/24") 280 cidr3 = cidr.MustParseCIDR("3.0.0.0/24") 281 ) 282 283 var tests = []struct { 284 // name of test 285 name string 286 // primary ipv4 allocation cidr 287 allocCIDR *cidr.CIDR 288 // secondary ipv4 allocation cidrs 289 secAllocCIDRs []*cidr.CIDR 290 // expected ipv4 cidrs 291 expectedCIDRs []*cidr.CIDR 292 }{ 293 { 294 name: "nil cidrs", 295 allocCIDR: nil, 296 secAllocCIDRs: nil, 297 expectedCIDRs: make([]*cidr.CIDR, 0), 298 }, 299 { 300 name: "one primary and no secondary cidrs", 301 allocCIDR: cidr1, 302 secAllocCIDRs: nil, 303 expectedCIDRs: []*cidr.CIDR{cidr1}, 304 }, 305 { 306 name: "one primary and one secondary cidr", 307 allocCIDR: cidr1, 308 secAllocCIDRs: []*cidr.CIDR{cidr2}, 309 expectedCIDRs: []*cidr.CIDR{cidr1, cidr2}, 310 }, 311 { 312 name: "one primary and multiple secondary cidrs", 313 allocCIDR: cidr1, 314 secAllocCIDRs: []*cidr.CIDR{cidr2, cidr3}, 315 expectedCIDRs: []*cidr.CIDR{cidr1, cidr2, cidr3}, 316 }, 317 } 318 for _, tt := range tests { 319 t.Run(tt.name, func(t *testing.T) { 320 n := Node{ 321 Name: fmt.Sprintf("node-%s", tt.name), 322 IPv4AllocCIDR: tt.allocCIDR, 323 IPv4SecondaryAllocCIDRs: tt.secAllocCIDRs, 324 } 325 326 actual := n.GetIPv4AllocCIDRs() 327 assert.Equal(t, actual, tt.expectedCIDRs) 328 }) 329 } 330 } 331 332 func TestGetIPv6AllocCIDRs(t *testing.T) { 333 var ( 334 cidr2001 = cidr.MustParseCIDR("2001:db8::/32") 335 cidr2002 = cidr.MustParseCIDR("2002:db8::/32") 336 cidr2003 = cidr.MustParseCIDR("2003:db8::/32") 337 ) 338 339 var tests = []struct { 340 // name of test 341 name string 342 // primary ipv6 allocation cidr 343 allocCIDR *cidr.CIDR 344 // secondary ipv6 allocation cidrs 345 secAllocCIDRs []*cidr.CIDR 346 // expected ipv6 cidrs 347 expectedCIDRs []*cidr.CIDR 348 }{ 349 { 350 name: "nil cidrs", 351 allocCIDR: nil, 352 secAllocCIDRs: nil, 353 expectedCIDRs: make([]*cidr.CIDR, 0), 354 }, 355 { 356 name: "one primary and no secondary cidrs", 357 allocCIDR: cidr2001, 358 secAllocCIDRs: nil, 359 expectedCIDRs: []*cidr.CIDR{cidr2001}, 360 }, 361 { 362 name: "one primary and one secondary cidr", 363 allocCIDR: cidr2001, 364 secAllocCIDRs: []*cidr.CIDR{cidr2002}, 365 expectedCIDRs: []*cidr.CIDR{cidr2001, cidr2002}, 366 }, 367 { 368 name: "one primary and multiple secondary cidrs", 369 allocCIDR: cidr2001, 370 secAllocCIDRs: []*cidr.CIDR{cidr2002, cidr2003}, 371 expectedCIDRs: []*cidr.CIDR{cidr2001, cidr2002, cidr2003}, 372 }, 373 } 374 for _, tt := range tests { 375 t.Run(tt.name, func(t *testing.T) { 376 n := Node{ 377 Name: fmt.Sprintf("node-%s", tt.name), 378 IPv6AllocCIDR: tt.allocCIDR, 379 IPv6SecondaryAllocCIDRs: tt.secAllocCIDRs, 380 } 381 382 actual := n.GetIPv6AllocCIDRs() 383 assert.Equal(t, actual, tt.expectedCIDRs) 384 }) 385 } 386 }