Skip to content

Commit 7a05bdf

Browse files
committed
feat: Update HTTPRoutePolicy handling for Ingress
Refactor the HTTPRoutePolicy update function to handle Ingress objects and improve logging. Add functionality to process HTTPRoutePolicies for Ingress in the IngressReconciler. Update tests to include scenarios for HTTPRoutePolicy targeting Ingress.
1 parent ba5c304 commit 7a05bdf

File tree

7 files changed

+396
-53
lines changed

7 files changed

+396
-53
lines changed

internal/controller/httproute_controller.go

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ func (r *HTTPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error {
130130
DeleteFunc: func(e event.DeleteEvent) bool {
131131
return true
132132
},
133-
UpdateFunc: r.httpRoutePolicyPredicateOnUpdate,
133+
UpdateFunc: httpRoutePolicyPredicateOnUpdate(r.genericEvent, "HTTPRoute"),
134134
GenericFunc: func(e event.GenericEvent) bool {
135135
return false
136136
},
@@ -400,7 +400,7 @@ func (r *HTTPRouteReconciler) listHTTPRouteByHTTPRoutePolicy(ctx context.Context
400400
}
401401

402402
var httpRoute gatewayv1.HTTPRoute
403-
if err := r.Get(ctx, client.ObjectKey{Namespace: key.Namespace, Name: key.Name}, &httpRoute); err != nil {
403+
if err := r.Get(ctx, key, &httpRoute); err != nil {
404404
r.Log.Error(err, "failed to get HTTPRoute by HTTPRoutePolicy targetRef", "namespace", key.Namespace, "name", key.Name)
405405
continue
406406
}
@@ -418,12 +418,7 @@ func (r *HTTPRouteReconciler) listHTTPRouteByHTTPRoutePolicy(ctx context.Context
418418
}
419419
}
420420
keys[key] = struct{}{}
421-
requests = append(requests, reconcile.Request{
422-
NamespacedName: types.NamespacedName{
423-
Namespace: key.Namespace,
424-
Name: key.Name,
425-
},
426-
})
421+
requests = append(requests, reconcile.Request{NamespacedName: key})
427422
}
428423

429424
return requests
@@ -466,14 +461,14 @@ func (r *HTTPRouteReconciler) listHTTPRouteForGenericEvent(ctx context.Context,
466461
if _, ok := namespacedNameMap[namespacedName]; !ok {
467462
namespacedNameMap[namespacedName] = struct{}{}
468463
if err := r.Get(ctx, namespacedName, new(gatewayv1.HTTPRoute)); err != nil {
469-
r.Log.Info("failed to Get HTTPRoute", "namespace", namespacedName.Namespace, "name", namespacedName.Name)
464+
r.Log.Error(err, "failed to Get HTTPRoute", "namespace", namespacedName.Namespace, "name", namespacedName.Name)
470465
continue
471466
}
472467
requests = append(requests, reconcile.Request{NamespacedName: namespacedName})
473468
}
474469
}
475470
default:
476-
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy")
471+
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy or HTTPRoutePolicy")
477472
}
478473
return requests
479474
}
@@ -595,28 +590,36 @@ func (r *HTTPRouteReconciler) processHTTPRoute(tctx *provider.TranslateContext,
595590
return terror
596591
}
597592

598-
func (r *HTTPRouteReconciler) httpRoutePolicyPredicateOnUpdate(e event.UpdateEvent) bool {
599-
oldPolicy, ok0 := e.ObjectOld.(*v1alpha1.HTTPRoutePolicy)
600-
newPolicy, ok1 := e.ObjectNew.(*v1alpha1.HTTPRoutePolicy)
601-
if !ok0 || !ok1 {
602-
return false
603-
}
604-
var discardsRefs = make(map[string]v1alpha2.LocalPolicyTargetReferenceWithSectionName)
605-
for _, ref := range oldPolicy.Spec.TargetRefs {
606-
key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "")
607-
discardsRefs[key] = ref
608-
}
609-
for _, ref := range newPolicy.Spec.TargetRefs {
610-
key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "")
611-
delete(discardsRefs, key)
612-
}
613-
if len(discardsRefs) > 0 {
614-
dump := oldPolicy.DeepCopy()
615-
dump.Spec.TargetRefs = make([]v1alpha2.LocalPolicyTargetReferenceWithSectionName, 0, len(discardsRefs))
616-
for _, ref := range discardsRefs {
617-
dump.Spec.TargetRefs = append(dump.Spec.TargetRefs, ref)
593+
func httpRoutePolicyPredicateOnUpdate(c chan event.GenericEvent, kind string) func(e event.UpdateEvent) bool {
594+
return func(e event.UpdateEvent) bool {
595+
oldPolicy, ok0 := e.ObjectOld.(*v1alpha1.HTTPRoutePolicy)
596+
newPolicy, ok1 := e.ObjectNew.(*v1alpha1.HTTPRoutePolicy)
597+
if !ok0 || !ok1 {
598+
return false
599+
}
600+
var discardsRefs = make(map[string]v1alpha2.LocalPolicyTargetReferenceWithSectionName)
601+
for _, ref := range oldPolicy.Spec.TargetRefs {
602+
if string(ref.Kind) != kind {
603+
continue
604+
}
605+
key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "")
606+
discardsRefs[key] = ref
607+
}
608+
for _, ref := range newPolicy.Spec.TargetRefs {
609+
if string(ref.Kind) != kind {
610+
continue
611+
}
612+
key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "")
613+
delete(discardsRefs, key)
614+
}
615+
if len(discardsRefs) > 0 {
616+
dump := oldPolicy.DeepCopy()
617+
dump.Spec.TargetRefs = make([]v1alpha2.LocalPolicyTargetReferenceWithSectionName, 0, len(discardsRefs))
618+
for _, ref := range discardsRefs {
619+
dump.Spec.TargetRefs = append(dump.Spec.TargetRefs, ref)
620+
}
621+
c <- event.GenericEvent{Object: dump}
618622
}
619-
r.genericEvent <- event.GenericEvent{Object: dump}
623+
return true
620624
}
621-
return true
622625
}

internal/controller/httproutepolicy.go

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"time"
66

7+
networkingv1 "k8s.io/api/networking/v1"
78
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
89
"k8s.io/utils/ptr"
910
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -19,8 +20,8 @@ func (r *HTTPRouteReconciler) processHTTPRoutePolicies(tctx *provider.TranslateC
1920
// list HTTPRoutePolices which sectionName is not specified
2021
var (
2122
checker = conflictChecker{
22-
httpRoute: httpRoute,
23-
policies: make(map[targetRefKey][]v1alpha1.HTTPRoutePolicy),
23+
object: httpRoute,
24+
policies: make(map[targetRefKey][]v1alpha1.HTTPRoutePolicy),
2425
}
2526
listForAllRules v1alpha1.HTTPRoutePolicyList
2627
key = indexer.GenHTTPRoutePolicyIndexKey(gatewayv1.GroupName, "HTTPRoute", httpRoute.GetNamespace(), httpRoute.GetName(), "")
@@ -111,10 +112,39 @@ func (r *HTTPRouteReconciler) modifyHTTPRoutePolicyStatus(httpRoute *gatewayv1.H
111112
_ = SetAncestors(&policy.Status, httpRoute.Spec.ParentRefs, condition)
112113
}
113114

115+
func (r *IngressReconciler) processHTTPRoutePolicies(tctx *provider.TranslateContext, ingress *networkingv1.Ingress) error {
116+
var (
117+
checker = conflictChecker{
118+
object: ingress,
119+
policies: make(map[targetRefKey][]v1alpha1.HTTPRoutePolicy),
120+
conflict: false,
121+
}
122+
list v1alpha1.HTTPRoutePolicyList
123+
key = indexer.GenHTTPRoutePolicyIndexKey(networkingv1.GroupName, "Ingress", ingress.GetNamespace(), ingress.GetName(), "")
124+
)
125+
if err := r.List(context.Background(), &list, client.MatchingFields{indexer.PolicyTargetRefs: key}); err != nil {
126+
return err
127+
}
128+
129+
for _, item := range list.Items {
130+
checker.append("", item)
131+
tctx.HTTPRoutePolicies["*"] = append(tctx.HTTPRoutePolicies["*"], item)
132+
}
133+
134+
if checker.conflict {
135+
// clear HTTPRoutePolicies from TranslateContext
136+
tctx.HTTPRoutePolicies = make(map[string][]v1alpha1.HTTPRoutePolicy)
137+
}
138+
139+
// todo: handle HTTPRoutePolicy status
140+
141+
return nil
142+
}
143+
114144
type conflictChecker struct {
115-
httpRoute *gatewayv1.HTTPRoute
116-
policies map[targetRefKey][]v1alpha1.HTTPRoutePolicy
117-
conflict bool
145+
object client.Object
146+
policies map[targetRefKey][]v1alpha1.HTTPRoutePolicy
147+
conflict bool
118148
}
119149

120150
type targetRefKey struct {
@@ -127,8 +157,8 @@ type targetRefKey struct {
127157
func (c *conflictChecker) append(sectionName string, policy v1alpha1.HTTPRoutePolicy) {
128158
key := targetRefKey{
129159
Group: gatewayv1.GroupName,
130-
Namespace: gatewayv1.Namespace(c.httpRoute.GetNamespace()),
131-
Name: gatewayv1.ObjectName(c.httpRoute.GetName()),
160+
Namespace: gatewayv1.Namespace(c.object.GetNamespace()),
161+
Name: gatewayv1.ObjectName(c.object.GetName()),
132162
SectionName: gatewayv1.SectionName(sectionName),
133163
}
134164
c.policies[key] = append(c.policies[key], policy)

internal/controller/indexer/indexer.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const (
2323
IngressClassRef = "ingressClassRef"
2424
ConsumerGatewayRef = "consumerGatewayRef"
2525
PolicyTargetRefs = "targetRefs"
26+
PolicyTargetRefIng = "targetRefIng"
2627
)
2728

2829
func SetupIndexer(mgr ctrl.Manager) error {
@@ -189,6 +190,16 @@ func setupIngressIndexer(mgr ctrl.Manager) error {
189190
return err
190191
}
191192

193+
// create HTTPRoutePolicy index
194+
if err := mgr.GetFieldIndexer().IndexField(
195+
context.Background(),
196+
&v1alpha1.HTTPRoutePolicy{},
197+
PolicyTargetRefIng,
198+
IngressHTTPRouteIndexFunc,
199+
); err != nil {
200+
return err
201+
}
202+
192203
return nil
193204
}
194205

@@ -256,6 +267,10 @@ func IngressSecretIndexFunc(rawObj client.Object) []string {
256267
return secrets
257268
}
258269

270+
func IngressHTTPRouteIndexFunc(rawObj client.Object) []string {
271+
return []string{GenHTTPRoutePolicyIndexKey(networkingv1.GroupName, "Ingress", rawObj.GetGenerateName(), rawObj.GetName(), "")}
272+
}
273+
259274
func GenIndexKeyWithGK(group, kind, namespace, name string) string {
260275
gvk := schema.GroupKind{
261276
Group: group,

internal/controller/ingress_controller.go

Lines changed: 95 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@ import (
66
"fmt"
77
"reflect"
88

9-
"github.com/api7/api7-ingress-controller/api/v1alpha1"
10-
"github.com/api7/api7-ingress-controller/internal/controller/config"
11-
"github.com/api7/api7-ingress-controller/internal/controller/indexer"
12-
"github.com/api7/api7-ingress-controller/internal/provider"
13-
"github.com/api7/gopkg/pkg/log"
149
"github.com/go-logr/logr"
1510
"go.uber.org/zap"
1611
corev1 "k8s.io/api/core/v1"
@@ -22,9 +17,17 @@ import (
2217
ctrl "sigs.k8s.io/controller-runtime"
2318
"sigs.k8s.io/controller-runtime/pkg/builder"
2419
"sigs.k8s.io/controller-runtime/pkg/client"
20+
"sigs.k8s.io/controller-runtime/pkg/event"
2521
"sigs.k8s.io/controller-runtime/pkg/handler"
2622
"sigs.k8s.io/controller-runtime/pkg/predicate"
2723
"sigs.k8s.io/controller-runtime/pkg/reconcile"
24+
"sigs.k8s.io/controller-runtime/pkg/source"
25+
26+
"github.com/api7/api7-ingress-controller/api/v1alpha1"
27+
"github.com/api7/api7-ingress-controller/internal/controller/config"
28+
"github.com/api7/api7-ingress-controller/internal/controller/indexer"
29+
"github.com/api7/api7-ingress-controller/internal/provider"
30+
"github.com/api7/gopkg/pkg/log"
2831
)
2932

3033
// IngressReconciler reconciles a Ingress object.
@@ -34,10 +37,14 @@ type IngressReconciler struct { //nolint:revive
3437
Log logr.Logger
3538

3639
Provider provider.Provider
40+
41+
genericEvent chan event.GenericEvent
3742
}
3843

3944
// SetupWithManager sets up the controller with the Manager.
4045
func (r *IngressReconciler) SetupWithManager(mgr ctrl.Manager) error {
46+
r.genericEvent = make(chan event.GenericEvent, 100)
47+
4148
return ctrl.NewControllerManagedBy(mgr).
4249
For(&networkingv1.Ingress{},
4350
builder.WithPredicates(
@@ -65,6 +72,29 @@ func (r *IngressReconciler) SetupWithManager(mgr ctrl.Manager) error {
6572
&corev1.Secret{},
6673
handler.EnqueueRequestsFromMapFunc(r.listIngressesBySecret),
6774
).
75+
Watches(&v1alpha1.HTTPRoutePolicy{},
76+
handler.EnqueueRequestsFromMapFunc(r.listIngressesByHTTPRoutePolicy),
77+
builder.WithPredicates(
78+
predicate.Funcs{
79+
CreateFunc: func(e event.CreateEvent) bool {
80+
return true
81+
},
82+
DeleteFunc: func(e event.DeleteEvent) bool {
83+
return true
84+
},
85+
UpdateFunc: httpRoutePolicyPredicateOnUpdate(r.genericEvent, "Ingress"),
86+
GenericFunc: func(e event.GenericEvent) bool {
87+
return false
88+
},
89+
},
90+
),
91+
).
92+
WatchesRawSource(
93+
source.Channel(
94+
r.genericEvent,
95+
handler.EnqueueRequestsFromMapFunc(r.listIngressesForGenericEvent),
96+
),
97+
).
6898
Complete(r)
6999
}
70100

@@ -121,6 +151,12 @@ func (r *IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
121151
return ctrl.Result{}, err
122152
}
123153

154+
// process HTTPRoutePolicy
155+
if err := r.processHTTPRoutePolicies(tctx, ingress); err != nil {
156+
r.Log.Error(err, "failed to process HTTPRoutePolicy", "ingress", ingress.Name)
157+
return ctrl.Result{}, err
158+
}
159+
124160
// update the ingress resources
125161
if err := r.Provider.Update(ctx, tctx, ingress); err != nil {
126162
r.Log.Error(err, "failed to update ingress resources", "ingress", ingress.Name)
@@ -341,6 +377,60 @@ func (r *IngressReconciler) listIngressesBySecret(ctx context.Context, obj clien
341377
return requests
342378
}
343379

380+
func (r *IngressReconciler) listIngressesByHTTPRoutePolicy(ctx context.Context, obj client.Object) (requests []reconcile.Request) {
381+
httpRoutePolicy, ok := obj.(*v1alpha1.HTTPRoutePolicy)
382+
if !ok {
383+
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to HTTPRoutePolicy")
384+
return nil
385+
}
386+
387+
var keys = make(map[types.NamespacedName]struct{})
388+
for _, ref := range httpRoutePolicy.Spec.TargetRefs {
389+
if ref.Kind != "Ingress" {
390+
continue
391+
}
392+
key := types.NamespacedName{
393+
Namespace: obj.GetNamespace(),
394+
Name: string(ref.Name),
395+
}
396+
if _, ok := keys[key]; ok {
397+
continue
398+
}
399+
400+
var ingress networkingv1.Ingress
401+
if err := r.Get(ctx, key, &ingress); err != nil {
402+
r.Log.Error(err, "failed to get Ingress By HTTPRoutePolicy targetRef", "namespace", key.Namespace, "name", key.Name)
403+
continue
404+
}
405+
keys[key] = struct{}{}
406+
requests = append(requests, reconcile.Request{NamespacedName: key})
407+
}
408+
return
409+
}
410+
411+
func (r *IngressReconciler) listIngressesForGenericEvent(ctx context.Context, obj client.Object) (requests []reconcile.Request) {
412+
var namespacedNameMap = make(map[types.NamespacedName]struct{})
413+
414+
switch v := obj.(type) {
415+
case *v1alpha1.HTTPRoutePolicy:
416+
for _, ref := range v.Spec.TargetRefs {
417+
namespacedName := types.NamespacedName{Namespace: v.GetNamespace(), Name: string(ref.Name)}
418+
if _, ok := namespacedNameMap[namespacedName]; !ok {
419+
namespacedNameMap[namespacedName] = struct{}{}
420+
if err := r.Get(ctx, namespacedName, new(networkingv1.Ingress)); err != nil {
421+
r.Log.Error(err, "failed to Get Ingress", "namespace", namespacedName.Namespace, "name", namespacedName.Name)
422+
continue
423+
}
424+
requests = append(requests, reconcile.Request{NamespacedName: namespacedName})
425+
}
426+
}
427+
default:
428+
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to HTTPRoutePolicy")
429+
}
430+
431+
return
432+
}
433+
344434
// processTLS process the TLS configuration of the ingress
345435
func (r *IngressReconciler) processTLS(tctx *provider.TranslateContext, ingress *networkingv1.Ingress) error {
346436
for _, tls := range ingress.Spec.TLS {

0 commit comments

Comments
 (0)