@@ -3,6 +3,7 @@ package graph
33import (
44 "fmt"
55 "slices"
6+ "strings"
67
78 "github.com/go-logr/logr"
89 "k8s.io/apimachinery/pkg/types"
@@ -75,12 +76,16 @@ func validateBackendTLSPolicy(
7576 valid = true
7677 ignored = false
7778
78- // Note: Ancestor limit checking moved to addGatewaysForBackendTLSPolicies for per-gateway effectiveness tracking
79- // The policy may be partially effective (work for some gateways but not others due to ancestor limits)
79+ // Ancestor limit handling is now done during gateway assignment phase, not validation
80+ // if backendTLSPolicyAncestorsFull(backendTLSPolicy.Status.Ancestors, ctlrName) {
81+ // valid = false
82+ // ignored = true
83+ // return
84+ // }
8085
8186 if err := validateBackendTLSHostname (backendTLSPolicy ); err != nil {
8287 valid = false
83- conds = append (conds , conditions .NewPolicyInvalid (fmt . Sprintf ( "invalid hostname: %s" , err .Error () )))
88+ conds = append (conds , conditions .NewPolicyInvalid (err .Error ()))
8489 }
8590
8691 caCertRefs := backendTLSPolicy .Spec .Validation .CACertificateRefs
@@ -182,61 +187,148 @@ func validateBackendTLSWellKnownCACerts(btp *v1alpha3.BackendTLSPolicy) error {
182187 return nil
183188}
184189
185- func addGatewaysForBackendTLSPolicies (
186- backendTLSPolicies map [types.NamespacedName ]* BackendTLSPolicy ,
190+ // countNonNGFAncestors counts the number of non-NGF ancestors in policy status.
191+ func countNonNGFAncestors (policy * v1alpha3.BackendTLSPolicy , ctlrName string ) int {
192+ nonNGFCount := 0
193+ for _ , ancestor := range policy .Status .Ancestors {
194+ if string (ancestor .ControllerName ) != ctlrName {
195+ nonNGFCount ++
196+ }
197+ }
198+ return nonNGFCount
199+ }
200+
201+ // addPolicyAncestorLimitCondition adds or updates a PolicyAncestorLimitReached condition.
202+ func addPolicyAncestorLimitCondition (
203+ conds []conditions.Condition ,
204+ policyName string ,
205+ policyType string ,
206+ ) []conditions.Condition {
207+ const policyAncestorLimitReachedType = "PolicyAncestorLimitReached"
208+
209+ for i , condition := range conds {
210+ if condition .Type == policyAncestorLimitReachedType {
211+ if ! strings .Contains (condition .Message , policyName ) {
212+ conds [i ].Message = fmt .Sprintf ("%s, %s %s" , condition .Message , policyType , policyName )
213+ }
214+ return conds
215+ }
216+ }
217+
218+ newCondition := conditions .NewPolicyAncestorLimitReached ()
219+ newCondition .Message = fmt .Sprintf ("%s %s %s" , newCondition .Message , policyType , policyName )
220+ conds = append (conds , newCondition )
221+ return conds
222+ }
223+
224+ // collectOrderedGateways collects gateways in spec order (services) then creation time order (gateways within service).
225+ func collectOrderedGateways (
226+ policy * v1alpha3.BackendTLSPolicy ,
187227 services map [types.NamespacedName ]* ReferencedService ,
188- ctlrName string ,
189228 gateways map [types.NamespacedName ]* Gateway ,
190- logger logr.Logger ,
191- ) {
192- for _ , backendTLSPolicy := range backendTLSPolicies {
193- potentialGateways := make (map [types.NamespacedName ]struct {})
229+ existingNGFGatewayAncestors map [types.NamespacedName ]struct {},
230+ ) (existingGateways []types.NamespacedName , newGateways []types.NamespacedName ) {
231+ seenGateways := make (map [types.NamespacedName ]struct {})
232+
233+ // Process services in spec order to maintain deterministic gateway ordering
234+ for _ , refs := range policy .Spec .TargetRefs {
235+ if refs .Kind != kinds .Service {
236+ continue
237+ }
238+
239+ svcNsName := types.NamespacedName {
240+ Namespace : policy .Namespace ,
241+ Name : string (refs .Name ),
242+ }
243+
244+ referencedService , exists := services [svcNsName ]
245+ if ! exists {
246+ continue
247+ }
194248
195- // First, collect all potential gateways for this policy
196- for _ , refs := range backendTLSPolicy . Source . Spec . TargetRefs {
197- if refs . Kind != kinds . Service {
249+ // Add to ordered lists, categorizing existing vs new, skipping duplicates
250+ for gateway := range referencedService . GatewayNsNames {
251+ if _ , seen := seenGateways [ gateway ]; seen {
198252 continue
199253 }
254+ seenGateways [gateway ] = struct {}{}
255+ if _ , exists := existingNGFGatewayAncestors [gateway ]; exists {
256+ existingGateways = append (existingGateways , gateway )
257+ } else {
258+ newGateways = append (newGateways , gateway )
259+ }
260+ }
261+ }
200262
201- for svcNsName , referencedServices := range services {
202- if svcNsName .Name != string (refs .Name ) {
203- continue
204- }
263+ sortGatewaysByCreationTime (existingGateways , gateways )
264+ sortGatewaysByCreationTime (newGateways , gateways )
205265
206- for gateway := range referencedServices .GatewayNsNames {
207- potentialGateways [gateway ] = struct {}{}
208- }
266+ return existingGateways , newGateways
267+ }
268+
269+ func extractExistingNGFGatewayAncestors (
270+ backendTLSPolicy * v1alpha3.BackendTLSPolicy ,
271+ ctlrName string ,
272+ ) map [types.NamespacedName ]struct {} {
273+ existingNGFGatewayAncestors := make (map [types.NamespacedName ]struct {})
274+
275+ for _ , ancestor := range backendTLSPolicy .Status .Ancestors {
276+ if string (ancestor .ControllerName ) != ctlrName {
277+ continue
278+ }
279+
280+ if ancestor .AncestorRef .Kind != nil && * ancestor .AncestorRef .Kind == v1 .Kind (kinds .Gateway ) &&
281+ ancestor .AncestorRef .Namespace != nil {
282+ gatewayNsName := types.NamespacedName {
283+ Namespace : string (* ancestor .AncestorRef .Namespace ),
284+ Name : string (ancestor .AncestorRef .Name ),
209285 }
286+ existingNGFGatewayAncestors [gatewayNsName ] = struct {}{}
210287 }
288+ }
289+
290+ return existingNGFGatewayAncestors
291+ }
211292
212- // Now check each potential gateway against ancestor limits
213- for gatewayNsName := range potentialGateways {
214- // Create a proposed ancestor reference for this gateway
215- proposedAncestor := createParentReference (v1 .GroupName , kinds .Gateway , gatewayNsName )
293+ func addGatewaysForBackendTLSPolicies (
294+ backendTLSPolicies map [types.NamespacedName ]* BackendTLSPolicy ,
295+ services map [types.NamespacedName ]* ReferencedService ,
296+ ctlrName string ,
297+ gateways map [types.NamespacedName ]* Gateway ,
298+ logger logr.Logger ,
299+ ) {
300+ for _ , backendTLSPolicy := range backendTLSPolicies {
301+ existingNGFGatewayAncestors := extractExistingNGFGatewayAncestors (backendTLSPolicy .Source , ctlrName )
302+ existingGateways , newGateways := collectOrderedGateways (
303+ backendTLSPolicy .Source , services , gateways , existingNGFGatewayAncestors )
304+
305+ existingGateways = append (existingGateways , newGateways ... )
306+ orderedGateways := existingGateways
216307
217- // Check ancestor limit for BackendTLS policy
218- isFull := backendTLSPolicyAncestorsFull (
219- backendTLSPolicy .Source .Status .Ancestors ,
220- ctlrName ,
221- )
308+ ancestorCount := countNonNGFAncestors (backendTLSPolicy .Source , ctlrName )
222309
223- if isFull {
310+ // Process each gateway, respecting ancestor limits
311+ for _ , gatewayNsName := range orderedGateways {
312+ // Check if adding this gateway would exceed the ancestor limit
313+ if ancestorCount >= maxAncestors {
224314 policyName := backendTLSPolicy .Source .Namespace + "/" + backendTLSPolicy .Source .Name
315+ proposedAncestor := createParentReference (v1 .GroupName , kinds .Gateway , gatewayNsName )
225316 gatewayName := getAncestorName (proposedAncestor )
226- gateway , ok := gateways [ gatewayNsName ]
227- if ok {
228- gateway .Conditions = append (gateway .Conditions , conditions . NewPolicyAncestorLimitReached ( policyName ) )
317+
318+ if gateway , ok := gateways [ gatewayNsName ]; ok {
319+ gateway .Conditions = addPolicyAncestorLimitCondition (gateway .Conditions , policyName , kinds . BackendTLSPolicy )
229320 } else {
230- // Not found in the graph, log the issue. I don't think this should happen.
231- logger .Info ("Gateway not found in the graph" , "policy" , policyName , "ancestor" , gatewayName )
321+ // This should never happen, but we'll log it if it does
322+ logger .Error (fmt .Errorf ("gateway not found in the graph" ),
323+ "Gateway not found in the graph" , "policy" , policyName , "ancestor" , gatewayName )
232324 }
233325
234326 LogAncestorLimitReached (logger , policyName , "BackendTLSPolicy" , gatewayName )
235-
236327 continue
237328 }
238329
239- // Gateway can be effectively used by this policy
330+ ancestorCount ++
331+
240332 backendTLSPolicy .Gateways = append (backendTLSPolicy .Gateways , gatewayNsName )
241333 }
242334 }
0 commit comments