github.com/cilium/cilium@v1.16.2/pkg/endpoint/redirect_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package endpoint 5 6 import ( 7 "context" 8 "sync" 9 "testing" 10 11 "github.com/stretchr/testify/require" 12 13 "github.com/cilium/cilium/pkg/completion" 14 datapath "github.com/cilium/cilium/pkg/datapath/types" 15 "github.com/cilium/cilium/pkg/fqdn/restore" 16 "github.com/cilium/cilium/pkg/identity" 17 "github.com/cilium/cilium/pkg/identity/cache" 18 "github.com/cilium/cilium/pkg/identity/identitymanager" 19 "github.com/cilium/cilium/pkg/kvstore" 20 "github.com/cilium/cilium/pkg/labels" 21 monitorAPI "github.com/cilium/cilium/pkg/monitor/api" 22 "github.com/cilium/cilium/pkg/option" 23 "github.com/cilium/cilium/pkg/policy" 24 "github.com/cilium/cilium/pkg/policy/api" 25 "github.com/cilium/cilium/pkg/policy/trafficdirection" 26 "github.com/cilium/cilium/pkg/proxy/endpoint" 27 "github.com/cilium/cilium/pkg/revert" 28 "github.com/cilium/cilium/pkg/testutils" 29 testidentity "github.com/cilium/cilium/pkg/testutils/identity" 30 testipcache "github.com/cilium/cilium/pkg/testutils/ipcache" 31 "github.com/cilium/cilium/pkg/u8proto" 32 ) 33 34 type RedirectSuite struct { 35 oldPolicyEnable string 36 mgr *cache.CachingIdentityAllocator 37 do *DummyOwner 38 rsp *RedirectSuiteProxy 39 stats *regenerationStatistics 40 } 41 42 func setupRedirectSuite(tb testing.TB) *RedirectSuite { 43 testutils.IntegrationTest(tb) 44 45 s := &RedirectSuite{ 46 do: &DummyOwner{}, 47 } 48 s.oldPolicyEnable = policy.GetPolicyEnabled() 49 policy.SetPolicyEnabled(option.DefaultEnforcement) 50 51 // Setup dependencies for endpoint. 52 kvstore.SetupDummy(tb, "etcd") 53 54 s.mgr = cache.NewCachingIdentityAllocator(s.do) 55 <-s.mgr.InitIdentityAllocator(nil) 56 57 identityCache := identity.IdentityMap{ 58 identity.NumericIdentity(identityFoo): labelsFoo, 59 identity.NumericIdentity(identityBar): labelsBar, 60 } 61 62 s.do.repo = policy.NewPolicyRepository(identityCache, nil, nil) 63 s.do.repo.GetSelectorCache().SetLocalIdentityNotifier(testidentity.NewDummyIdentityNotifier()) 64 65 s.rsp = &RedirectSuiteProxy{ 66 parserProxyPortMap: map[string]uint16{ 67 policy.ParserTypeHTTP.String(): httpPort, 68 policy.ParserTypeDNS.String(): dnsPort, 69 policy.ParserTypeKafka.String(): kafkaPort, 70 "crd/cec1/listener1": crd1Port, 71 "crd/cec2/listener2": crd2Port, 72 }, 73 redirectPortUserMap: make(map[uint16][]string), 74 } 75 76 s.stats = new(regenerationStatistics) 77 78 tb.Cleanup(func() { 79 identitymanager.RemoveAll() 80 s.mgr.Close() 81 policy.SetPolicyEnabled(s.oldPolicyEnable) 82 }) 83 84 return s 85 } 86 87 // RedirectSuiteProxy implements EndpointProxy. It is used for testing the 88 // functions related to generating proxy redirects for a given Endpoint. 89 type RedirectSuiteProxy struct { 90 parserProxyPortMap map[string]uint16 91 redirectPortUserMap map[uint16][]string 92 } 93 94 // CreateOrUpdateRedirect returns the proxy port for the given L7Parser from the 95 // ProxyPolicy parameter. 96 func (r *RedirectSuiteProxy) CreateOrUpdateRedirect(ctx context.Context, l4 policy.ProxyPolicy, id string, localEndpoint endpoint.EndpointUpdater, wg *completion.WaitGroup) (proxyPort uint16, err error, finalizeFunc revert.FinalizeFunc, revertFunc revert.RevertFunc) { 97 pp := r.parserProxyPortMap[l4.GetL7Parser().String()+l4.GetListener()] 98 return pp, nil, func() { log.Infof("FINALIZER CALLED") }, nil 99 } 100 101 // RemoveRedirect does nothing. 102 func (r *RedirectSuiteProxy) RemoveRedirect(id string, wg *completion.WaitGroup) (error, revert.FinalizeFunc, revert.RevertFunc) { 103 return nil, nil, nil 104 } 105 106 // UpdateNetworkPolicy does nothing. 107 func (r *RedirectSuiteProxy) UpdateNetworkPolicy(ep endpoint.EndpointUpdater, vis *policy.VisibilityPolicy, policy *policy.L4Policy, ingressPolicyEnforced, egressPolicyEnforced bool, wg *completion.WaitGroup) (error, func() error) { 108 return nil, nil 109 } 110 111 // RemoveNetworkPolicy does nothing. 112 func (r *RedirectSuiteProxy) RemoveNetworkPolicy(ep endpoint.EndpointInfoSource) {} 113 114 // DummyIdentityAllocatorOwner implements 115 // pkg/identity/cache/IdentityAllocatorOwner. It is used for unit testing. 116 type DummyIdentityAllocatorOwner struct{} 117 118 // UpdateIdentities does nothing. 119 func (d *DummyIdentityAllocatorOwner) UpdateIdentities(added, deleted identity.IdentityMap) { 120 } 121 122 // GetNodeSuffix does nothing. 123 func (d *DummyIdentityAllocatorOwner) GetNodeSuffix() string { 124 return "" 125 } 126 127 // DummyOwner implements pkg/endpoint/regeneration/Owner. Used for unit testing. 128 type DummyOwner struct { 129 repo *policy.Repository 130 } 131 132 // GetPolicyRepository returns the policy repository of the owner. 133 func (d *DummyOwner) GetPolicyRepository() *policy.Repository { 134 return d.repo 135 } 136 137 // QueueEndpointBuild does nothing. 138 func (d *DummyOwner) QueueEndpointBuild(ctx context.Context, epID uint64) (func(), error) { 139 return nil, nil 140 } 141 142 // GetCompilationLock does nothing. 143 func (d *DummyOwner) GetCompilationLock() datapath.CompilationLock { 144 return nil 145 } 146 147 // GetCIDRPrefixLengths does nothing. 148 func (d *DummyOwner) GetCIDRPrefixLengths() (s6, s4 []int) { 149 return nil, nil 150 } 151 152 // SendNotification does nothing. 153 func (d *DummyOwner) SendNotification(msg monitorAPI.AgentNotifyMessage) error { 154 return nil 155 } 156 157 // Datapath returns a nil datapath. 158 func (d *DummyOwner) Datapath() datapath.Datapath { 159 return nil 160 } 161 162 func (s *DummyOwner) GetDNSRules(epID uint16) restore.DNSRules { 163 return nil 164 } 165 166 func (s *DummyOwner) RemoveRestoredDNSRules(epID uint16) { 167 } 168 169 // GetNodeSuffix does nothing. 170 func (d *DummyOwner) GetNodeSuffix() string { 171 return "" 172 } 173 174 func (d *DummyOwner) UpdateIdentities(added, deleted identity.IdentityMap) { 175 wg := &sync.WaitGroup{} 176 d.repo.GetSelectorCache().UpdateIdentities(added, deleted, wg) 177 wg.Wait() 178 } 179 180 const ( 181 httpPort = uint16(19001) 182 dnsPort = uint16(19002) 183 kafkaPort = uint16(19003) 184 crd1Port = uint16(19004) 185 crd2Port = uint16(19005) 186 ) 187 188 func (s *RedirectSuite) NewTestEndpoint(t *testing.T) *Endpoint { 189 ep := NewTestEndpointWithState(t, s.do, s.do, testipcache.NewMockIPCache(), s.rsp, s.mgr, 12345, StateRegenerating) 190 ep.SetPropertyValue(PropertyFakeEndpoint, false) 191 192 epIdentity, _, err := s.mgr.AllocateIdentity(context.Background(), labelsBar.Labels(), true, identity.NumericIdentity(identityBar)) 193 require.Nil(t, err) 194 ep.SetIdentity(epIdentity, true) 195 196 return ep 197 } 198 199 func (s *RedirectSuite) AddRules(rules api.Rules) { 200 s.do.repo.MustAddList(rules) 201 } 202 203 func (s *RedirectSuite) TearDownTest(t *testing.T) { 204 identitymanager.RemoveAll() 205 s.mgr.Close() 206 policy.SetPolicyEnabled(s.oldPolicyEnable) 207 } 208 209 func TestAddVisibilityRedirects(t *testing.T) { 210 s := setupRedirectSuite(t) 211 ep := s.NewTestEndpoint(t) 212 213 firstAnno := "<Ingress/80/TCP/HTTP>" 214 ep.UpdateVisibilityPolicy(func(_, _ string) (proxyVisibility string, err error) { 215 return firstAnno, nil 216 }) 217 res, err := ep.regeneratePolicy(s.stats) 218 require.Nil(t, err) 219 err = ep.setDesiredPolicy(res) 220 require.Nil(t, err) 221 222 ctx, cancel := context.WithCancel(context.Background()) 223 defer cancel() 224 cmp := completion.NewWaitGroup(ctx) 225 226 _, err, _, _ = ep.addNewRedirects(cmp) 227 require.Nil(t, err) 228 v, ok := ep.desiredPolicy.GetPolicyMap().Get(policy.Key{ 229 Identity: 0, 230 DestPort: uint16(80), 231 Nexthdr: uint8(u8proto.TCP), 232 TrafficDirection: trafficdirection.Ingress.Uint8(), 233 }) 234 require.Equal(t, true, ok) 235 require.Equal(t, httpPort, v.ProxyPort) 236 237 secondAnno := "<Ingress/80/TCP/Kafka>" 238 239 ep.UpdateVisibilityPolicy(func(_, _ string) (proxyVisibility string, err error) { 240 return secondAnno, nil 241 }) 242 res, err = ep.regeneratePolicy(s.stats) 243 require.Nil(t, err) 244 err = ep.setDesiredPolicy(res) 245 require.Nil(t, err) 246 247 d, err, _, _ := ep.addNewRedirects(cmp) 248 require.Nil(t, err) 249 v, ok = ep.desiredPolicy.GetPolicyMap().Get(policy.Key{ 250 Identity: 0, 251 DestPort: uint16(80), 252 Nexthdr: uint8(u8proto.TCP), 253 TrafficDirection: trafficdirection.Ingress.Uint8(), 254 }) 255 require.Equal(t, true, ok) 256 // Check that proxyport was updated accordingly. 257 require.Equal(t, kafkaPort, v.ProxyPort) 258 259 thirdAnno := "<Ingress/80/TCP/Kafka>,<Egress/80/TCP/HTTP>" 260 261 // Check that multiple values in annotation are handled correctly. 262 ep.UpdateVisibilityPolicy(func(_, _ string) (proxyVisibility string, err error) { 263 return thirdAnno, nil 264 }) 265 res, err = ep.regeneratePolicy(s.stats) 266 require.Nil(t, err) 267 err = ep.setDesiredPolicy(res) 268 require.Nil(t, err) 269 270 realizedRedirects := ep.GetRealizedRedirects() 271 d2, err, _, _ := ep.addNewRedirects(cmp) 272 require.Nil(t, err) 273 v, ok = ep.desiredPolicy.GetPolicyMap().Get(policy.Key{ 274 Identity: 0, 275 DestPort: uint16(80), 276 Nexthdr: uint8(u8proto.TCP), 277 TrafficDirection: trafficdirection.Ingress.Uint8(), 278 }) 279 require.Equal(t, true, ok) 280 require.Equal(t, kafkaPort, v.ProxyPort) 281 282 v, ok = ep.desiredPolicy.GetPolicyMap().Get(policy.Key{ 283 Identity: 0, 284 DestPort: uint16(80), 285 Nexthdr: uint8(u8proto.TCP), 286 TrafficDirection: trafficdirection.Ingress.Uint8(), 287 }) 288 require.Equal(t, true, ok) 289 require.Equal(t, kafkaPort, v.ProxyPort) 290 291 v, ok = ep.desiredPolicy.GetPolicyMap().Get(policy.Key{ 292 Identity: 0, 293 DestPort: uint16(80), 294 Nexthdr: uint8(u8proto.TCP), 295 TrafficDirection: trafficdirection.Egress.Uint8(), 296 }) 297 require.Equal(t, true, ok) 298 require.Equal(t, httpPort, v.ProxyPort) 299 pID := policy.ProxyID(ep.ID, false, u8proto.TCP.String(), uint16(80), "") 300 p, ok := d2[pID] 301 require.Equal(t, true, ok) 302 require.Equal(t, httpPort, p) 303 304 // Check that the egress redirect is removed when the redirects have been 305 // updated. 306 ep.removeOldRedirects(d, realizedRedirects, cmp) 307 // Egress redirect should not exist in desired redirects 308 _, ok = d[pID] 309 require.Equal(t, false, ok) 310 311 // Check that all redirects are removed when no visibility policy applies. 312 noAnno := "" 313 ep.UpdateVisibilityPolicy(func(_, _ string) (proxyVisibility string, err error) { 314 return noAnno, nil 315 }) 316 res, err = ep.regeneratePolicy(s.stats) 317 require.Nil(t, err) 318 err = ep.setDesiredPolicy(res) 319 require.Nil(t, err) 320 321 realizedRedirects = ep.GetRealizedRedirects() 322 d, err, _, _ = ep.addNewRedirects(cmp) 323 require.Nil(t, err) 324 ep.removeOldRedirects(d, realizedRedirects, cmp) 325 require.Equal(t, 0, len(d)) 326 } 327 328 var ( 329 // Identity, labels, selectors for an endpoint named "foo" 330 identityFoo = uint32(100) 331 labelsFoo = labels.ParseSelectLabelArray("foo", "red") 332 selectFoo_ = api.NewESFromLabels(labels.ParseSelectLabel("foo")) 333 selectRed_ = api.NewESFromLabels(labels.ParseSelectLabel("red")) 334 denyFooL3__ = selectFoo_ 335 336 identityBar = uint32(200) 337 338 labelsBar = labels.ParseSelectLabelArray("bar", "blue") 339 selectBar_ = api.NewESFromLabels(labels.ParseSelectLabel("bar")) 340 341 denyAllL4_ []api.PortDenyRule 342 343 allowPort80 = []api.PortRule{{ 344 Ports: []api.PortProtocol{ 345 {Port: "80", Protocol: api.ProtoTCP}, 346 }, 347 }} 348 allowHTTPRoot = &api.L7Rules{ 349 HTTP: []api.PortRuleHTTP{ 350 {Method: "GET", Path: "/"}, 351 }, 352 } 353 354 lblsL3DenyFoo = labels.ParseLabelArray("l3-deny") 355 ruleL3DenyFoo = api.NewRule(). 356 WithLabels(lblsL3DenyFoo). 357 WithIngressDenyRules([]api.IngressDenyRule{{ 358 IngressCommonRule: api.IngressCommonRule{ 359 FromEndpoints: []api.EndpointSelector{denyFooL3__}, 360 }, 361 ToPorts: denyAllL4_, 362 }}) 363 lblsL4L7Allow = labels.ParseLabelArray("l4l7-allow") 364 ruleL4L7Allow = api.NewRule(). 365 WithLabels(lblsL4L7Allow). 366 WithIngressRules([]api.IngressRule{{ 367 IngressCommonRule: api.IngressCommonRule{}, 368 ToPorts: combineL4L7(allowPort80, allowHTTPRoot), 369 }}) 370 371 AllowAnyEgressLabels = labels.LabelArray{labels.NewLabel(policy.LabelKeyPolicyDerivedFrom, 372 policy.LabelAllowAnyEgress, 373 labels.LabelSourceReserved)} 374 375 dirIngress = trafficdirection.Ingress.Uint8() 376 dirEgress = trafficdirection.Egress.Uint8() 377 mapKeyAllL7 = policy.Key{Identity: 0, DestPort: 80, Nexthdr: 6, TrafficDirection: dirIngress} 378 mapKeyFoo = policy.Key{Identity: identityFoo, DestPort: 0, InvertedPortMask: 0xffff, Nexthdr: 0, TrafficDirection: dirIngress} 379 mapKeyFooL7 = policy.Key{Identity: identityFoo, DestPort: 80, Nexthdr: 6, TrafficDirection: dirIngress} 380 mapKeyAllowAllE = policy.Key{Identity: 0, DestPort: 0, Nexthdr: 0, InvertedPortMask: 0xffff, TrafficDirection: dirEgress} 381 ) 382 383 // combineL4L7 returns a new PortRule that refers to the specified l4 ports and 384 // l7 rules. 385 func combineL4L7(l4 []api.PortRule, l7 *api.L7Rules) []api.PortRule { 386 result := make([]api.PortRule, 0, len(l4)) 387 for _, pr := range l4 { 388 result = append(result, api.PortRule{ 389 Ports: pr.Ports, 390 Rules: l7, 391 }) 392 } 393 return result 394 } 395 396 func TestRedirectWithDeny(t *testing.T) { 397 s := setupRedirectSuite(t) 398 ep := s.NewTestEndpoint(t) 399 400 // Policy denies anything to "foo" 401 s.AddRules(api.Rules{ 402 ruleL3DenyFoo.WithEndpointSelector(selectBar_), 403 ruleL4L7Allow.WithEndpointSelector(selectBar_), 404 }) 405 406 res, err := ep.regeneratePolicy(s.stats) 407 require.Nil(t, err) 408 err = ep.setDesiredPolicy(res) 409 require.Nil(t, err) 410 411 expected := policy.NewMapState(map[policy.Key]policy.MapStateEntry{ 412 mapKeyAllowAllE: { 413 DerivedFromRules: labels.LabelArrayList{AllowAnyEgressLabels}, 414 }, 415 mapKeyFoo: { 416 IsDeny: true, 417 DerivedFromRules: labels.LabelArrayList{lblsL3DenyFoo}, 418 }, 419 }) 420 if !ep.desiredPolicy.GetPolicyMap().Equals(expected) { 421 t.Fatal("desired policy map does not equal expected map:\n", 422 ep.desiredPolicy.GetPolicyMap().Diff(expected)) 423 } 424 425 ctx, cancel := context.WithCancel(context.Background()) 426 defer cancel() 427 cmp := completion.NewWaitGroup(ctx) 428 429 realizedRedirects := ep.GetRealizedRedirects() 430 desiredRedirects, err, finalizeFunc, revertFunc := ep.addNewRedirects(cmp) 431 require.Nil(t, err) 432 finalizeFunc() 433 434 // Redirect is still created, even if all MapState entries may have been overridden by a 435 // deny entry. A new FQDN redirect may have no MapState entries as the associated CIDR 436 // identities may match no numeric IDs yet, so we can not count the number of added MapState 437 // entries and make any conclusions from it. 438 require.Equal(t, 1, len(desiredRedirects)) 439 440 expected2 := policy.NewMapState(map[policy.Key]policy.MapStateEntry{ 441 mapKeyAllowAllE: { 442 DerivedFromRules: labels.LabelArrayList{AllowAnyEgressLabels}, 443 }, 444 mapKeyAllL7: { 445 IsDeny: false, 446 ProxyPort: httpPort, 447 DerivedFromRules: labels.LabelArrayList{lblsL4L7Allow}, 448 }, 449 mapKeyFoo: { 450 IsDeny: true, 451 DerivedFromRules: labels.LabelArrayList{lblsL3DenyFoo}, 452 }, 453 mapKeyFooL7: { 454 IsDeny: true, 455 DerivedFromRules: labels.LabelArrayList{lblsL3DenyFoo}, 456 }, 457 }) 458 459 // Redirect for the HTTP port should have been added, but there should be a deny for Foo on 460 // that port, as it is shadowed by the deny rule 461 if !ep.desiredPolicy.GetPolicyMap().Equals(expected2) { 462 t.Fatal("desired policy map does not equal expected map:\n", 463 ep.desiredPolicy.GetPolicyMap().Diff(expected2)) 464 } 465 466 // Keep only desired redirects 467 ep.removeOldRedirects(desiredRedirects, realizedRedirects, cmp) 468 469 // Check that the redirect is still realized 470 require.Equal(t, 1, len(desiredRedirects)) 471 require.Equal(t, 4, ep.desiredPolicy.GetPolicyMap().Len()) 472 473 // Pretend that something failed and revert the changes 474 revertFunc() 475 476 // Check that the state before addRedirects is restored 477 if !ep.desiredPolicy.GetPolicyMap().Equals(expected) { 478 t.Fatal("desired policy map does not equal expected map:\n", 479 ep.desiredPolicy.GetPolicyMap().Diff(expected)) 480 } 481 require.Equal(t, 2, ep.desiredPolicy.GetPolicyMap().Len()) 482 } 483 484 var ( 485 allowListener1Port80 = []api.PortRule{{ 486 Ports: []api.PortProtocol{ 487 {Port: "80", Protocol: api.ProtoTCP}, 488 }, 489 Listener: &api.Listener{ 490 EnvoyConfig: &api.EnvoyConfig{ 491 Name: "cec1", 492 }, 493 Name: "listener1", 494 }, 495 }} 496 allowListener2Port80Priority1 = []api.PortRule{{ 497 Ports: []api.PortProtocol{ 498 {Port: "80", Protocol: api.ProtoTCP}, 499 }, 500 Listener: &api.Listener{ 501 EnvoyConfig: &api.EnvoyConfig{ 502 Name: "cec2", 503 }, 504 Name: "listener2", 505 Priority: 1, 506 }, 507 }} 508 allowListener1Port80Priority1 = []api.PortRule{{ 509 Ports: []api.PortProtocol{ 510 {Port: "80", Protocol: api.ProtoTCP}, 511 }, 512 Listener: &api.Listener{ 513 EnvoyConfig: &api.EnvoyConfig{ 514 Name: "cec1", 515 }, 516 Name: "listener1", 517 Priority: 1, 518 }, 519 }} 520 lblsL4AllowListener1 = labels.ParseLabelArray("foo-l4l7-allow-listener1") 521 ruleL4AllowListener1 = api.NewRule(). 522 WithLabels(lblsL4AllowListener1). 523 WithIngressRules([]api.IngressRule{{ 524 IngressCommonRule: api.IngressCommonRule{ 525 FromEndpoints: []api.EndpointSelector{selectFoo_}, 526 }, 527 ToPorts: allowListener1Port80, 528 }}) 529 lblsL4L7AllowListener1Priority1 = labels.ParseLabelArray("foo-l4l7-allow-listener1-priority1") 530 ruleL4L7AllowListener1Priority1 = api.NewRule(). 531 WithLabels(lblsL4L7AllowListener1Priority1). 532 WithIngressRules([]api.IngressRule{{ 533 IngressCommonRule: api.IngressCommonRule{ 534 FromEndpoints: []api.EndpointSelector{selectFoo_}, 535 }, 536 ToPorts: allowListener1Port80Priority1, 537 }}) 538 lblsL4AllowPort80 = labels.ParseLabelArray("l4-allow-port80") 539 ruleL4AllowPort80 = api.NewRule(). 540 WithLabels(lblsL4AllowPort80). 541 WithIngressRules([]api.IngressRule{{ 542 IngressCommonRule: api.IngressCommonRule{}, 543 ToPorts: allowPort80, 544 }}) 545 lblsL4L7AllowListener2Priority1 = labels.ParseLabelArray("red-l4l7-allow-listener2-priority1") 546 ruleL4L7AllowListener2Priority1 = api.NewRule(). 547 WithLabels(lblsL4L7AllowListener2Priority1). 548 WithIngressRules([]api.IngressRule{{ 549 IngressCommonRule: api.IngressCommonRule{ 550 FromEndpoints: []api.EndpointSelector{selectRed_}, 551 }, 552 ToPorts: allowListener2Port80Priority1, 553 }}) 554 ) 555 556 func TestRedirectWithPriority(t *testing.T) { 557 s := setupRedirectSuite(t) 558 559 ep := s.NewTestEndpoint(t) 560 api.TestAllowIngressListener = true 561 defer func() { api.TestAllowIngressListener = false }() 562 563 s.AddRules(api.Rules{ 564 ruleL4AllowListener1.WithEndpointSelector(selectBar_), 565 ruleL4AllowPort80.WithEndpointSelector(selectBar_), 566 ruleL4L7AllowListener2Priority1.WithEndpointSelector(selectBar_), 567 }) 568 569 res, err := ep.regeneratePolicy(s.stats) 570 require.Nil(t, err) 571 err = ep.setDesiredPolicy(res) 572 require.Nil(t, err) 573 574 expected := policy.NewMapState(map[policy.Key]policy.MapStateEntry{ 575 mapKeyAllowAllE: { 576 DerivedFromRules: labels.LabelArrayList{AllowAnyEgressLabels}, 577 }, 578 mapKeyAllL7: { 579 DerivedFromRules: labels.LabelArrayList{lblsL4AllowListener1, lblsL4AllowPort80, lblsL4L7AllowListener2Priority1}, 580 }, 581 }) 582 if !ep.desiredPolicy.GetPolicyMap().Equals(expected) { 583 t.Fatal("desired policy map does not equal expected map:\n", 584 ep.desiredPolicy.GetPolicyMap().Diff(expected)) 585 } 586 587 ctx, cancel := context.WithCancel(context.Background()) 588 defer cancel() 589 cmp := completion.NewWaitGroup(ctx) 590 591 realizedRedirects := ep.GetRealizedRedirects() 592 desiredRedirects, err, finalizeFunc, revertFunc := ep.addNewRedirects(cmp) 593 require.Nil(t, err) 594 finalizeFunc() 595 596 // Check that all redirects have been created. 597 require.Equal(t, crd2Port, desiredRedirects["12345:ingress:TCP:80:/cec2/listener2"]) 598 require.Equal(t, crd1Port, desiredRedirects["12345:ingress:TCP:80:/cec1/listener1"]) 599 require.Equal(t, 2, len(desiredRedirects)) 600 601 expected2 := policy.NewMapState(map[policy.Key]policy.MapStateEntry{ 602 mapKeyAllowAllE: { 603 DerivedFromRules: labels.LabelArrayList{AllowAnyEgressLabels}, 604 }, 605 mapKeyFooL7: { 606 ProxyPort: crd2Port, 607 Listener: "/cec2/listener2", 608 DerivedFromRules: labels.LabelArrayList{lblsL4AllowListener1, lblsL4AllowPort80, lblsL4L7AllowListener2Priority1}, 609 }, 610 mapKeyAllL7: { 611 DerivedFromRules: labels.LabelArrayList{lblsL4AllowListener1, lblsL4AllowPort80, lblsL4L7AllowListener2Priority1}, 612 }, 613 }) 614 if !ep.desiredPolicy.GetPolicyMap().Equals(expected2) { 615 t.Fatal("desired policy map does not equal expected map:\n", 616 ep.desiredPolicy.GetPolicyMap().Diff(expected2)) 617 } 618 619 // Keep only desired redirects 620 ep.removeOldRedirects(desiredRedirects, realizedRedirects, cmp) 621 622 // Check that the redirect is still realized 623 require.Equal(t, 2, len(desiredRedirects)) 624 require.Equal(t, 3, ep.desiredPolicy.GetPolicyMap().Len()) 625 626 // Pretend that something failed and revert the changes 627 revertFunc() 628 629 // Check that the state before addRedirects is restored 630 if !ep.desiredPolicy.GetPolicyMap().Equals(expected) { 631 t.Fatal("desired policy map does not equal expected map:\n", 632 ep.desiredPolicy.GetPolicyMap().Diff(expected)) 633 } 634 require.Equal(t, 2, ep.desiredPolicy.GetPolicyMap().Len()) 635 } 636 637 func TestRedirectWithEqualPriority(t *testing.T) { 638 s := setupRedirectSuite(t) 639 640 ep := s.NewTestEndpoint(t) 641 642 api.TestAllowIngressListener = true 643 defer func() { api.TestAllowIngressListener = false }() 644 s.AddRules(api.Rules{ 645 ruleL4L7AllowListener1Priority1.WithEndpointSelector(selectBar_), 646 ruleL4AllowPort80.WithEndpointSelector(selectBar_), 647 ruleL4L7AllowListener2Priority1.WithEndpointSelector(selectBar_), 648 }) 649 650 res, err := ep.regeneratePolicy(s.stats) 651 require.Nil(t, err) 652 err = ep.setDesiredPolicy(res) 653 require.Nil(t, err) 654 655 expected := policy.NewMapState(map[policy.Key]policy.MapStateEntry{ 656 mapKeyAllowAllE: { 657 DerivedFromRules: labels.LabelArrayList{AllowAnyEgressLabels}, 658 }, 659 mapKeyAllL7: { 660 DerivedFromRules: labels.LabelArrayList{lblsL4L7AllowListener1Priority1, lblsL4AllowPort80, lblsL4L7AllowListener2Priority1}, 661 }, 662 }) 663 if !ep.desiredPolicy.GetPolicyMap().Equals(expected) { 664 t.Fatal("desired policy map does not equal expected map:\n", 665 ep.desiredPolicy.GetPolicyMap().Diff(expected)) 666 } 667 668 ctx, cancel := context.WithCancel(context.Background()) 669 defer cancel() 670 cmp := completion.NewWaitGroup(ctx) 671 672 realizedRedirects := ep.GetRealizedRedirects() 673 desiredRedirects, err, finalizeFunc, revertFunc := ep.addNewRedirects(cmp) 674 require.Nil(t, err) 675 finalizeFunc() 676 677 // Check that all redirects have been created. 678 require.Equal(t, crd2Port, desiredRedirects["12345:ingress:TCP:80:/cec2/listener2"]) 679 require.Equal(t, crd1Port, desiredRedirects["12345:ingress:TCP:80:/cec1/listener1"]) 680 require.Equal(t, 2, len(desiredRedirects)) 681 682 expected2 := policy.NewMapState(map[policy.Key]policy.MapStateEntry{ 683 mapKeyAllowAllE: { 684 DerivedFromRules: labels.LabelArrayList{AllowAnyEgressLabels}, 685 }, 686 mapKeyFooL7: { 687 ProxyPort: crd1Port, 688 Listener: "/cec1/listener1", 689 DerivedFromRules: labels.LabelArrayList{lblsL4L7AllowListener1Priority1, lblsL4AllowPort80, lblsL4L7AllowListener2Priority1}, 690 }, 691 mapKeyAllL7: { 692 DerivedFromRules: labels.LabelArrayList{lblsL4L7AllowListener1Priority1, lblsL4AllowPort80, lblsL4L7AllowListener2Priority1}, 693 }, 694 }) 695 if !ep.desiredPolicy.GetPolicyMap().Equals(expected2) { 696 t.Fatal("desired policy map does not equal expected map:\n", 697 ep.desiredPolicy.GetPolicyMap().Diff(expected2)) 698 } 699 700 // Keep only desired redirects 701 ep.removeOldRedirects(desiredRedirects, realizedRedirects, cmp) 702 703 // Check that the redirect is still realized 704 require.Equal(t, 2, len(desiredRedirects)) 705 require.Equal(t, 3, ep.desiredPolicy.GetPolicyMap().Len()) 706 707 // Pretend that something failed and revert the changes 708 revertFunc() 709 710 // Check that the state before addRedirects is restored 711 if !ep.desiredPolicy.GetPolicyMap().Equals(expected) { 712 t.Fatal("desired policy map does not equal expected map:\n", 713 ep.desiredPolicy.GetPolicyMap().Diff(expected)) 714 } 715 require.Equal(t, 2, ep.desiredPolicy.GetPolicyMap().Len()) 716 }