Skip to content

Commit bcb11a7

Browse files
authored
feat: support backendtrafficpolicy for Ingress (#100)
1 parent ba5c304 commit bcb11a7

File tree

6 files changed

+301
-87
lines changed

6 files changed

+301
-87
lines changed

internal/controller/httproute_controller.go

Lines changed: 2 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -75,49 +75,7 @@ func (r *HTTPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error {
7575
Watches(&v1alpha1.BackendTrafficPolicy{},
7676
handler.EnqueueRequestsFromMapFunc(r.listHTTPRoutesForBackendTrafficPolicy),
7777
builder.WithPredicates(
78-
predicate.Funcs{
79-
GenericFunc: func(e event.GenericEvent) bool {
80-
return false
81-
},
82-
DeleteFunc: func(e event.DeleteEvent) bool {
83-
return true
84-
},
85-
CreateFunc: func(e event.CreateEvent) bool {
86-
return true
87-
},
88-
UpdateFunc: func(e event.UpdateEvent) bool {
89-
oldObj, ok := e.ObjectOld.(*v1alpha1.BackendTrafficPolicy)
90-
newObj, ok2 := e.ObjectNew.(*v1alpha1.BackendTrafficPolicy)
91-
if !ok || !ok2 {
92-
return false
93-
}
94-
oldRefs := oldObj.Spec.TargetRefs
95-
newRefs := newObj.Spec.TargetRefs
96-
97-
oldRefMap := make(map[string]v1alpha1.BackendPolicyTargetReferenceWithSectionName)
98-
for _, ref := range oldRefs {
99-
key := fmt.Sprintf("%s/%s/%s", ref.Group, ref.Kind, ref.Name)
100-
oldRefMap[key] = ref
101-
}
102-
103-
for _, ref := range newRefs {
104-
key := fmt.Sprintf("%s/%s/%s", ref.Group, ref.Kind, ref.Name)
105-
delete(oldRefMap, key)
106-
}
107-
if len(oldRefMap) > 0 {
108-
targetRefs := make([]v1alpha1.BackendPolicyTargetReferenceWithSectionName, 0, len(oldRefs))
109-
for _, ref := range oldRefMap {
110-
targetRefs = append(targetRefs, ref)
111-
}
112-
dump := oldObj.DeepCopy()
113-
dump.Spec.TargetRefs = targetRefs
114-
r.genericEvent <- event.GenericEvent{
115-
Object: dump,
116-
}
117-
}
118-
return true
119-
},
120-
},
78+
BackendTrafficPolicyPredicateFunc(r.genericEvent),
12179
),
12280
).
12381
Watches(&v1alpha1.HTTPRoutePolicy{},
@@ -434,32 +392,7 @@ func (r *HTTPRouteReconciler) listHTTPRouteForGenericEvent(ctx context.Context,
434392

435393
switch v := obj.(type) {
436394
case *v1alpha1.BackendTrafficPolicy:
437-
httprouteAll := []gatewayv1.HTTPRoute{}
438-
for _, ref := range v.Spec.TargetRefs {
439-
httprouteList := &gatewayv1.HTTPRouteList{}
440-
if err := r.List(ctx, httprouteList, client.MatchingFields{
441-
indexer.ServiceIndexRef: indexer.GenIndexKey(v.GetNamespace(), string(ref.Name)),
442-
}); err != nil {
443-
r.Log.Error(err, "failed to list HTTPRoutes for BackendTrafficPolicy", "namespace", v.GetNamespace(), "ref", ref.Name)
444-
return nil
445-
}
446-
httprouteAll = append(httprouteAll, httprouteList.Items...)
447-
}
448-
for _, hr := range httprouteAll {
449-
key := types.NamespacedName{
450-
Namespace: hr.Namespace,
451-
Name: hr.Name,
452-
}
453-
if _, ok := namespacedNameMap[key]; !ok {
454-
namespacedNameMap[key] = struct{}{}
455-
requests = append(requests, reconcile.Request{
456-
NamespacedName: client.ObjectKey{
457-
Namespace: hr.Namespace,
458-
Name: hr.Name,
459-
},
460-
})
461-
}
462-
}
395+
requests = r.listHTTPRoutesForBackendTrafficPolicy(ctx, v)
463396
case *v1alpha1.HTTPRoutePolicy:
464397
for _, ref := range v.Spec.TargetRefs {
465398
namespacedName := types.NamespacedName{Namespace: v.GetNamespace(), Name: string(ref.Name)}

internal/controller/ingress_controller.go

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ import (
1919
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020
"k8s.io/apimachinery/pkg/runtime"
2121
"k8s.io/apimachinery/pkg/types"
22+
"k8s.io/utils/ptr"
2223
ctrl "sigs.k8s.io/controller-runtime"
2324
"sigs.k8s.io/controller-runtime/pkg/builder"
2425
"sigs.k8s.io/controller-runtime/pkg/client"
26+
"sigs.k8s.io/controller-runtime/pkg/event"
2527
"sigs.k8s.io/controller-runtime/pkg/handler"
2628
"sigs.k8s.io/controller-runtime/pkg/predicate"
2729
"sigs.k8s.io/controller-runtime/pkg/reconcile"
30+
"sigs.k8s.io/controller-runtime/pkg/source"
31+
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
2832
)
2933

3034
// IngressReconciler reconciles a Ingress object.
@@ -33,11 +37,14 @@ type IngressReconciler struct { //nolint:revive
3337
Scheme *runtime.Scheme
3438
Log logr.Logger
3539

36-
Provider provider.Provider
40+
Provider provider.Provider
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,18 @@ func (r *IngressReconciler) SetupWithManager(mgr ctrl.Manager) error {
6572
&corev1.Secret{},
6673
handler.EnqueueRequestsFromMapFunc(r.listIngressesBySecret),
6774
).
75+
Watches(&v1alpha1.BackendTrafficPolicy{},
76+
handler.EnqueueRequestsFromMapFunc(r.listIngressForBackendTrafficPolicy),
77+
builder.WithPredicates(
78+
BackendTrafficPolicyPredicateFunc(r.genericEvent),
79+
),
80+
).
81+
WatchesRawSource(
82+
source.Channel(
83+
r.genericEvent,
84+
handler.EnqueueRequestsFromMapFunc(r.listIngressForGenericEvent),
85+
),
86+
).
6887
Complete(r)
6988
}
7089

@@ -103,6 +122,12 @@ func (r *IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
103122
return ctrl.Result{}, err
104123
}
105124

125+
tctx.RouteParentRefs = append(tctx.RouteParentRefs, gatewayv1.ParentReference{
126+
Group: ptr.To(gatewayv1.Group(ingressClass.GroupVersionKind().Group)),
127+
Kind: ptr.To(gatewayv1.Kind("IngressClass")),
128+
Name: gatewayv1.ObjectName(ingressClass.Name),
129+
})
130+
106131
// process IngressClass parameters if they reference GatewayProxy
107132
if err := r.processIngressClassParameters(ctx, tctx, ingress, ingressClass); err != nil {
108133
r.Log.Error(err, "failed to process IngressClass parameters", "ingressClass", ingressClass.Name)
@@ -121,12 +146,17 @@ func (r *IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
121146
return ctrl.Result{}, err
122147
}
123148

149+
ProcessBackendTrafficPolicy(r.Client, r.Log, tctx)
150+
124151
// update the ingress resources
125152
if err := r.Provider.Update(ctx, tctx, ingress); err != nil {
126153
r.Log.Error(err, "failed to update ingress resources", "ingress", ingress.Name)
127154
return ctrl.Result{}, err
128155
}
129156

157+
// update the status of related resources
158+
UpdateStatus(r.Client, r.Log, tctx)
159+
130160
// update the ingress status
131161
if err := r.updateStatus(ctx, tctx, ingress, ingressClass); err != nil {
132162
r.Log.Error(err, "failed to update ingress status", "ingress", ingress.Name)
@@ -341,6 +371,59 @@ func (r *IngressReconciler) listIngressesBySecret(ctx context.Context, obj clien
341371
return requests
342372
}
343373

374+
func (r *IngressReconciler) listIngressForBackendTrafficPolicy(ctx context.Context, obj client.Object) (requests []reconcile.Request) {
375+
v, ok := obj.(*v1alpha1.BackendTrafficPolicy)
376+
if !ok {
377+
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy")
378+
return nil
379+
}
380+
var namespacedNameMap = make(map[types.NamespacedName]struct{})
381+
ingresses := []networkingv1.Ingress{}
382+
for _, ref := range v.Spec.TargetRefs {
383+
service := &corev1.Service{}
384+
if err := r.Get(ctx, client.ObjectKey{
385+
Namespace: v.Namespace,
386+
Name: string(ref.Name),
387+
}, service); err != nil {
388+
if client.IgnoreNotFound(err) != nil {
389+
r.Log.Error(err, "failed to get service", "namespace", v.Namespace, "name", ref.Name)
390+
}
391+
continue
392+
}
393+
ingressList := &networkingv1.IngressList{}
394+
if err := r.List(ctx, ingressList, client.MatchingFields{
395+
indexer.ServiceIndexRef: indexer.GenIndexKey(v.GetNamespace(), string(ref.Name)),
396+
}); err != nil {
397+
r.Log.Error(err, "failed to list HTTPRoutes for BackendTrafficPolicy", "namespace", v.GetNamespace(), "ref", ref.Name)
398+
return nil
399+
}
400+
ingresses = append(ingresses, ingressList.Items...)
401+
}
402+
for _, ins := range ingresses {
403+
key := types.NamespacedName{
404+
Namespace: ins.Namespace,
405+
Name: ins.Name,
406+
}
407+
if _, ok := namespacedNameMap[key]; !ok {
408+
namespacedNameMap[key] = struct{}{}
409+
requests = append(requests, reconcile.Request{
410+
NamespacedName: key,
411+
})
412+
}
413+
}
414+
return requests
415+
}
416+
417+
func (r *IngressReconciler) listIngressForGenericEvent(ctx context.Context, obj client.Object) (requests []reconcile.Request) {
418+
switch v := obj.(type) {
419+
case *v1alpha1.BackendTrafficPolicy:
420+
requests = r.listIngressForBackendTrafficPolicy(ctx, v)
421+
default:
422+
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy")
423+
}
424+
return requests
425+
}
426+
344427
// processTLS process the TLS configuration of the ingress
345428
func (r *IngressReconciler) processTLS(tctx *provider.TranslateContext, ingress *networkingv1.Ingress) error {
346429
for _, tls := range ingress.Spec.TLS {

internal/controller/policies.go

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"k8s.io/apimachinery/pkg/runtime/schema"
1515
"k8s.io/apimachinery/pkg/types"
1616
"sigs.k8s.io/controller-runtime/pkg/client"
17+
"sigs.k8s.io/controller-runtime/pkg/event"
18+
"sigs.k8s.io/controller-runtime/pkg/predicate"
1719

1820
"github.com/api7/api7-ingress-controller/api/v1alpha1"
1921
"github.com/api7/api7-ingress-controller/internal/controller/config"
@@ -30,6 +32,52 @@ func (p PolicyTargetKey) String() string {
3032
return p.NsName.String() + "/" + p.GroupKind.String()
3133
}
3234

35+
func BackendTrafficPolicyPredicateFunc(channel chan event.GenericEvent) predicate.Predicate {
36+
return predicate.Funcs{
37+
GenericFunc: func(e event.GenericEvent) bool {
38+
return false
39+
},
40+
DeleteFunc: func(e event.DeleteEvent) bool {
41+
return true
42+
},
43+
CreateFunc: func(e event.CreateEvent) bool {
44+
return true
45+
},
46+
UpdateFunc: func(e event.UpdateEvent) bool {
47+
oldObj, ok := e.ObjectOld.(*v1alpha1.BackendTrafficPolicy)
48+
newObj, ok2 := e.ObjectNew.(*v1alpha1.BackendTrafficPolicy)
49+
if !ok || !ok2 {
50+
return false
51+
}
52+
oldRefs := oldObj.Spec.TargetRefs
53+
newRefs := newObj.Spec.TargetRefs
54+
55+
oldRefMap := make(map[string]v1alpha1.BackendPolicyTargetReferenceWithSectionName)
56+
for _, ref := range oldRefs {
57+
key := fmt.Sprintf("%s/%s/%s", ref.Group, ref.Kind, ref.Name)
58+
oldRefMap[key] = ref
59+
}
60+
61+
for _, ref := range newRefs {
62+
key := fmt.Sprintf("%s/%s/%s", ref.Group, ref.Kind, ref.Name)
63+
delete(oldRefMap, key)
64+
}
65+
if len(oldRefMap) > 0 {
66+
targetRefs := make([]v1alpha1.BackendPolicyTargetReferenceWithSectionName, 0, len(oldRefs))
67+
for _, ref := range oldRefMap {
68+
targetRefs = append(targetRefs, ref)
69+
}
70+
dump := oldObj.DeepCopy()
71+
dump.Spec.TargetRefs = targetRefs
72+
channel <- event.GenericEvent{
73+
Object: dump,
74+
}
75+
}
76+
return true
77+
},
78+
}
79+
}
80+
3381
func ProcessBackendTrafficPolicy(
3482
c client.Client,
3583
log logr.Logger,
@@ -131,10 +179,7 @@ func SetAncestorStatus(status *v1alpha1.PolicyStatus, ancestorStatus gatewayv1al
131179
}
132180
condition := ancestorStatus.Conditions[0]
133181
for _, c := range status.Ancestors {
134-
if c.AncestorRef.Name == ancestorStatus.AncestorRef.Name &&
135-
ptr.Equal(c.AncestorRef.Namespace, ancestorStatus.AncestorRef.Namespace) &&
136-
ptr.Equal(c.AncestorRef.Group, ancestorStatus.AncestorRef.Group) &&
137-
ptr.Equal(c.AncestorRef.Kind, ancestorStatus.AncestorRef.Kind) &&
182+
if parentRefValueEqual(ancestorStatus.AncestorRef, c.AncestorRef) &&
138183
c.ControllerName == ancestorStatus.ControllerName {
139184
if !VerifyConditions(&c.Conditions, condition) {
140185
return false

internal/provider/adc/translator/ingress.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ import (
44
"fmt"
55
"strings"
66

7-
adctypes "github.com/api7/api7-ingress-controller/api/adc"
8-
"github.com/api7/api7-ingress-controller/internal/controller/label"
9-
"github.com/api7/api7-ingress-controller/internal/id"
10-
"github.com/api7/api7-ingress-controller/internal/provider"
117
corev1 "k8s.io/api/core/v1"
128
discoveryv1 "k8s.io/api/discovery/v1"
139
networkingv1 "k8s.io/api/networking/v1"
1410
"k8s.io/apimachinery/pkg/types"
11+
12+
adctypes "github.com/api7/api7-ingress-controller/api/adc"
13+
"github.com/api7/api7-ingress-controller/internal/controller/label"
14+
"github.com/api7/api7-ingress-controller/internal/id"
15+
"github.com/api7/api7-ingress-controller/internal/provider"
1516
)
1617

1718
func (t *Translator) translateIngressTLS(ingressTLS *networkingv1.IngressTLS, secret *corev1.Secret, labels map[string]string) (*adctypes.SSL, error) {
@@ -104,12 +105,15 @@ func (t *Translator) TranslateIngress(tctx *provider.TranslateContext, obj *netw
104105

105106
// get the EndpointSlice of the backend service
106107
backendService := path.Backend.Service
107-
endpointSlices := tctx.EndpointSlices[types.NamespacedName{
108-
Namespace: obj.Namespace,
109-
Name: backendService.Name,
110-
}]
111-
112-
t.attachBackendTrafficPolicyToUpstream(nil, upstream)
108+
var endpointSlices []discoveryv1.EndpointSlice
109+
if backendService != nil {
110+
endpointSlices = tctx.EndpointSlices[types.NamespacedName{
111+
Namespace: obj.Namespace,
112+
Name: backendService.Name,
113+
}]
114+
backendRef := convertBackendRef(obj.Namespace, backendService.Name, "Service")
115+
t.AttachBackendTrafficPolicyToUpstream(backendRef, tctx.BackendTrafficPolicies, upstream)
116+
}
113117

114118
// get the service port configuration
115119
var servicePort int32 = 0

internal/provider/adc/translator/policies.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,31 @@ import (
44
"github.com/api7/api7-ingress-controller/api/adc"
55
"github.com/api7/api7-ingress-controller/api/v1alpha1"
66
"k8s.io/apimachinery/pkg/types"
7+
"k8s.io/utils/ptr"
78
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
89

910
adctypes "github.com/api7/api7-ingress-controller/api/adc"
1011
)
1112

13+
func convertBackendRef(namespace, name, kind string) gatewayv1.BackendRef {
14+
backendRef := gatewayv1.BackendRef{}
15+
backendRef.Name = gatewayv1.ObjectName(name)
16+
backendRef.Namespace = ptr.To(gatewayv1.Namespace(namespace))
17+
backendRef.Kind = ptr.To(gatewayv1.Kind(kind))
18+
return backendRef
19+
}
20+
1221
func (t *Translator) AttachBackendTrafficPolicyToUpstream(ref gatewayv1.BackendRef, policies map[types.NamespacedName]*v1alpha1.BackendTrafficPolicy, upstream *adctypes.Upstream) {
1322
if len(policies) == 0 {
1423
return
1524
}
1625
var policy *v1alpha1.BackendTrafficPolicy
1726
for _, po := range policies {
27+
if ref.Namespace != nil && string(*ref.Namespace) != po.Namespace {
28+
continue
29+
}
1830
for _, targetRef := range po.Spec.TargetRefs {
19-
if ref.Name == targetRef.Name &&
20-
(ref.Namespace != nil && string(*ref.Namespace) == po.Namespace) {
31+
if ref.Name == targetRef.Name {
2132
policy = po
2233
break
2334
}

0 commit comments

Comments
 (0)