@@ -8,6 +8,7 @@ package kubernetes
88import (
99 "context"
1010 "fmt"
11+ "reflect"
1112
1213 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1314 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -111,7 +112,7 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
111112 Spec : h .Spec ,
112113 Status : gwapiv1.HTTPRouteStatus {
113114 RouteStatus : gwapiv1.RouteStatus {
114- Parents : mergeRouteParentStatus (h .Namespace , h .Status .Parents , valCopy .Parents ),
115+ Parents : mergeStatus (h .Namespace , r . envoyGateway . Gateway . ControllerName , h .Status .Parents , valCopy .Parents ),
115116 },
116117 },
117118 }
@@ -151,7 +152,7 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
151152 Spec : g .Spec ,
152153 Status : gwapiv1.GRPCRouteStatus {
153154 RouteStatus : gwapiv1.RouteStatus {
154- Parents : mergeRouteParentStatus (g .Namespace , g .Status .Parents , valCopy .Parents ),
155+ Parents : mergeStatus (g .Namespace , r . envoyGateway . Gateway . ControllerName , g .Status .Parents , valCopy .Parents ),
155156 },
156157 },
157158 }
@@ -193,7 +194,7 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
193194 Spec : t .Spec ,
194195 Status : gwapiv1a2.TLSRouteStatus {
195196 RouteStatus : gwapiv1.RouteStatus {
196- Parents : mergeRouteParentStatus (t .Namespace , t .Status .Parents , valCopy .Parents ),
197+ Parents : mergeStatus (t .Namespace , r . envoyGateway . Gateway . ControllerName , t .Status .Parents , valCopy .Parents ),
197198 },
198199 },
199200 }
@@ -235,7 +236,7 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
235236 Spec : t .Spec ,
236237 Status : gwapiv1a2.TCPRouteStatus {
237238 RouteStatus : gwapiv1.RouteStatus {
238- Parents : mergeRouteParentStatus (t .Namespace , t .Status .Parents , valCopy .Parents ),
239+ Parents : mergeStatus (t .Namespace , r . envoyGateway . Gateway . ControllerName , t .Status .Parents , valCopy .Parents ),
239240 },
240241 },
241242 }
@@ -277,7 +278,7 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
277278 Spec : u .Spec ,
278279 Status : gwapiv1a2.UDPRouteStatus {
279280 RouteStatus : gwapiv1.RouteStatus {
280- Parents : mergeRouteParentStatus (u .Namespace , u .Status .Parents , valCopy .Parents ),
281+ Parents : mergeStatus (u .Namespace , r . envoyGateway . Gateway . ControllerName , u .Status .Parents , valCopy .Parents ),
281282 },
282283 },
283284 }
@@ -317,7 +318,9 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
317318 TypeMeta : t .TypeMeta ,
318319 ObjectMeta : t .ObjectMeta ,
319320 Spec : t .Spec ,
320- Status : * valCopy ,
321+ Status : gwapiv1.PolicyStatus {
322+ Ancestors : mergeStatus (t .Namespace , r .envoyGateway .Gateway .ControllerName , t .Status .Ancestors , valCopy .Ancestors ),
323+ },
321324 }
322325 return tCopy
323326 }),
@@ -355,7 +358,9 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
355358 TypeMeta : t .TypeMeta ,
356359 ObjectMeta : t .ObjectMeta ,
357360 Spec : t .Spec ,
358- Status : * valCopy ,
361+ Status : gwapiv1.PolicyStatus {
362+ Ancestors : mergeStatus (t .Namespace , r .envoyGateway .Gateway .ControllerName , t .Status .Ancestors , valCopy .Ancestors ),
363+ },
359364 }
360365 return tCopy
361366 }),
@@ -393,7 +398,9 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
393398 TypeMeta : t .TypeMeta ,
394399 ObjectMeta : t .ObjectMeta ,
395400 Spec : t .Spec ,
396- Status : * valCopy ,
401+ Status : gwapiv1.PolicyStatus {
402+ Ancestors : mergeStatus (t .Namespace , r .envoyGateway .Gateway .ControllerName , t .Status .Ancestors , valCopy .Ancestors ),
403+ },
397404 }
398405 return tCopy
399406 }),
@@ -431,7 +438,9 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
431438 TypeMeta : t .TypeMeta ,
432439 ObjectMeta : t .ObjectMeta ,
433440 Spec : t .Spec ,
434- Status : * valCopy ,
441+ Status : gwapiv1.PolicyStatus {
442+ Ancestors : mergeStatus (t .Namespace , r .envoyGateway .Gateway .ControllerName , t .Status .Ancestors , valCopy .Ancestors ),
443+ },
435444 }
436445 return tCopy
437446 }),
@@ -467,7 +476,9 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
467476 TypeMeta : t .TypeMeta ,
468477 ObjectMeta : t .ObjectMeta ,
469478 Spec : t .Spec ,
470- Status : * valCopy ,
479+ Status : gwapiv1.PolicyStatus {
480+ Ancestors : mergeStatus (t .Namespace , r .envoyGateway .Gateway .ControllerName , t .Status .Ancestors , valCopy .Ancestors ),
481+ },
471482 }
472483 return tCopy
473484 }),
@@ -505,7 +516,9 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
505516 TypeMeta : t .TypeMeta ,
506517 ObjectMeta : t .ObjectMeta ,
507518 Spec : t .Spec ,
508- Status : * valCopy ,
519+ Status : gwapiv1.PolicyStatus {
520+ Ancestors : mergeStatus (t .Namespace , r .envoyGateway .Gateway .ControllerName , t .Status .Ancestors , valCopy .Ancestors ),
521+ },
509522 }
510523 return tCopy
511524 }),
@@ -579,10 +592,11 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
579592 errChan <- err
580593 panic (err )
581594 }
582- tCopy := t .DeepCopy ()
583595 valCopy := val .DeepCopy ()
584596 setLastTransitionTimeInConditionsForPolicyStatus (valCopy , metav1 .Now ())
585- tCopy .Object ["status" ] = * valCopy
597+ tCopy := t .DeepCopy ()
598+ oldStatus := gatewayapi .ExtServerPolicyStatusAsPolicyStatus (tCopy )
599+ tCopy .Object ["status" ] = mergeStatus (t .GetNamespace (), r .envoyGateway .Gateway .ControllerName , oldStatus .Ancestors , valCopy .Ancestors )
586600 return tCopy
587601 }),
588602 })
@@ -593,31 +607,28 @@ func (r *gatewayAPIReconciler) updateStatusFromSubscriptions(ctx context.Context
593607 }
594608}
595609
596- // mergeRouteParentStatus merges the old and new RouteParentStatus.
597- // This is needed because the RouteParentStatus doesn't support strategic merge patch yet.
598- func mergeRouteParentStatus (ns string , old , new []gwapiv1.RouteParentStatus ) []gwapiv1.RouteParentStatus {
610+ // mergeStatus merges the old and new `RouteParentStatus`/`PolicyAncestorStatus`.
611+ // This is needed because the `RouteParentStatus`/`PolicyAncestorStatus` doesn't support strategic merge patch yet.
612+ // This depends on the fact that we get the full updated status of the route/policy (all parents/ancestors), and will break otherwise.
613+ func mergeStatus [K interface {}](ns , controllerName string , old , new []K ) []K {
599614 // Allocating with worst-case capacity to avoid reallocation.
600- merged := make ([]gwapiv1. RouteParentStatus , 0 , len (old )+ len (new ))
615+ merged := make ([]K , 0 , len (old )+ len (new ))
601616
602617 // Range over old status parentRefs in order:
603618 // 1. The parentRef exists in the new status: append the new one to the final status.
604619 // 2. The parentRef doesn't exist in the new status and it's not our controller: append it to the final status.
605- // 3. The parentRef doesn't exist in the new status, and it is our controller: keep it in the final status.
606- // This is important for routes with multiple parent references - not all parents are updated in each reconciliation.
620+ // 3. The parentRef doesn't exist in the new status, and it is our controller: don't append it to the final status.
607621 for _ , oldP := range old {
608622 found := - 1
609623 for newI , newP := range new {
610- if gatewayapi . IsParentRefEqual (oldP . ParentRef , newP . ParentRef , ns ) {
624+ if isParentOrAncestorRefEqual (oldP , newP , ns ) {
611625 found = newI
612626 break
613627 }
614628 }
615629 if found >= 0 {
616630 merged = append (merged , new [found ])
617- } else {
618- // Keep all old parent statuses, regardless of controller.
619- // For routes with multiple parents managed by the same controller,
620- // not all parents are necessarily updated in each reconciliation.
631+ } else if parentOrAncestorControllerName (oldP ) != gwapiv1 .GatewayController (controllerName ) {
621632 merged = append (merged , oldP )
622633 }
623634 }
@@ -626,7 +637,7 @@ func mergeRouteParentStatus(ns string, old, new []gwapiv1.RouteParentStatus) []g
626637 for _ , newP := range new {
627638 found := false
628639 for _ , mergedP := range merged {
629- if gatewayapi . IsParentRefEqual (newP . ParentRef , mergedP . ParentRef , ns ) {
640+ if isParentOrAncestorRefEqual (newP , mergedP , ns ) {
630641 found = true
631642 break
632643 }
@@ -639,6 +650,28 @@ func mergeRouteParentStatus(ns string, old, new []gwapiv1.RouteParentStatus) []g
639650 return merged
640651}
641652
653+ func isParentOrAncestorRefEqual [K any ](firstRef , secondRef K , ns string ) bool {
654+ switch reflect .TypeOf (firstRef ) {
655+ case reflect .TypeOf (gwapiv1.RouteParentStatus {}):
656+ return gatewayapi .IsParentRefEqual (any (firstRef ).(gwapiv1.RouteParentStatus ).ParentRef , any (secondRef ).(gwapiv1.RouteParentStatus ).ParentRef , ns )
657+ case reflect .TypeOf (gwapiv1.PolicyAncestorStatus {}):
658+ return gatewayapi .IsParentRefEqual (any (firstRef ).(gwapiv1.PolicyAncestorStatus ).AncestorRef , any (secondRef ).(gwapiv1.PolicyAncestorStatus ).AncestorRef , ns )
659+ default :
660+ return false
661+ }
662+ }
663+
664+ func parentOrAncestorControllerName [K any ](ref K ) gwapiv1.GatewayController {
665+ switch reflect .TypeOf (ref ) {
666+ case reflect .TypeOf (gwapiv1.RouteParentStatus {}):
667+ return any (ref ).(gwapiv1.RouteParentStatus ).ControllerName
668+ case reflect .TypeOf (gwapiv1.PolicyAncestorStatus {}):
669+ return any (ref ).(gwapiv1.PolicyAncestorStatus ).ControllerName
670+ default :
671+ return gwapiv1 .GatewayController ("" )
672+ }
673+ }
674+
642675func (r * gatewayAPIReconciler ) updateStatusForGateway (ctx context.Context , gtw * gwapiv1.Gateway ) {
643676 // nil check for unit tests.
644677 if r .statusUpdater == nil {
0 commit comments