@@ -2,10 +2,12 @@ package controller
22
33import (
44 "context"
5- "time "
5+ "slices "
66
7+ "github.com/go-logr/logr"
78 networkingv1 "k8s.io/api/networking/v1"
89 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+ "k8s.io/apimachinery/pkg/types"
911 "k8s.io/utils/ptr"
1012 "sigs.k8s.io/controller-runtime/pkg/client"
1113 gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
@@ -19,115 +21,107 @@ import (
1921func (r * HTTPRouteReconciler ) processHTTPRoutePolicies (tctx * provider.TranslateContext , httpRoute * gatewayv1.HTTPRoute ) error {
2022 // list HTTPRoutePolices which sectionName is not specified
2123 var (
22- checker = conflictChecker {
23- object : httpRoute ,
24- policies : make (map [targetRefKey ][]v1alpha1.HTTPRoutePolicy ),
25- }
26- listForAllRules v1alpha1.HTTPRoutePolicyList
27- key = indexer .GenHTTPRoutePolicyIndexKey (gatewayv1 .GroupName , "HTTPRoute" , httpRoute .GetNamespace (), httpRoute .GetName (), "" )
24+ list v1alpha1.HTTPRoutePolicyList
25+ key = indexer .GenIndexKeyWithGK (gatewayv1 .GroupName , "HTTPRoute" , httpRoute .GetNamespace (), httpRoute .GetName ())
2826 )
29- if err := r .List (context .Background (), & listForAllRules , client.MatchingFields {indexer .PolicyTargetRefs : key }); err != nil {
27+ if err := r .List (context .Background (), & list , client.MatchingFields {indexer .PolicyTargetRefs : key }); err != nil {
3028 return err
3129 }
3230
33- for _ , item := range listForAllRules .Items {
34- checker .append ("" , item )
35- tctx .HTTPRoutePolicies ["*" ] = append (tctx .HTTPRoutePolicies ["*" ], item )
31+ if len (list .Items ) == 0 {
32+ return nil
3633 }
3734
35+ var conflicts = make (map [types.NamespacedName ]v1alpha1.HTTPRoutePolicy )
3836 for _ , rule := range httpRoute .Spec .Rules {
39- if rule .Name == nil {
40- continue
37+ var policies = findPoliciesWhichTargetRefTheRule (rule .Name , "HTTPRoute" , list )
38+ if conflict := checkPoliciesConflict (policies ); conflict {
39+ for _ , policy := range policies {
40+ namespacedName := types.NamespacedName {Namespace : policy .GetNamespace (), Name : policy .GetName ()}
41+ conflicts [namespacedName ] = policy
42+ }
4143 }
44+ }
4245
46+ for i := range list .Items {
4347 var (
44- ruleName = string (* rule .Name )
45- listForSectionRules v1alpha1.HTTPRoutePolicyList
46- key = indexer .GenHTTPRoutePolicyIndexKey (gatewayv1 .GroupName , "HTTPRoute" , httpRoute .GetNamespace (), httpRoute .GetName (), ruleName )
48+ policy = list .Items [i ]
49+ namespacedName = types.NamespacedName {Namespace : policy .GetNamespace (), Name : policy .GetName ()}
50+
51+ status = false
52+ reason = string (v1alpha2 .PolicyReasonConflicted )
53+ message = "HTTPRoutePolicy conflict with others target to the HTTPRoute"
4754 )
48- if err := r . List ( context . Background (), & listForSectionRules , client. MatchingFields { indexer . PolicyTargetRefs : key }); err != nil {
49- continue
50- }
51- for _ , item := range listForSectionRules . Items {
52- checker . append ( ruleName , item )
53- tctx .HTTPRoutePolicies [ ruleName ] = append (tctx .HTTPRoutePolicies [ ruleName ], item )
55+ if _ , conflict := conflicts [ namespacedName ]; ! conflict {
56+ status = true
57+ reason = string ( v1alpha2 . PolicyReasonAccepted )
58+ message = ""
59+
60+ tctx .HTTPRoutePolicies = append (tctx .HTTPRoutePolicies , policy )
5461 }
62+ modifyHTTPRoutePolicyStatus (httpRoute .Spec .ParentRefs , & policy , status , reason , message )
63+ tctx .StatusUpdaters = append (tctx .StatusUpdaters , & policy )
5564 }
5665
57- // todo: unreachable
58- // if the HTTPRoute is deleted, clear tctx.HTTPRoutePolicies and delete Ancestors from HTTPRoutePolicies status
59- // if !httpRoute.GetDeletionTimestamp().IsZero() {
60- // for _, policies := range checker.policies {
61- // for i := range policies {
62- // policy := policies[i]
63- // _ = DeleteAncestors(&policy.Status, httpRoute.Spec.ParentRefs)
64- // data, _ := json.Marshal(policy.Status)
65- // r.Log.Info("policy status after delete ancestor", "data", string(data))
66- // if err := r.Status().Update(context.Background(), &policy); err != nil {
67- // r.Log.Error(err, "failed to Update policy status")
68- // }
69- // // tctx.StatusUpdaters = append(tctx.StatusUpdaters, &policy)
70- // }
71- // }
72- // return nil
73- // }
66+ return nil
67+ }
7468
69+ func (r * HTTPRouteReconciler ) updateHTTPRoutePolicyStatusOnDeleting (nn types.NamespacedName ) error {
7570 var (
76- status = true
77- reason = string (v1alpha2 .PolicyReasonAccepted )
78- message string
71+ list v1alpha1.HTTPRoutePolicyList
72+ key = indexer .GenIndexKeyWithGK (gatewayv1 .GroupName , "HTTPRoute" , nn .Namespace , nn .Name )
7973 )
80- if checker .conflict {
81- status = false
82- reason = string (v1alpha2 .PolicyReasonConflicted )
83- message = "HTTPRoutePolicy conflict with others target to the HTTPRoute"
84-
85- // clear HTTPRoutePolices from TranslateContext
86- tctx .HTTPRoutePolicies = make (map [string ][]v1alpha1.HTTPRoutePolicy )
74+ if err := r .List (context .Background (), & list , client.MatchingFields {indexer .PolicyTargetRefs : key }); err != nil {
75+ return err
8776 }
88-
89- for _ , policies := range checker .policies {
90- for i := range policies {
91- policy := policies [i ]
92- modifyHTTPRoutePolicyStatus (httpRoute .Spec .ParentRefs , & policy , status , reason , message )
93- tctx .StatusUpdaters = append (tctx .StatusUpdaters , & policy )
77+ var (
78+ httpRoutes = make (map [types.NamespacedName ]gatewayv1.HTTPRoute )
79+ )
80+ for _ , policy := range list .Items {
81+ // collect all parentRefs for the HTTPRoutePolicy
82+ var parentRefs []gatewayv1.ParentReference
83+ for _ , ref := range policy .Spec .TargetRefs {
84+ var namespacedName = types.NamespacedName {Namespace : policy .GetNamespace (), Name : string (ref .Name )}
85+ httpRoute , ok := httpRoutes [namespacedName ]
86+ if ! ok {
87+ if err := r .Get (context .Background (), namespacedName , & httpRoute ); err != nil {
88+ continue
89+ }
90+ httpRoutes [namespacedName ] = httpRoute
91+ }
92+ parentRefs = append (parentRefs , httpRoute .Spec .ParentRefs ... )
9493 }
94+ // delete AncestorRef which is not exist in the all parentRefs for each policy
95+ updateDeleteAncestors (r .Client , r .Log , policy , parentRefs )
9596 }
9697
9798 return nil
9899}
99100
100101func (r * IngressReconciler ) processHTTPRoutePolicies (tctx * provider.TranslateContext , ingress * networkingv1.Ingress ) error {
101102 var (
102- checker = conflictChecker {
103- object : ingress ,
104- policies : make (map [targetRefKey ][]v1alpha1.HTTPRoutePolicy ),
105- conflict : false ,
106- }
107103 list v1alpha1.HTTPRoutePolicyList
108- key = indexer .GenHTTPRoutePolicyIndexKey (networkingv1 .GroupName , "Ingress" , ingress .GetNamespace (), ingress .GetName (), "" )
104+ key = indexer .GenIndexKeyWithGK (networkingv1 .GroupName , "Ingress" , ingress .GetNamespace (), ingress .GetName ())
109105 )
110106 if err := r .List (context .Background (), & list , client.MatchingFields {indexer .PolicyTargetRefs : key }); err != nil {
111107 return err
112108 }
113109
114- for _ , item := range list .Items {
115- checker .append ("" , item )
116- tctx .HTTPRoutePolicies ["*" ] = append (tctx .HTTPRoutePolicies ["*" ], item )
110+ if len (list .Items ) == 0 {
111+ return nil
117112 }
118113
119114 var (
120- status = true
121- reason = string (v1alpha2 .PolicyReasonAccepted )
122- message string
123- )
124- if checker .conflict {
125- status = false
126- reason = string (v1alpha2 .PolicyReasonConflicted )
115+ status = false
116+ reason = string (v1alpha2 .PolicyReasonConflicted )
127117 message = "HTTPRoutePolicy conflict with others target to the Ingress"
118+ )
119+ if conflict := checkPoliciesConflict (list .Items ); ! conflict {
120+ status = true
121+ reason = string (v1alpha2 .PolicyReasonAccepted )
122+ message = ""
128123
129- // clear HTTPRoutePolicies from TranslateContext
130- tctx .HTTPRoutePolicies = make (map [string ][]v1alpha1.HTTPRoutePolicy )
124+ tctx .HTTPRoutePolicies = list .Items
131125 }
132126
133127 for i := range list .Items {
@@ -139,12 +133,54 @@ func (r *IngressReconciler) processHTTPRoutePolicies(tctx *provider.TranslateCon
139133 return nil
140134}
141135
136+ func (r * IngressReconciler ) updateHTTPRoutePolicyStatusOnDeleting (nn types.NamespacedName ) error {
137+ var (
138+ list v1alpha1.HTTPRoutePolicyList
139+ key = indexer .GenIndexKeyWithGK (networkingv1 .GroupName , "Ingress" , nn .Namespace , nn .Name )
140+ )
141+ if err := r .List (context .Background (), & list , client.MatchingFields {indexer .PolicyTargetRefs : key }); err != nil {
142+ return err
143+ }
144+ var (
145+ ingress2ParentRef = make (map [types.NamespacedName ]gatewayv1.ParentReference )
146+ )
147+ for _ , policy := range list .Items {
148+ // collect all parentRefs for the HTTPRoutePolicy
149+ var parentRefs []gatewayv1.ParentReference
150+ for _ , ref := range policy .Spec .TargetRefs {
151+ var namespacedName = types.NamespacedName {Namespace : policy .GetNamespace (), Name : string (ref .Name )}
152+ parentRef , ok := ingress2ParentRef [namespacedName ]
153+ if ! ok {
154+ var ingress networkingv1.Ingress
155+ if err := r .Get (context .Background (), namespacedName , & ingress ); err != nil {
156+ continue
157+ }
158+ ingressClass , err := r .getIngressClass (& ingress )
159+ if err != nil {
160+ continue
161+ }
162+ parentRef = gatewayv1.ParentReference {
163+ Group : ptr .To (gatewayv1 .Group (ingressClass .GroupVersionKind ().Group )),
164+ Kind : ptr .To (gatewayv1 .Kind ("IngressClass" )),
165+ Name : gatewayv1 .ObjectName (ingressClass .Name ),
166+ }
167+ ingress2ParentRef [namespacedName ] = parentRef
168+ }
169+ parentRefs = append (parentRefs , parentRef )
170+ }
171+ // delete AncestorRef which is not exist in the all parentRefs
172+ updateDeleteAncestors (r .Client , r .Log , policy , parentRefs )
173+ }
174+
175+ return nil
176+ }
177+
142178func modifyHTTPRoutePolicyStatus (parentRefs []gatewayv1.ParentReference , policy * v1alpha1.HTTPRoutePolicy , status bool , reason , message string ) {
143179 condition := metav1.Condition {
144180 Type : string (v1alpha2 .PolicyConditionAccepted ),
145181 Status : metav1 .ConditionTrue ,
146182 ObservedGeneration : policy .GetGeneration (),
147- LastTransitionTime : metav1.Time { Time : time . Now ()} ,
183+ LastTransitionTime : metav1 .Now (),
148184 Reason : reason ,
149185 Message : message ,
150186 }
@@ -154,37 +190,48 @@ func modifyHTTPRoutePolicyStatus(parentRefs []gatewayv1.ParentReference, policy
154190 _ = SetAncestors (& policy .Status , parentRefs , condition )
155191}
156192
157- type conflictChecker struct {
158- object client.Object
159- policies map [targetRefKey ][]v1alpha1.HTTPRoutePolicy
160- conflict bool
193+ // checkPoliciesConflict determines if there is a conflict among the given HTTPRoutePolicy objects based on their priority values.
194+ // It returns true if any policy has a different priority than the first policy in the list, otherwise false.
195+ // An empty or single-element policies slice is considered non-conflicting.
196+ // The function assumes all policies have a valid Spec.Priority field for comparison.
197+ func checkPoliciesConflict (policies []v1alpha1.HTTPRoutePolicy ) bool {
198+ if len (policies ) == 0 {
199+ return false
200+ }
201+ priority := policies [0 ].Spec .Priority
202+ for _ , policy := range policies {
203+ if ! ptr .Equal (policy .Spec .Priority , priority ) {
204+ return true
205+ }
206+ }
207+ return false
161208}
162209
163- type targetRefKey struct {
164- Group gatewayv1.Group
165- Namespace gatewayv1.Namespace
166- Name gatewayv1.ObjectName
167- SectionName gatewayv1.SectionName
210+ // findPoliciesWhichTargetRefTheRule filters HTTPRoutePolicy objects whose TargetRefs match the given ruleName and kind.
211+ // A match occurs if the TargetRef's Kind equals the provided kind and its SectionName is nil, empty, or equal to ruleName.
212+ func findPoliciesWhichTargetRefTheRule (ruleName * gatewayv1.SectionName , kind string , list v1alpha1.HTTPRoutePolicyList ) (policies []v1alpha1.HTTPRoutePolicy ) {
213+ for _ , policy := range list .Items {
214+ for _ , ref := range policy .Spec .TargetRefs {
215+ if string (ref .Kind ) == kind && (ref .SectionName == nil || * ref .SectionName == "" || ptr .Equal (ref .SectionName , ruleName )) {
216+ policies = append (policies , policy )
217+ break
218+ }
219+ }
220+ }
221+ return
168222}
169223
170- func (c * conflictChecker ) append (sectionName string , policy v1alpha1.HTTPRoutePolicy ) {
171- key := targetRefKey {
172- Group : gatewayv1 .GroupName ,
173- Namespace : gatewayv1 .Namespace (c .object .GetNamespace ()),
174- Name : gatewayv1 .ObjectName (c .object .GetName ()),
175- SectionName : gatewayv1 .SectionName (sectionName ),
176- }
177- c .policies [key ] = append (c .policies [key ], policy )
178-
179- if ! c .conflict {
180- Loop:
181- for _ , items := range c .policies {
182- for _ , item := range items {
183- if ! ptr .Equal (item .Spec .Priority , policy .Spec .Priority ) {
184- c .conflict = true
185- break Loop
186- }
187- }
224+ // updateDeleteAncestors removes ancestor references from HTTPRoutePolicy statuses that are no longer present in the provided parentRefs.
225+ func updateDeleteAncestors (client client.Client , logger logr.Logger , policy v1alpha1.HTTPRoutePolicy , parentRefs []gatewayv1.ParentReference ) {
226+ length := len (policy .Status .Ancestors )
227+ policy .Status .Ancestors = slices .DeleteFunc (policy .Status .Ancestors , func (status v1alpha2.PolicyAncestorStatus ) bool {
228+ return ! slices .ContainsFunc (parentRefs , func (ref gatewayv1.ParentReference ) bool {
229+ return parentRefValueEqual (status .AncestorRef , ref )
230+ })
231+ })
232+ if length != len (policy .Status .Ancestors ) {
233+ if err := client .Status ().Update (context .Background (), & policy ); err != nil {
234+ logger .Error (err , "failed to update HTTPRoutePolicy status" )
188235 }
189236 }
190237}
0 commit comments