@@ -21,6 +21,8 @@ import (
21
21
22
22
"github.com/go-test/deep"
23
23
24
+ maps0 "maps"
25
+
24
26
"github.com/haproxytech/client-native/v6/models"
25
27
"github.com/haproxytech/kubernetes-ingress/pkg/annotations"
26
28
"github.com/haproxytech/kubernetes-ingress/pkg/fs"
@@ -150,26 +152,7 @@ func (c *HAProxyController) updateHAProxy() {
150
152
logger .Error (err )
151
153
}
152
154
153
- for _ , namespace := range c .store .Namespaces {
154
- c .store .SecretsProcessed = map [string ]struct {}{}
155
- for _ , ingResource := range namespace .Ingresses {
156
- if ! namespace .Relevant && ! ingResource .Faked {
157
- // As we watch only for white-listed namespaces, we should not worry about iterating over
158
- // many ingresses in irrelevant namespaces.
159
- // There should only be fake ingresses in irrelevant namespaces so loop should be whithin small amount of ingresses (Prometheus)
160
- continue
161
- }
162
- i := ingress .New (ingResource , c .osArgs .IngressClass , c .osArgs .EmptyIngressClass , c .annotations )
163
- if ! i .Supported (c .store , c .annotations ) {
164
- logger .Debugf ("ingress '%s/%s' ignored: no matching" , ingResource .Namespace , ingResource .Name )
165
- } else {
166
- i .Update (c .store , c .haproxy , c .annotations )
167
- }
168
- if ingResource .Status == store .ADDED || ingResource .ClassUpdated {
169
- c .updateStatusManager .AddIngress (i )
170
- }
171
- }
172
- }
155
+ c .processIngressesWithMerge ()
173
156
174
157
updated := deep .Equal (route .CurentCustomRoutes , route .CustomRoutes , deep .FLAG_IGNORE_SLICE_ORDER )
175
158
if len (updated ) != 0 {
@@ -339,3 +322,104 @@ func (c *HAProxyController) clean(failedSync bool) {
339
322
func (c * HAProxyController ) SetGatewayAPIInstalled (gatewayAPIInstalled bool ) {
340
323
c .gatewayManager .SetGatewayAPIInstalled (gatewayAPIInstalled )
341
324
}
325
+
326
+ func (c * HAProxyController ) manageIngress (ing * store.Ingress ) {
327
+ i := ingress .New (ing , c .osArgs .IngressClass , c .osArgs .EmptyIngressClass , c .annotations )
328
+ if ! i .Supported (c .store , c .annotations ) {
329
+ logger .Debugf ("ingress '%s/%s' ignored: no matching" , ing .Namespace , ing .Name )
330
+ } else {
331
+ i .Update (c .store , c .haproxy , c .annotations )
332
+ }
333
+ if ing .Status == store .ADDED || ing .ClassUpdated {
334
+ c .updateStatusManager .AddIngress (i )
335
+ }
336
+ }
337
+
338
+ func (c * HAProxyController ) processIngressesWithMerge () {
339
+ for _ , namespace := range c .store .Namespaces {
340
+ c .store .SecretsProcessed = map [string ]struct {}{}
341
+ // Iterate over services
342
+ for _ , service := range namespace .Services {
343
+ ingressesOrderedList := c .store .IngressesByService [service .Namespace + "/" + service .Name ]
344
+ if ingressesOrderedList == nil {
345
+ continue
346
+ }
347
+ ingresses := ingressesOrderedList .Items ()
348
+ if len (ingresses ) == 0 {
349
+ continue
350
+ }
351
+ // Put standalone ingresses aside.
352
+ var standaloneIngresses []* store.Ingress
353
+ // Get the name of ingresses referring to the service
354
+ var ingressesToMerge []* store.Ingress
355
+ for _ , ing := range ingresses {
356
+ i := ingress .New (ing , c .osArgs .IngressClass , c .osArgs .EmptyIngressClass , c .annotations )
357
+ if ! i .Supported (c .store , c .annotations ) {
358
+ continue
359
+ }
360
+ // if the ingress has standalone-backend annotation, put it aside and continue.
361
+ if ing .Annotations ["standalone-backend" ] == "true" {
362
+ standaloneIngresses = append (standaloneIngresses , ing )
363
+ continue
364
+ }
365
+ ingressesToMerge = append (ingressesToMerge , ing )
366
+ }
367
+
368
+ // Get copy of annotationsFromAllIngresses from all ingresses
369
+ annotationsFromAllIngresses := map [string ]string {}
370
+
371
+ for _ , ingressToMerge := range ingressesToMerge {
372
+ // Gather all annotations from all ingresses referring to the service in a consistent order based on ingress name.
373
+ for ann , value := range ingressToMerge .Annotations {
374
+ if _ , specific := annotations .SpecificAnnotations [ann ]; specific {
375
+ continue
376
+ }
377
+ annotationsFromAllIngresses [ann ] = value
378
+ }
379
+ }
380
+
381
+ // Now we've gathered the annotations set we can process all ingresses.
382
+ for _ , ingressToMerge := range ingressesToMerge {
383
+ // We copy the ingress
384
+ consolidatedIngress := * ingressToMerge
385
+ // We assign the general set of annotations
386
+ consolidatedIngressAnns := map [string ]string {}
387
+ maps0 .Copy (consolidatedIngressAnns , annotationsFromAllIngresses )
388
+
389
+ consolidatedIngress .Annotations = consolidatedIngressAnns
390
+ for ann , value := range ingressToMerge .Annotations {
391
+ if _ , specific := annotations .SpecificAnnotations [ann ]; ! specific {
392
+ continue
393
+ }
394
+ consolidatedIngress .Annotations [ann ] = value
395
+ }
396
+ // We will reprocess the rules because we need to skip the ones referring to an other service.
397
+ rules := map [string ]* store.IngressRule {}
398
+ consolidatedIngress .Rules = rules
399
+ for _ , rule := range ingressToMerge .Rules {
400
+ newRule := store.IngressRule {
401
+ Host : rule .Host ,
402
+ Paths : map [string ]* store.IngressPath {},
403
+ }
404
+ for _ , path := range rule .Paths {
405
+ // if the rule refers to the service then keep it ...
406
+ if path .SvcNamespace == service .Namespace && path .SvcName == service .Name {
407
+ newRule .Paths [path .Path ] = path
408
+ }
409
+ }
410
+ // .. if it's not empty
411
+ if len (newRule .Paths ) > 0 {
412
+ rules [newRule .Host ] = & newRule
413
+ }
414
+ }
415
+ // Back to the usual processing of the ingress
416
+
417
+ c .manageIngress (& consolidatedIngress )
418
+ }
419
+ // Now process the standalone ingresses as usual.
420
+ for _ , standaloneIngress := range standaloneIngresses {
421
+ c .manageIngress (standaloneIngress )
422
+ }
423
+ }
424
+ }
425
+ }
0 commit comments