@@ -2,10 +2,12 @@ package controller
2
2
3
3
import (
4
4
"context"
5
- "time "
5
+ "slices "
6
6
7
+ "github.com/go-logr/logr"
7
8
networkingv1 "k8s.io/api/networking/v1"
8
9
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10
+ "k8s.io/apimachinery/pkg/types"
9
11
"k8s.io/utils/ptr"
10
12
"sigs.k8s.io/controller-runtime/pkg/client"
11
13
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
@@ -19,115 +21,107 @@ import (
19
21
func (r * HTTPRouteReconciler ) processHTTPRoutePolicies (tctx * provider.TranslateContext , httpRoute * gatewayv1.HTTPRoute ) error {
20
22
// list HTTPRoutePolices which sectionName is not specified
21
23
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 ())
28
26
)
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 {
30
28
return err
31
29
}
32
30
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
36
33
}
37
34
35
+ var conflicts = make (map [types.NamespacedName ]v1alpha1.HTTPRoutePolicy )
38
36
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
+ }
41
43
}
44
+ }
42
45
46
+ for i := range list .Items {
43
47
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"
47
54
)
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 )
54
61
}
62
+ modifyHTTPRoutePolicyStatus (httpRoute .Spec .ParentRefs , & policy , status , reason , message )
63
+ tctx .StatusUpdaters = append (tctx .StatusUpdaters , & policy )
55
64
}
56
65
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
+ }
74
68
69
+ func (r * HTTPRouteReconciler ) updateHTTPRoutePolicyStatusOnDeleting (nn types.NamespacedName ) error {
75
70
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 )
79
73
)
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
87
76
}
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 ... )
94
93
}
94
+ // delete AncestorRef which is not exist in the all parentRefs for each policy
95
+ updateDeleteAncestors (r .Client , r .Log , policy , parentRefs )
95
96
}
96
97
97
98
return nil
98
99
}
99
100
100
101
func (r * IngressReconciler ) processHTTPRoutePolicies (tctx * provider.TranslateContext , ingress * networkingv1.Ingress ) error {
101
102
var (
102
- checker = conflictChecker {
103
- object : ingress ,
104
- policies : make (map [targetRefKey ][]v1alpha1.HTTPRoutePolicy ),
105
- conflict : false ,
106
- }
107
103
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 ())
109
105
)
110
106
if err := r .List (context .Background (), & list , client.MatchingFields {indexer .PolicyTargetRefs : key }); err != nil {
111
107
return err
112
108
}
113
109
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
117
112
}
118
113
119
114
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 )
127
117
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 = ""
128
123
129
- // clear HTTPRoutePolicies from TranslateContext
130
- tctx .HTTPRoutePolicies = make (map [string ][]v1alpha1.HTTPRoutePolicy )
124
+ tctx .HTTPRoutePolicies = list .Items
131
125
}
132
126
133
127
for i := range list .Items {
@@ -139,12 +133,54 @@ func (r *IngressReconciler) processHTTPRoutePolicies(tctx *provider.TranslateCon
139
133
return nil
140
134
}
141
135
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
+
142
178
func modifyHTTPRoutePolicyStatus (parentRefs []gatewayv1.ParentReference , policy * v1alpha1.HTTPRoutePolicy , status bool , reason , message string ) {
143
179
condition := metav1.Condition {
144
180
Type : string (v1alpha2 .PolicyConditionAccepted ),
145
181
Status : metav1 .ConditionTrue ,
146
182
ObservedGeneration : policy .GetGeneration (),
147
- LastTransitionTime : metav1.Time { Time : time . Now ()} ,
183
+ LastTransitionTime : metav1 .Now (),
148
184
Reason : reason ,
149
185
Message : message ,
150
186
}
@@ -154,37 +190,48 @@ func modifyHTTPRoutePolicyStatus(parentRefs []gatewayv1.ParentReference, policy
154
190
_ = SetAncestors (& policy .Status , parentRefs , condition )
155
191
}
156
192
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
161
208
}
162
209
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
168
222
}
169
223
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" )
188
235
}
189
236
}
190
237
}
0 commit comments