github.com/cilium/cilium@v1.16.2/pkg/policy/api/egress_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package api 5 6 import ( 7 "context" 8 "fmt" 9 "net/netip" 10 "testing" 11 12 "github.com/stretchr/testify/require" 13 "k8s.io/apimachinery/pkg/util/intstr" 14 15 slim_metav1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1" 16 ) 17 18 func TestRequiresDerivativeRuleWithoutToGroups(t *testing.T) { 19 eg := EgressRule{} 20 require.Equal(t, false, eg.RequiresDerivative()) 21 } 22 23 func TestRequiresDerivativeRuleWithToGroups(t *testing.T) { 24 eg := EgressRule{} 25 eg.ToGroups = []Groups{ 26 GetGroupsRule(), 27 } 28 require.Equal(t, true, eg.RequiresDerivative()) 29 } 30 31 func TestCreateDerivativeRuleWithoutToGroups(t *testing.T) { 32 eg := &EgressRule{ 33 EgressCommonRule: EgressCommonRule{ 34 ToEndpoints: []EndpointSelector{ 35 { 36 LabelSelector: &slim_metav1.LabelSelector{MatchLabels: map[string]string{ 37 "test": "true", 38 }, 39 }, 40 }, 41 }, 42 }, 43 } 44 newRule, err := eg.CreateDerivative(context.TODO()) 45 require.EqualValues(t, newRule, eg) 46 require.Nil(t, err) 47 } 48 49 func TestCreateDerivativeRuleWithToGroupsWitInvalidRegisterCallback(t *testing.T) { 50 cb := func(ctx context.Context, group *Groups) ([]netip.Addr, error) { 51 return []netip.Addr{}, fmt.Errorf("Invalid error") 52 } 53 RegisterToGroupsProvider(AWSProvider, cb) 54 55 eg := &EgressRule{ 56 EgressCommonRule: EgressCommonRule{ 57 ToGroups: []Groups{ 58 GetGroupsRule(), 59 }, 60 }, 61 } 62 _, err := eg.CreateDerivative(context.TODO()) 63 require.Error(t, err) 64 } 65 66 func TestCreateDerivativeRuleWithToGroupsAndToPorts(t *testing.T) { 67 cb := GetCallBackWithRule("192.168.1.1") 68 RegisterToGroupsProvider(AWSProvider, cb) 69 70 eg := &EgressRule{ 71 EgressCommonRule: EgressCommonRule{ 72 ToGroups: []Groups{ 73 GetGroupsRule(), 74 }, 75 }, 76 } 77 78 // Checking that the derivative rule is working correctly 79 require.Equal(t, true, eg.RequiresDerivative()) 80 81 newRule, err := eg.CreateDerivative(context.TODO()) 82 require.Nil(t, err) 83 require.Equal(t, 0, len(newRule.ToGroups)) 84 require.Equal(t, 1, len(newRule.ToCIDRSet)) 85 } 86 87 func TestCreateDerivativeWithoutErrorAndNoIPs(t *testing.T) { 88 // Testing that if the len of the Ips returned by provider is 0 to block 89 // all the IPS outside. 90 cb := GetCallBackWithRule() 91 RegisterToGroupsProvider(AWSProvider, cb) 92 93 eg := &EgressRule{ 94 EgressCommonRule: EgressCommonRule{ 95 ToGroups: []Groups{ 96 GetGroupsRule(), 97 }, 98 }, 99 } 100 101 // Checking that the derivative rule is working correctly 102 require.Equal(t, true, eg.RequiresDerivative()) 103 104 newRule, err := eg.CreateDerivative(context.TODO()) 105 require.Nil(t, err) 106 require.EqualValues(t, &EgressRule{}, newRule) 107 } 108 109 func TestIsLabelBasedEgress(t *testing.T) { 110 setUpSuite(t) 111 112 type args struct { 113 eg *EgressRule 114 } 115 type wanted struct { 116 isLabelBased bool 117 } 118 119 tests := []struct { 120 name string 121 setupArgs func() args 122 setupWanted func() wanted 123 }{ 124 { 125 name: "label-based-rule", 126 setupArgs: func() args { 127 return args{ 128 eg: &EgressRule{ 129 EgressCommonRule: EgressCommonRule{ 130 ToEndpoints: []EndpointSelector{ 131 { 132 LabelSelector: &slim_metav1.LabelSelector{MatchLabels: map[string]string{ 133 "test": "true", 134 }, 135 }, 136 }, 137 }, 138 }, 139 }, 140 } 141 }, 142 setupWanted: func() wanted { 143 return wanted{ 144 isLabelBased: true, 145 } 146 }, 147 }, 148 { 149 name: "cidr-based-rule", 150 setupArgs: func() args { 151 return args{ 152 &EgressRule{ 153 EgressCommonRule: EgressCommonRule{ 154 ToCIDR: CIDRSlice{"192.0.0.0/3"}, 155 }, 156 }, 157 } 158 }, 159 setupWanted: func() wanted { 160 return wanted{ 161 isLabelBased: true, 162 } 163 }, 164 }, 165 { 166 name: "cidrset-based-rule", 167 setupArgs: func() args { 168 return args{ 169 &EgressRule{ 170 EgressCommonRule: EgressCommonRule{ 171 ToCIDRSet: CIDRRuleSlice{ 172 { 173 Cidr: "192.0.0.0/3", 174 }, 175 }, 176 }, 177 }, 178 } 179 }, 180 setupWanted: func() wanted { 181 return wanted{ 182 isLabelBased: true, 183 } 184 }, 185 }, 186 { 187 name: "rule-with-requirements", 188 setupArgs: func() args { 189 return args{ 190 &EgressRule{ 191 EgressCommonRule: EgressCommonRule{ 192 ToRequires: []EndpointSelector{ 193 { 194 LabelSelector: &slim_metav1.LabelSelector{MatchLabels: map[string]string{ 195 "test": "true", 196 }, 197 }, 198 }, 199 }, 200 }, 201 }, 202 } 203 }, 204 setupWanted: func() wanted { 205 return wanted{ 206 isLabelBased: false, 207 } 208 }, 209 }, 210 { 211 name: "rule-with-services", 212 setupArgs: func() args { 213 214 svcLabels := map[string]string{ 215 "app": "tested-service", 216 } 217 selector := ServiceSelector(NewESFromMatchRequirements(svcLabels, nil)) 218 return args{ 219 &EgressRule{ 220 EgressCommonRule: EgressCommonRule{ 221 ToServices: []Service{ 222 { 223 K8sServiceSelector: &K8sServiceSelectorNamespace{ 224 Selector: selector, 225 Namespace: "", 226 }, 227 }, 228 }, 229 }, 230 }, 231 } 232 }, 233 setupWanted: func() wanted { 234 return wanted{ 235 isLabelBased: false, 236 } 237 }, 238 }, 239 { 240 name: "rule-with-fqdn", 241 setupArgs: func() args { 242 return args{ 243 &EgressRule{ 244 ToFQDNs: FQDNSelectorSlice{ 245 { 246 MatchName: "cilium.io", 247 }, 248 }, 249 }, 250 } 251 }, 252 setupWanted: func() wanted { 253 return wanted{ 254 isLabelBased: false, 255 } 256 }, 257 }, 258 { 259 name: "rule-with-entities", 260 setupArgs: func() args { 261 return args{ 262 &EgressRule{ 263 EgressCommonRule: EgressCommonRule{ 264 ToEntities: EntitySlice{ 265 EntityHost, 266 }, 267 }, 268 }, 269 } 270 }, 271 setupWanted: func() wanted { 272 return wanted{ 273 isLabelBased: true, 274 } 275 }, 276 }, 277 { 278 name: "rule-with-no-l3-specification", 279 setupArgs: func() args { 280 return args{ 281 &EgressRule{ 282 ToPorts: []PortRule{ 283 { 284 Ports: []PortProtocol{ 285 { 286 Port: "80", 287 Protocol: ProtoTCP, 288 }, 289 }, 290 }, 291 }, 292 }, 293 } 294 }, 295 setupWanted: func() wanted { 296 return wanted{ 297 isLabelBased: true, 298 } 299 }, 300 }, 301 { 302 name: "rule-with-icmp", 303 setupArgs: func() args { 304 icmpType := intstr.FromInt(8) 305 return args{ 306 &EgressRule{ 307 ICMPs: ICMPRules{ 308 { 309 Fields: []ICMPField{ 310 { 311 Type: &icmpType, 312 }, 313 }, 314 }, 315 }, 316 }, 317 } 318 }, 319 setupWanted: func() wanted { 320 return wanted{ 321 isLabelBased: true, 322 } 323 }, 324 }, 325 { 326 name: "rule-with-icmp6", 327 setupArgs: func() args { 328 icmpType := intstr.FromInt(128) 329 return args{ 330 &EgressRule{ 331 ICMPs: ICMPRules{ 332 { 333 Fields: []ICMPField{ 334 { 335 Family: IPv6Family, 336 Type: &icmpType, 337 }, 338 }, 339 }, 340 }, 341 }, 342 } 343 }, 344 setupWanted: func() wanted { 345 return wanted{ 346 isLabelBased: true, 347 } 348 }, 349 }, 350 } 351 352 for _, tt := range tests { 353 args := tt.setupArgs() 354 want := tt.setupWanted() 355 require.Equal(t, nil, args.eg.sanitize(), fmt.Sprintf("Test name: %q", tt.name)) 356 isLabelBased := args.eg.AllowsWildcarding() 357 require.EqualValues(t, want.isLabelBased, isLabelBased, fmt.Sprintf("Test name: %q", tt.name)) 358 } 359 } 360 361 func TestEgressCommonRuleDeepEqual(t *testing.T) { 362 testCases := []struct { 363 name string 364 in, other *EgressCommonRule 365 expected bool 366 }{ 367 { 368 name: "All fields are nil in both", 369 in: &EgressCommonRule{}, 370 other: &EgressCommonRule{}, 371 expected: true, 372 }, 373 { 374 name: "All fields are empty in both", 375 in: &EgressCommonRule{ 376 ToEndpoints: []EndpointSelector{}, 377 ToCIDR: []CIDR{}, 378 ToCIDRSet: []CIDRRule{}, 379 ToEntities: []Entity{}, 380 }, 381 other: &EgressCommonRule{ 382 ToEndpoints: []EndpointSelector{}, 383 ToCIDR: []CIDR{}, 384 ToCIDRSet: []CIDRRule{}, 385 ToEntities: []Entity{}, 386 }, 387 expected: true, 388 }, 389 { 390 name: "ToEndpoints is nil in left operand", 391 in: &EgressCommonRule{ 392 ToEndpoints: nil, 393 }, 394 other: &EgressCommonRule{ 395 ToEndpoints: []EndpointSelector{}, 396 }, 397 expected: false, 398 }, 399 { 400 name: "ToEndpoints is empty in left operand", 401 in: &EgressCommonRule{ 402 ToEndpoints: []EndpointSelector{}, 403 }, 404 other: &EgressCommonRule{ 405 ToEndpoints: nil, 406 }, 407 expected: false, 408 }, 409 { 410 name: "ToCIDR is nil in left operand", 411 in: &EgressCommonRule{ 412 ToCIDR: nil, 413 }, 414 other: &EgressCommonRule{ 415 ToCIDR: []CIDR{}, 416 }, 417 expected: false, 418 }, 419 { 420 name: "ToCIDR is empty in left operand", 421 in: &EgressCommonRule{ 422 ToCIDR: []CIDR{}, 423 }, 424 other: &EgressCommonRule{ 425 ToCIDR: nil, 426 }, 427 expected: false, 428 }, 429 { 430 name: "ToCIDRSet is nil in left operand", 431 in: &EgressCommonRule{ 432 ToCIDRSet: nil, 433 }, 434 other: &EgressCommonRule{ 435 ToCIDRSet: []CIDRRule{}, 436 }, 437 expected: false, 438 }, 439 { 440 name: "ToCIDRSet is empty in left operand", 441 in: &EgressCommonRule{ 442 ToCIDRSet: []CIDRRule{}, 443 }, 444 other: &EgressCommonRule{ 445 ToCIDRSet: nil, 446 }, 447 expected: false, 448 }, 449 { 450 name: "ToEntities is nil in left operand", 451 in: &EgressCommonRule{ 452 ToEntities: nil, 453 }, 454 other: &EgressCommonRule{ 455 ToEntities: []Entity{}, 456 }, 457 expected: false, 458 }, 459 { 460 name: "ToEntities is empty in left operand", 461 in: &EgressCommonRule{ 462 ToEntities: []Entity{}, 463 }, 464 other: &EgressCommonRule{ 465 ToEntities: nil, 466 }, 467 expected: false, 468 }, 469 } 470 for _, tc := range testCases { 471 t.Run(tc.name, func(t *testing.T) { 472 require.Equal(t, tc.expected, tc.in.DeepEqual(tc.other)) 473 }) 474 } 475 }