Skip to content

Commit 11d4805

Browse files
authored
feat: Update HTTPRoutePolicy handling for Ingress (#99)
1 parent bcb11a7 commit 11d4805

File tree

7 files changed

+393
-86
lines changed

7 files changed

+393
-86
lines changed

internal/controller/httproute_controller.go

Lines changed: 44 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,7 @@ func (r *HTTPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error {
8080
).
8181
Watches(&v1alpha1.HTTPRoutePolicy{},
8282
handler.EnqueueRequestsFromMapFunc(r.listHTTPRouteByHTTPRoutePolicy),
83-
builder.WithPredicates(
84-
predicate.Funcs{
85-
CreateFunc: func(e event.CreateEvent) bool {
86-
return true
87-
},
88-
DeleteFunc: func(e event.DeleteEvent) bool {
89-
return true
90-
},
91-
UpdateFunc: r.httpRoutePolicyPredicateOnUpdate,
92-
GenericFunc: func(e event.GenericEvent) bool {
93-
return false
94-
},
95-
},
96-
),
83+
builder.WithPredicates(httpRoutePolicyPredicateFuncs(r.genericEvent)),
9784
).
9885
WatchesRawSource(
9986
source.Channel(
@@ -358,7 +345,7 @@ func (r *HTTPRouteReconciler) listHTTPRouteByHTTPRoutePolicy(ctx context.Context
358345
}
359346

360347
var httpRoute gatewayv1.HTTPRoute
361-
if err := r.Get(ctx, client.ObjectKey{Namespace: key.Namespace, Name: key.Name}, &httpRoute); err != nil {
348+
if err := r.Get(ctx, key, &httpRoute); err != nil {
362349
r.Log.Error(err, "failed to get HTTPRoute by HTTPRoutePolicy targetRef", "namespace", key.Namespace, "name", key.Name)
363350
continue
364351
}
@@ -376,39 +363,22 @@ func (r *HTTPRouteReconciler) listHTTPRouteByHTTPRoutePolicy(ctx context.Context
376363
}
377364
}
378365
keys[key] = struct{}{}
379-
requests = append(requests, reconcile.Request{
380-
NamespacedName: types.NamespacedName{
381-
Namespace: key.Namespace,
382-
Name: key.Name,
383-
},
384-
})
366+
requests = append(requests, reconcile.Request{NamespacedName: key})
385367
}
386368

387369
return requests
388370
}
389371

390372
func (r *HTTPRouteReconciler) listHTTPRouteForGenericEvent(ctx context.Context, obj client.Object) (requests []reconcile.Request) {
391-
var namespacedNameMap = make(map[types.NamespacedName]struct{})
392-
393-
switch v := obj.(type) {
373+
switch obj.(type) {
394374
case *v1alpha1.BackendTrafficPolicy:
395-
requests = r.listHTTPRoutesForBackendTrafficPolicy(ctx, v)
375+
return r.listHTTPRoutesForBackendTrafficPolicy(ctx, obj)
396376
case *v1alpha1.HTTPRoutePolicy:
397-
for _, ref := range v.Spec.TargetRefs {
398-
namespacedName := types.NamespacedName{Namespace: v.GetNamespace(), Name: string(ref.Name)}
399-
if _, ok := namespacedNameMap[namespacedName]; !ok {
400-
namespacedNameMap[namespacedName] = struct{}{}
401-
if err := r.Get(ctx, namespacedName, new(gatewayv1.HTTPRoute)); err != nil {
402-
r.Log.Info("failed to Get HTTPRoute", "namespace", namespacedName.Namespace, "name", namespacedName.Name)
403-
continue
404-
}
405-
requests = append(requests, reconcile.Request{NamespacedName: namespacedName})
406-
}
407-
}
377+
return r.listHTTPRouteByHTTPRoutePolicy(ctx, obj)
408378
default:
409-
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy")
379+
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy or HTTPRoutePolicy")
380+
return nil
410381
}
411-
return requests
412382
}
413383

414384
func (r *HTTPRouteReconciler) processHTTPRouteBackendRefs(tctx *provider.TranslateContext) error {
@@ -528,28 +498,41 @@ func (r *HTTPRouteReconciler) processHTTPRoute(tctx *provider.TranslateContext,
528498
return terror
529499
}
530500

531-
func (r *HTTPRouteReconciler) httpRoutePolicyPredicateOnUpdate(e event.UpdateEvent) bool {
532-
oldPolicy, ok0 := e.ObjectOld.(*v1alpha1.HTTPRoutePolicy)
533-
newPolicy, ok1 := e.ObjectNew.(*v1alpha1.HTTPRoutePolicy)
534-
if !ok0 || !ok1 {
535-
return false
536-
}
537-
var discardsRefs = make(map[string]v1alpha2.LocalPolicyTargetReferenceWithSectionName)
538-
for _, ref := range oldPolicy.Spec.TargetRefs {
539-
key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "")
540-
discardsRefs[key] = ref
541-
}
542-
for _, ref := range newPolicy.Spec.TargetRefs {
543-
key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "")
544-
delete(discardsRefs, key)
545-
}
546-
if len(discardsRefs) > 0 {
547-
dump := oldPolicy.DeepCopy()
548-
dump.Spec.TargetRefs = make([]v1alpha2.LocalPolicyTargetReferenceWithSectionName, 0, len(discardsRefs))
549-
for _, ref := range discardsRefs {
550-
dump.Spec.TargetRefs = append(dump.Spec.TargetRefs, ref)
551-
}
552-
r.genericEvent <- event.GenericEvent{Object: dump}
501+
func httpRoutePolicyPredicateFuncs(channel chan event.GenericEvent) predicate.Predicate {
502+
return predicate.Funcs{
503+
CreateFunc: func(e event.CreateEvent) bool {
504+
return true
505+
},
506+
DeleteFunc: func(e event.DeleteEvent) bool {
507+
return true
508+
},
509+
UpdateFunc: func(e event.UpdateEvent) bool {
510+
oldPolicy, ok0 := e.ObjectOld.(*v1alpha1.HTTPRoutePolicy)
511+
newPolicy, ok1 := e.ObjectNew.(*v1alpha1.HTTPRoutePolicy)
512+
if !ok0 || !ok1 {
513+
return false
514+
}
515+
var discardsRefs = make(map[string]v1alpha2.LocalPolicyTargetReferenceWithSectionName)
516+
for _, ref := range oldPolicy.Spec.TargetRefs {
517+
key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "")
518+
discardsRefs[key] = ref
519+
}
520+
for _, ref := range newPolicy.Spec.TargetRefs {
521+
key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "")
522+
delete(discardsRefs, key)
523+
}
524+
if len(discardsRefs) > 0 {
525+
dump := oldPolicy.DeepCopy()
526+
dump.Spec.TargetRefs = make([]v1alpha2.LocalPolicyTargetReferenceWithSectionName, 0, len(discardsRefs))
527+
for _, ref := range discardsRefs {
528+
dump.Spec.TargetRefs = append(dump.Spec.TargetRefs, ref)
529+
}
530+
channel <- event.GenericEvent{Object: dump}
531+
}
532+
return true
533+
},
534+
GenericFunc: func(e event.GenericEvent) bool {
535+
return false
536+
},
553537
}
554-
return true
555538
}

internal/controller/httproutepolicy.go

Lines changed: 53 additions & 10 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(), "")
@@ -88,15 +89,57 @@ func (r *HTTPRouteReconciler) processHTTPRoutePolicies(tctx *provider.TranslateC
8889
for _, policies := range checker.policies {
8990
for i := range policies {
9091
policy := policies[i]
91-
r.modifyHTTPRoutePolicyStatus(httpRoute, &policy, status, reason, message)
92+
modifyHTTPRoutePolicyStatus(httpRoute.Spec.ParentRefs, &policy, status, reason, message)
9293
tctx.StatusUpdaters = append(tctx.StatusUpdaters, &policy)
9394
}
9495
}
9596

9697
return nil
9798
}
9899

99-
func (r *HTTPRouteReconciler) modifyHTTPRoutePolicyStatus(httpRoute *gatewayv1.HTTPRoute, policy *v1alpha1.HTTPRoutePolicy, status bool, reason, message string) {
100+
func (r *IngressReconciler) processHTTPRoutePolicies(tctx *provider.TranslateContext, ingress *networkingv1.Ingress) error {
101+
var (
102+
checker = conflictChecker{
103+
object: ingress,
104+
policies: make(map[targetRefKey][]v1alpha1.HTTPRoutePolicy),
105+
conflict: false,
106+
}
107+
list v1alpha1.HTTPRoutePolicyList
108+
key = indexer.GenHTTPRoutePolicyIndexKey(networkingv1.GroupName, "Ingress", ingress.GetNamespace(), ingress.GetName(), "")
109+
)
110+
if err := r.List(context.Background(), &list, client.MatchingFields{indexer.PolicyTargetRefs: key}); err != nil {
111+
return err
112+
}
113+
114+
for _, item := range list.Items {
115+
checker.append("", item)
116+
tctx.HTTPRoutePolicies["*"] = append(tctx.HTTPRoutePolicies["*"], item)
117+
}
118+
119+
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)
127+
message = "HTTPRoutePolicy conflict with others target to the Ingress"
128+
129+
// clear HTTPRoutePolicies from TranslateContext
130+
tctx.HTTPRoutePolicies = make(map[string][]v1alpha1.HTTPRoutePolicy)
131+
}
132+
133+
for i := range list.Items {
134+
policy := list.Items[i]
135+
modifyHTTPRoutePolicyStatus(tctx.RouteParentRefs, &policy, status, reason, message)
136+
tctx.StatusUpdaters = append(tctx.StatusUpdaters, &policy)
137+
}
138+
139+
return nil
140+
}
141+
142+
func modifyHTTPRoutePolicyStatus(parentRefs []gatewayv1.ParentReference, policy *v1alpha1.HTTPRoutePolicy, status bool, reason, message string) {
100143
condition := metav1.Condition{
101144
Type: string(v1alpha2.PolicyConditionAccepted),
102145
Status: metav1.ConditionTrue,
@@ -108,13 +151,13 @@ func (r *HTTPRouteReconciler) modifyHTTPRoutePolicyStatus(httpRoute *gatewayv1.H
108151
if !status {
109152
condition.Status = metav1.ConditionFalse
110153
}
111-
_ = SetAncestors(&policy.Status, httpRoute.Spec.ParentRefs, condition)
154+
_ = SetAncestors(&policy.Status, parentRefs, condition)
112155
}
113156

114157
type conflictChecker struct {
115-
httpRoute *gatewayv1.HTTPRoute
116-
policies map[targetRefKey][]v1alpha1.HTTPRoutePolicy
117-
conflict bool
158+
object client.Object
159+
policies map[targetRefKey][]v1alpha1.HTTPRoutePolicy
160+
conflict bool
118161
}
119162

120163
type targetRefKey struct {
@@ -127,8 +170,8 @@ type targetRefKey struct {
127170
func (c *conflictChecker) append(sectionName string, policy v1alpha1.HTTPRoutePolicy) {
128171
key := targetRefKey{
129172
Group: gatewayv1.GroupName,
130-
Namespace: gatewayv1.Namespace(c.httpRoute.GetNamespace()),
131-
Name: gatewayv1.ObjectName(c.httpRoute.GetName()),
173+
Namespace: gatewayv1.Namespace(c.object.GetNamespace()),
174+
Name: gatewayv1.ObjectName(c.object.GetName()),
132175
SectionName: gatewayv1.SectionName(sectionName),
133176
}
134177
c.policies[key] = append(c.policies[key], policy)

internal/controller/ingress_controller.go

Lines changed: 52 additions & 8 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"
@@ -29,6 +24,12 @@ import (
2924
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3025
"sigs.k8s.io/controller-runtime/pkg/source"
3126
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
27+
28+
"github.com/api7/api7-ingress-controller/api/v1alpha1"
29+
"github.com/api7/api7-ingress-controller/internal/controller/config"
30+
"github.com/api7/api7-ingress-controller/internal/controller/indexer"
31+
"github.com/api7/api7-ingress-controller/internal/provider"
32+
"github.com/api7/gopkg/pkg/log"
3233
)
3334

3435
// IngressReconciler reconciles a Ingress object.
@@ -78,6 +79,10 @@ func (r *IngressReconciler) SetupWithManager(mgr ctrl.Manager) error {
7879
BackendTrafficPolicyPredicateFunc(r.genericEvent),
7980
),
8081
).
82+
Watches(&v1alpha1.HTTPRoutePolicy{},
83+
handler.EnqueueRequestsFromMapFunc(r.listIngressesByHTTPRoutePolicy),
84+
builder.WithPredicates(httpRoutePolicyPredicateFuncs(r.genericEvent)),
85+
).
8186
WatchesRawSource(
8287
source.Channel(
8388
r.genericEvent,
@@ -146,6 +151,12 @@ func (r *IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
146151
return ctrl.Result{}, err
147152
}
148153

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+
149160
ProcessBackendTrafficPolicy(r.Client, r.Log, tctx)
150161

151162
// update the ingress resources
@@ -415,13 +426,46 @@ func (r *IngressReconciler) listIngressForBackendTrafficPolicy(ctx context.Conte
415426
}
416427

417428
func (r *IngressReconciler) listIngressForGenericEvent(ctx context.Context, obj client.Object) (requests []reconcile.Request) {
418-
switch v := obj.(type) {
429+
switch obj.(type) {
419430
case *v1alpha1.BackendTrafficPolicy:
420-
requests = r.listIngressForBackendTrafficPolicy(ctx, v)
431+
return r.listIngressForBackendTrafficPolicy(ctx, obj)
432+
case *v1alpha1.HTTPRoutePolicy:
433+
return r.listIngressesByHTTPRoutePolicy(ctx, obj)
421434
default:
422435
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy")
436+
return nil
423437
}
424-
return requests
438+
}
439+
440+
func (r *IngressReconciler) listIngressesByHTTPRoutePolicy(ctx context.Context, obj client.Object) (requests []reconcile.Request) {
441+
httpRoutePolicy, ok := obj.(*v1alpha1.HTTPRoutePolicy)
442+
if !ok {
443+
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to HTTPRoutePolicy")
444+
return nil
445+
}
446+
447+
var keys = make(map[types.NamespacedName]struct{})
448+
for _, ref := range httpRoutePolicy.Spec.TargetRefs {
449+
if ref.Kind != "Ingress" {
450+
continue
451+
}
452+
key := types.NamespacedName{
453+
Namespace: obj.GetNamespace(),
454+
Name: string(ref.Name),
455+
}
456+
if _, ok := keys[key]; ok {
457+
continue
458+
}
459+
460+
var ingress networkingv1.Ingress
461+
if err := r.Get(ctx, key, &ingress); err != nil {
462+
r.Log.Error(err, "failed to get Ingress By HTTPRoutePolicy targetRef", "namespace", key.Namespace, "name", key.Name)
463+
continue
464+
}
465+
keys[key] = struct{}{}
466+
requests = append(requests, reconcile.Request{NamespacedName: key})
467+
}
468+
return
425469
}
426470

427471
// processTLS process the TLS configuration of the ingress

internal/provider/adc/translator/httproute.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"k8s.io/utils/ptr"
1313
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
1414

15+
"github.com/api7/api7-ingress-controller/api/v1alpha1"
1516
"github.com/api7/gopkg/pkg/log"
1617

1718
adctypes "github.com/api7/api7-ingress-controller/api/adc"
@@ -231,10 +232,22 @@ func (t *Translator) fillPluginFromHTTPRequestRedirectFilter(plugins adctypes.Pl
231232
plugin.URI = uri
232233
}
233234

234-
func (t *Translator) fillHTTPRoutePolicies(tctx *provider.TranslateContext, rule gatewayv1.HTTPRouteRule, routes []*adctypes.Route) {
235-
policies := tctx.HTTPRoutePolicies["*"] // policies which not specify a sectionName
235+
func (t *Translator) fillHTTPRoutePoliciesForHTTPRoute(tctx *provider.TranslateContext, routes []*adctypes.Route, rule gatewayv1.HTTPRouteRule) {
236+
var keys = []string{"*"}
236237
if rule.Name != nil {
237-
policies = append(policies, tctx.HTTPRoutePolicies[string(*rule.Name)]...) // append policies which specify the sectionName as the same as rule.name
238+
keys = append(keys, string(*rule.Name))
239+
}
240+
t.fillHTTPRoutePolicies(tctx, routes, keys...)
241+
}
242+
243+
func (t *Translator) fillHTTPRoutePoliciesForIngress(tctx *provider.TranslateContext, routes []*adctypes.Route) {
244+
t.fillHTTPRoutePolicies(tctx, routes, "*")
245+
}
246+
247+
func (t *Translator) fillHTTPRoutePolicies(tctx *provider.TranslateContext, routes []*adctypes.Route, ctxKeys ...string) {
248+
var policies []v1alpha1.HTTPRoutePolicy
249+
for _, key := range ctxKeys {
250+
policies = append(policies, tctx.HTTPRoutePolicies[key]...)
238251
}
239252

240253
for _, policy := range policies {
@@ -352,7 +365,7 @@ func (t *Translator) TranslateHTTPRoute(tctx *provider.TranslateContext, httpRou
352365
route.EnableWebsocket = ptr.To(true)
353366
routes = append(routes, route)
354367
}
355-
t.fillHTTPRoutePolicies(tctx, rule, routes)
368+
t.fillHTTPRoutePoliciesForHTTPRoute(tctx, routes, rule)
356369
service.Routes = routes
357370

358371
result.Services = append(result.Services, service)

0 commit comments

Comments
 (0)