github.com/cilium/cilium@v1.16.2/pkg/k8s/node_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package k8s 5 6 import ( 7 "testing" 8 9 "github.com/stretchr/testify/require" 10 11 "github.com/cilium/cilium/pkg/annotation" 12 slim_corev1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1" 13 slim_metav1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1" 14 nodeAddressing "github.com/cilium/cilium/pkg/node/addressing" 15 "github.com/cilium/cilium/pkg/option" 16 "github.com/cilium/cilium/pkg/source" 17 ) 18 19 func TestParseNode(t *testing.T) { 20 prevAnnotateK8sNode := option.Config.AnnotateK8sNode 21 option.Config.AnnotateK8sNode = true 22 defer func() { 23 option.Config.AnnotateK8sNode = prevAnnotateK8sNode 24 }() 25 26 // PodCIDR takes precedence over annotations 27 k8sNode := &slim_corev1.Node{ 28 ObjectMeta: slim_metav1.ObjectMeta{ 29 Name: "node1", 30 Annotations: map[string]string{ 31 annotation.V4CIDRName: "10.254.0.0/16", 32 annotation.V6CIDRName: "f00d:aaaa:bbbb:cccc:dddd:eeee::/112", 33 annotation.CiliumHostIP: "10.254.9.9", 34 annotation.CiliumHostIPv6: "fd00:10:244:1::8ace", 35 "cilium.io/foo": "value", 36 "qux.cilium.io/foo": "value", 37 "fr3d.qux.cilium.io/foo": "value", 38 "other.whatever.io/foo": "value", 39 }, 40 Labels: map[string]string{ 41 "type": "m5.xlarge", 42 }, 43 }, 44 Spec: slim_corev1.NodeSpec{ 45 PodCIDR: "10.1.0.0/16", 46 }, 47 } 48 49 n := ParseNode(k8sNode, source.Local) 50 require.Equal(t, "node1", n.Name) 51 require.NotNil(t, n.IPv4AllocCIDR) 52 require.Equal(t, "10.1.0.0/16", n.IPv4AllocCIDR.String()) 53 require.NotNil(t, n.IPv6AllocCIDR) 54 require.Equal(t, "f00d:aaaa:bbbb:cccc:dddd:eeee::/112", n.IPv6AllocCIDR.String()) 55 require.Equal(t, "m5.xlarge", n.Labels["type"]) 56 require.Equal(t, 2, len(n.IPAddresses)) 57 require.Equal(t, "10.254.9.9", n.IPAddresses[0].IP.String()) 58 require.Equal(t, nodeAddressing.NodeCiliumInternalIP, n.IPAddresses[0].Type) 59 require.Equal(t, "fd00:10:244:1::8ace", n.IPAddresses[1].IP.String()) 60 require.Equal(t, nodeAddressing.NodeCiliumInternalIP, n.IPAddresses[1].Type) 61 62 for _, key := range []string{"cilium.io/foo", "qux.cilium.io/foo", "fr3d.qux.cilium.io/foo"} { 63 require.Equal(t, "value", n.Annotations[key]) 64 } 65 require.NotContains(t, n.Annotations, "other.whatever.io/foo") 66 67 // No IPv6 annotation 68 k8sNode = &slim_corev1.Node{ 69 ObjectMeta: slim_metav1.ObjectMeta{ 70 Name: "node2", 71 Annotations: map[string]string{ 72 annotation.V4CIDRName: "10.254.0.0/16", 73 }, 74 }, 75 Spec: slim_corev1.NodeSpec{ 76 PodCIDR: "10.1.0.0/16", 77 }, 78 } 79 80 n = ParseNode(k8sNode, source.Local) 81 require.Equal(t, "node2", n.Name) 82 require.NotNil(t, n.IPv4AllocCIDR) 83 require.Equal(t, "10.1.0.0/16", n.IPv4AllocCIDR.String()) 84 require.Nil(t, n.IPv6AllocCIDR) 85 86 // No IPv6 annotation but PodCIDR with v6 87 k8sNode = &slim_corev1.Node{ 88 ObjectMeta: slim_metav1.ObjectMeta{ 89 Name: "node2", 90 Annotations: map[string]string{ 91 annotation.V4CIDRName: "10.254.0.0/16", 92 }, 93 }, 94 Spec: slim_corev1.NodeSpec{ 95 PodCIDR: "f00d:aaaa:bbbb:cccc:dddd:eeee::/112", 96 }, 97 } 98 99 n = ParseNode(k8sNode, source.Local) 100 require.Equal(t, "node2", n.Name) 101 require.NotNil(t, n.IPv4AllocCIDR) 102 require.Equal(t, "10.254.0.0/16", n.IPv4AllocCIDR.String()) 103 require.NotNil(t, n.IPv6AllocCIDR) 104 require.Equal(t, "f00d:aaaa:bbbb:cccc:dddd:eeee::/112", n.IPv6AllocCIDR.String()) 105 106 // No IPv4/IPv6 annotations but PodCIDRs with IPv4/IPv6 107 k8sNode = &slim_corev1.Node{ 108 ObjectMeta: slim_metav1.ObjectMeta{ 109 Name: "node2", 110 Annotations: map[string]string{ 111 annotation.V4CIDRName: "10.254.0.0/16", 112 }, 113 }, 114 Spec: slim_corev1.NodeSpec{ 115 PodCIDR: "10.1.0.0/16", 116 PodCIDRs: []string{"10.1.0.0/16", "f00d:aaaa:bbbb:cccc:dddd:eeee::/112"}, 117 }, 118 } 119 120 n = ParseNode(k8sNode, source.Local) 121 require.Equal(t, "node2", n.Name) 122 require.NotNil(t, n.IPv4AllocCIDR) 123 require.Equal(t, "10.1.0.0/16", n.IPv4AllocCIDR.String()) 124 require.NotNil(t, n.IPv6AllocCIDR) 125 require.Equal(t, "f00d:aaaa:bbbb:cccc:dddd:eeee::/112", n.IPv6AllocCIDR.String()) 126 127 // Node with multiple status addresses of the same type and family 128 expected := []string{"1.2.3.4", "f00d:aaaa:bbbb:cccc:dddd:eeee:0:1", "4.3.2.1", "f00d:aaaa:bbbb:cccc:dddd:eeef:0:1"} 129 notExpected := []string{"5.6.7.8", "f00d:aaaa:bbbb:cccc:dddd:aaaa::1", "8.7.6.5", "f00d:aaaa:bbbb:cccc:dddd:aaab::1"} 130 k8sNode = &slim_corev1.Node{ 131 ObjectMeta: slim_metav1.ObjectMeta{ 132 Name: "node2", 133 Annotations: map[string]string{}, 134 }, 135 Spec: slim_corev1.NodeSpec{ 136 PodCIDR: "10.1.0.0/16", 137 }, 138 Status: slim_corev1.NodeStatus{ 139 Addresses: []slim_corev1.NodeAddress{ 140 { 141 Type: slim_corev1.NodeInternalIP, 142 Address: expected[0], 143 }, 144 { 145 Type: slim_corev1.NodeInternalIP, 146 Address: notExpected[0], 147 }, 148 { 149 Type: slim_corev1.NodeInternalIP, 150 Address: expected[1], 151 }, 152 { 153 Type: slim_corev1.NodeInternalIP, 154 Address: notExpected[1], 155 }, 156 { 157 Type: slim_corev1.NodeExternalIP, 158 Address: expected[2], 159 }, 160 { 161 Type: slim_corev1.NodeExternalIP, 162 Address: notExpected[2], 163 }, 164 { 165 Type: slim_corev1.NodeExternalIP, 166 Address: expected[3], 167 }, 168 { 169 Type: slim_corev1.NodeExternalIP, 170 Address: notExpected[3], 171 }, 172 }, 173 }, 174 } 175 176 n = ParseNode(k8sNode, source.Local) 177 require.Equal(t, "node2", n.Name) 178 require.NotNil(t, n.IPv4AllocCIDR) 179 require.Equal(t, "10.1.0.0/16", n.IPv4AllocCIDR.String()) 180 require.Equal(t, len(expected), len(n.IPAddresses)) 181 addrsFound := 0 182 for _, addr := range n.IPAddresses { 183 for _, expect := range expected { 184 if addr.IP.String() == expect { 185 addrsFound++ 186 } 187 } 188 } 189 require.Equal(t, len(expected), addrsFound) 190 } 191 192 func TestParseNodeWithoutAnnotations(t *testing.T) { 193 prevAnnotateK8sNode := option.Config.AnnotateK8sNode 194 option.Config.AnnotateK8sNode = false 195 defer func() { 196 option.Config.AnnotateK8sNode = prevAnnotateK8sNode 197 }() 198 199 // PodCIDR takes precedence over annotations 200 k8sNode := &slim_corev1.Node{ 201 ObjectMeta: slim_metav1.ObjectMeta{ 202 Name: "node1", 203 Annotations: map[string]string{ 204 annotation.V4CIDRName: "10.254.0.0/16", 205 annotation.V6CIDRName: "f00d:aaaa:bbbb:cccc:dddd:eeee::/112", 206 "cilium.io/foo": "value", 207 "qux.cilium.io/foo": "value", 208 "fr3d.qux.cilium.io/foo": "value", 209 "other.whatever.io/foo": "value", 210 }, 211 Labels: map[string]string{ 212 "type": "m5.xlarge", 213 }, 214 }, 215 Spec: slim_corev1.NodeSpec{ 216 PodCIDR: "10.1.0.0/16", 217 }, 218 } 219 220 n := ParseNode(k8sNode, source.Local) 221 require.Equal(t, "node1", n.Name) 222 require.NotNil(t, n.IPv4AllocCIDR) 223 require.Equal(t, "10.1.0.0/16", n.IPv4AllocCIDR.String()) 224 require.Nil(t, n.IPv6AllocCIDR) 225 require.Equal(t, "m5.xlarge", n.Labels["type"]) 226 227 for _, key := range []string{"cilium.io/foo", "qux.cilium.io/foo", "fr3d.qux.cilium.io/foo"} { 228 require.Equal(t, "value", n.Annotations[key]) 229 } 230 require.NotContains(t, n.Annotations, "other.whatever.io/foo") 231 232 // No IPv6 annotation but PodCIDR with v6 233 k8sNode = &slim_corev1.Node{ 234 ObjectMeta: slim_metav1.ObjectMeta{ 235 Name: "node2", 236 Annotations: map[string]string{ 237 annotation.V4CIDRName: "10.254.0.0/16", 238 }, 239 }, 240 Spec: slim_corev1.NodeSpec{ 241 PodCIDR: "f00d:aaaa:bbbb:cccc:dddd:eeee::/112", 242 }, 243 } 244 245 n = ParseNode(k8sNode, source.Local) 246 require.Equal(t, "node2", n.Name) 247 require.Nil(t, n.IPv4AllocCIDR) 248 require.NotNil(t, n.IPv6AllocCIDR) 249 require.Equal(t, "f00d:aaaa:bbbb:cccc:dddd:eeee::/112", n.IPv6AllocCIDR.String()) 250 } 251 252 func Test_ParseNodeAddressType(t *testing.T) { 253 type args struct { 254 k8sNodeType slim_corev1.NodeAddressType 255 } 256 257 type result struct { 258 ciliumNodeType nodeAddressing.AddressType 259 errExists bool 260 } 261 262 tests := []struct { 263 name string 264 args args 265 want result 266 }{ 267 { 268 name: "NodeExternalDNS", 269 args: args{ 270 k8sNodeType: slim_corev1.NodeExternalDNS, 271 }, 272 want: result{ 273 ciliumNodeType: nodeAddressing.NodeExternalDNS, 274 errExists: false, 275 }, 276 }, 277 { 278 name: "NodeExternalIP", 279 args: args{ 280 k8sNodeType: slim_corev1.NodeExternalIP, 281 }, 282 want: result{ 283 ciliumNodeType: nodeAddressing.NodeExternalIP, 284 errExists: false, 285 }, 286 }, 287 { 288 name: "NodeHostName", 289 args: args{ 290 k8sNodeType: slim_corev1.NodeHostName, 291 }, 292 want: result{ 293 ciliumNodeType: nodeAddressing.NodeHostName, 294 errExists: false, 295 }, 296 }, 297 { 298 name: "NodeInternalIP", 299 args: args{ 300 k8sNodeType: slim_corev1.NodeInternalIP, 301 }, 302 want: result{ 303 ciliumNodeType: nodeAddressing.NodeInternalIP, 304 errExists: false, 305 }, 306 }, 307 { 308 name: "NodeInternalDNS", 309 args: args{ 310 k8sNodeType: slim_corev1.NodeInternalDNS, 311 }, 312 want: result{ 313 ciliumNodeType: nodeAddressing.NodeInternalDNS, 314 errExists: false, 315 }, 316 }, 317 { 318 name: "invalid", 319 args: args{ 320 k8sNodeType: slim_corev1.NodeAddressType("lololol"), 321 }, 322 want: result{ 323 ciliumNodeType: nodeAddressing.AddressType("lololol"), 324 errExists: true, 325 }, 326 }, 327 } 328 329 for _, tt := range tests { 330 t.Run(tt.name, func(t *testing.T) { 331 gotNodeAddress, gotErr := ParseNodeAddressType(tt.args.k8sNodeType) 332 res := result{ 333 ciliumNodeType: gotNodeAddress, 334 errExists: gotErr != nil, 335 } 336 require.EqualValues(t, tt.want, res) 337 }) 338 } 339 }