Skip to content

Commit 92c1519

Browse files
authored
feat: support backendtrafficpolicy for httproute (#97)
1 parent c6f9a74 commit 92c1519

File tree

14 files changed

+462
-130
lines changed

14 files changed

+462
-130
lines changed

api/adc/types.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,9 @@ type Route struct {
126126
}
127127

128128
type Timeout struct {
129-
Connect float64 `json:"connect"`
130-
Read float64 `json:"read"`
131-
Send float64 `json:"send"`
129+
Connect int `json:"connect"`
130+
Read int `json:"read"`
131+
Send int `json:"send"`
132132
}
133133

134134
type StreamRoute struct {
@@ -149,7 +149,7 @@ type Upstream struct {
149149
HashOn string `json:"hash_on,omitempty" yaml:"hash_on,omitempty"`
150150
Key string `json:"key,omitempty" yaml:"key,omitempty"`
151151
Nodes UpstreamNodes `json:"nodes" yaml:"nodes"`
152-
PassHost *PassHost `json:"pass_host,omitempty" yaml:"pass_host,omitempty"`
152+
PassHost string `json:"pass_host,omitempty" yaml:"pass_host,omitempty"`
153153
Retries *int64 `json:"retries,omitempty" yaml:"retries,omitempty"`
154154
RetryTimeout *float64 `json:"retry_timeout,omitempty" yaml:"retry_timeout,omitempty"`
155155
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
@@ -202,14 +202,6 @@ const (
202202
Trace Method = "TRACE"
203203
)
204204

205-
type PassHost string
206-
207-
const (
208-
Node PassHost = "node"
209-
Pass PassHost = "pass"
210-
Rewrite PassHost = "rewrite"
211-
)
212-
213205
type Scheme string
214206

215207
const (

api/v1alpha1/backendtrafficpolicy_types.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ type BackendTrafficPolicySpec struct {
4444
//
4545
// +kubebuilder:validation:Enum=pass;node;rewrite;
4646
// +kubebuilder:default=pass
47-
PassHost string `json:"pass_host,omitempty" yaml:"pass_host,omitempty"`
47+
PassHost string `json:"passHost,omitempty" yaml:"passHost,omitempty"`
4848

4949
// Specifies the host of the Upstream request. This is only valid if
50-
// the pass_host is set to rewrite
51-
Host Hostname `json:"upstream_host,omitempty" yaml:"upstream_host,omitempty"`
50+
// the passHost is set to rewrite
51+
Host Hostname `json:"upstreamHost,omitempty" yaml:"upstreamHost,omitempty"`
5252
}
5353

5454
// LoadBalancer describes the load balancing parameters.
@@ -69,10 +69,16 @@ type LoadBalancer struct {
6969

7070
type Timeout struct {
7171
// +kubebuilder:default="60s"
72+
// +kubebuilder:validation:Pattern=`^[0-9]+s$`
73+
// +kubebuilder:validation:Type=string
7274
Connect metav1.Duration `json:"connect,omitempty" yaml:"connect,omitempty"`
7375
// +kubebuilder:default="60s"
76+
// +kubebuilder:validation:Pattern=`^[0-9]+s$`
77+
// +kubebuilder:validation:Type=string
7478
Send metav1.Duration `json:"send,omitempty" yaml:"send,omitempty"`
7579
// +kubebuilder:default="60s"
80+
// +kubebuilder:validation:Pattern=`^[0-9]+s$`
81+
// +kubebuilder:validation:Type=string
7682
Read metav1.Duration `json:"read,omitempty" yaml:"read,omitempty"`
7783
}
7884

config/crd/bases/gateway.apisix.io_backendtrafficpolicies.yaml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ spec:
7070
type: object
7171
x-kubernetes-validations:
7272
- rule: '!(has(self.key) && self.type != ''chash'')'
73-
pass_host:
73+
passHost:
7474
default: pass
7575
description: |-
7676
Configures the host when the request is forwarded to the upstream.
@@ -164,18 +164,21 @@ spec:
164164
properties:
165165
connect:
166166
default: 60s
167+
pattern: ^[0-9]+s$
167168
type: string
168169
read:
169170
default: 60s
171+
pattern: ^[0-9]+s$
170172
type: string
171173
send:
172174
default: 60s
175+
pattern: ^[0-9]+s$
173176
type: string
174177
type: object
175-
upstream_host:
178+
upstreamHost:
176179
description: |-
177180
Specifies the host of the Upstream request. This is only valid if
178-
the pass_host is set to rewrite
181+
the passHost is set to rewrite
179182
maxLength: 253
180183
minLength: 1
181184
pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$

internal/controller/gateway_controller.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
7575
if err := r.Provider.Delete(ctx, gateway); err != nil {
7676
return ctrl.Result{}, err
7777
}
78+
return ctrl.Result{}, nil
7879
}
7980
return ctrl.Result{}, err
8081
}
@@ -234,6 +235,9 @@ func (r *GatewayReconciler) listGatewaysForGatewayProxy(ctx context.Context, obj
234235

235236
recs := make([]reconcile.Request, 0, len(gatewayList.Items))
236237
for _, gateway := range gatewayList.Items {
238+
if !r.checkGatewayClass(&gateway) {
239+
continue
240+
}
237241
recs = append(recs, reconcile.Request{
238242
NamespacedName: client.ObjectKey{
239243
Namespace: gateway.GetNamespace(),
@@ -244,7 +248,7 @@ func (r *GatewayReconciler) listGatewaysForGatewayProxy(ctx context.Context, obj
244248
return recs
245249
}
246250

247-
func (r *GatewayReconciler) listGatewaysForHTTPRoute(_ context.Context, obj client.Object) []reconcile.Request {
251+
func (r *GatewayReconciler) listGatewaysForHTTPRoute(ctx context.Context, obj client.Object) []reconcile.Request {
248252
httpRoute, ok := obj.(*gatewayv1.HTTPRoute)
249253
if !ok {
250254
r.Log.Error(
@@ -268,6 +272,18 @@ func (r *GatewayReconciler) listGatewaysForHTTPRoute(_ context.Context, obj clie
268272
gatewayNamespace = string(*parentRef.Namespace)
269273
}
270274

275+
gateway := new(gatewayv1.Gateway)
276+
if err := r.Get(ctx, client.ObjectKey{
277+
Namespace: gatewayNamespace,
278+
Name: string(parentRef.Name),
279+
}, gateway); err != nil {
280+
continue
281+
}
282+
283+
if !r.checkGatewayClass(gateway) {
284+
continue
285+
}
286+
271287
recs = append(recs, reconcile.Request{
272288
NamespacedName: client.ObjectKey{
273289
Namespace: gatewayNamespace,

internal/controller/httproute_controller.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"sigs.k8s.io/controller-runtime/pkg/handler"
1919
"sigs.k8s.io/controller-runtime/pkg/predicate"
2020
"sigs.k8s.io/controller-runtime/pkg/reconcile"
21+
"sigs.k8s.io/controller-runtime/pkg/source"
2122
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
2223

2324
"github.com/api7/api7-ingress-controller/api/v1alpha1"
@@ -33,10 +34,14 @@ type HTTPRouteReconciler struct { //nolint:revive
3334
Log logr.Logger
3435

3536
Provider provider.Provider
37+
38+
genericEvent chan event.GenericEvent
3639
}
3740

3841
// SetupWithManager sets up the controller with the Manager.
3942
func (r *HTTPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error {
43+
r.genericEvent = make(chan event.GenericEvent, 100)
44+
4045
return ctrl.NewControllerManagedBy(mgr).
4146
For(&gatewayv1.HTTPRoute{}).
4247
WithEventFilter(predicate.GenerationChangedPredicate{}).
@@ -65,9 +70,100 @@ func (r *HTTPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error {
6570
},
6671
),
6772
).
73+
Watches(&v1alpha1.BackendTrafficPolicy{},
74+
handler.EnqueueRequestsFromMapFunc(r.listHTTPRoutesForBackendTrafficPolicy),
75+
builder.WithPredicates(
76+
predicate.Funcs{
77+
GenericFunc: func(e event.GenericEvent) bool {
78+
return false
79+
},
80+
DeleteFunc: func(e event.DeleteEvent) bool {
81+
return true
82+
},
83+
CreateFunc: func(e event.CreateEvent) bool {
84+
return true
85+
},
86+
UpdateFunc: func(e event.UpdateEvent) bool {
87+
oldObj, ok := e.ObjectOld.(*v1alpha1.BackendTrafficPolicy)
88+
newObj, ok2 := e.ObjectNew.(*v1alpha1.BackendTrafficPolicy)
89+
if !ok || !ok2 {
90+
return false
91+
}
92+
oldRefs := oldObj.Spec.TargetRefs
93+
newRefs := newObj.Spec.TargetRefs
94+
95+
oldRefMap := make(map[string]v1alpha1.BackendPolicyTargetReferenceWithSectionName)
96+
for _, ref := range oldRefs {
97+
key := fmt.Sprintf("%s/%s/%s", ref.Group, ref.Kind, ref.Name)
98+
oldRefMap[key] = ref
99+
}
100+
101+
for _, ref := range newRefs {
102+
key := fmt.Sprintf("%s/%s/%s", ref.Group, ref.Kind, ref.Name)
103+
delete(oldRefMap, key)
104+
}
105+
if len(oldRefMap) > 0 {
106+
targetRefs := make([]v1alpha1.BackendPolicyTargetReferenceWithSectionName, 0, len(oldRefs))
107+
for _, ref := range oldRefMap {
108+
targetRefs = append(targetRefs, ref)
109+
}
110+
dump := oldObj.DeepCopy()
111+
dump.Spec.TargetRefs = targetRefs
112+
r.genericEvent <- event.GenericEvent{
113+
Object: dump,
114+
}
115+
}
116+
return true
117+
},
118+
},
119+
),
120+
).
121+
WatchesRawSource(
122+
source.Channel(
123+
r.genericEvent,
124+
handler.EnqueueRequestsFromMapFunc(r.listHTTPRouteForGenericEvent),
125+
),
126+
).
68127
Complete(r)
69128
}
70129

130+
func (r *HTTPRouteReconciler) listHTTPRouteForGenericEvent(ctx context.Context, obj client.Object) []reconcile.Request {
131+
var namespacedNameMap = make(map[types.NamespacedName]struct{})
132+
requests := []reconcile.Request{}
133+
switch v := obj.(type) {
134+
case *v1alpha1.BackendTrafficPolicy:
135+
httprouteAll := []gatewayv1.HTTPRoute{}
136+
for _, ref := range v.Spec.TargetRefs {
137+
httprouteList := &gatewayv1.HTTPRouteList{}
138+
if err := r.List(ctx, httprouteList, client.MatchingFields{
139+
indexer.ServiceIndexRef: indexer.GenIndexKey(v.GetNamespace(), string(ref.Name)),
140+
}); err != nil {
141+
r.Log.Error(err, "failed to list HTTPRoutes for BackendTrafficPolicy", "namespace", v.GetNamespace(), "ref", ref.Name)
142+
return nil
143+
}
144+
httprouteAll = append(httprouteAll, httprouteList.Items...)
145+
}
146+
for _, hr := range httprouteAll {
147+
key := types.NamespacedName{
148+
Namespace: hr.Namespace,
149+
Name: hr.Name,
150+
}
151+
if _, ok := namespacedNameMap[key]; !ok {
152+
namespacedNameMap[key] = struct{}{}
153+
requests = append(requests, reconcile.Request{
154+
NamespacedName: client.ObjectKey{
155+
Namespace: hr.Namespace,
156+
Name: hr.Name,
157+
},
158+
})
159+
}
160+
}
161+
default:
162+
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy")
163+
}
164+
return requests
165+
}
166+
71167
func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
72168
hr := new(gatewayv1.HTTPRoute)
73169
if err := r.Get(ctx, req.NamespacedName, hr); err != nil {
@@ -114,6 +210,7 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
114210

115211
tctx := provider.NewDefaultTranslateContext(ctx)
116212

213+
tctx.RouteParentRefs = hr.Spec.ParentRefs
117214
rk := provider.ResourceKind{
118215
Kind: hr.Kind,
119216
Namespace: hr.Namespace,
@@ -138,6 +235,8 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
138235
}
139236
}
140237

238+
ProcessBackendTrafficPolicy(r.Client, r.Log, tctx)
239+
141240
if err := r.Provider.Update(ctx, tctx, hr); err != nil {
142241
acceptStatus.status = false
143242
acceptStatus.msg = err.Error()
@@ -161,6 +260,7 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
161260
if err := r.Status().Update(ctx, hr); err != nil {
162261
return ctrl.Result{}, err
163262
}
263+
UpdateStatus(r.Client, r.Log, tctx)
164264
return ctrl.Result{}, nil
165265
}
166266

@@ -220,6 +320,54 @@ func (r *HTTPRouteReconciler) listHTTPRoutesByExtensionRef(ctx context.Context,
220320
return requests
221321
}
222322

323+
func (r *HTTPRouteReconciler) listHTTPRoutesForBackendTrafficPolicy(ctx context.Context, obj client.Object) []reconcile.Request {
324+
policy, ok := obj.(*v1alpha1.BackendTrafficPolicy)
325+
if !ok {
326+
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy")
327+
return nil
328+
}
329+
330+
httprouteList := []gatewayv1.HTTPRoute{}
331+
for _, targetRef := range policy.Spec.TargetRefs {
332+
service := &corev1.Service{}
333+
if err := r.Get(ctx, client.ObjectKey{
334+
Namespace: policy.Namespace,
335+
Name: string(targetRef.Name),
336+
}, service); err != nil {
337+
if client.IgnoreNotFound(err) != nil {
338+
r.Log.Error(err, "failed to get service", "namespace", policy.Namespace, "name", targetRef.Name)
339+
}
340+
continue
341+
}
342+
hrList := &gatewayv1.HTTPRouteList{}
343+
if err := r.List(ctx, hrList, client.MatchingFields{
344+
indexer.ServiceIndexRef: indexer.GenIndexKey(policy.Namespace, string(targetRef.Name)),
345+
}); err != nil {
346+
r.Log.Error(err, "failed to list httproutes by service reference", "service", targetRef.Name)
347+
return nil
348+
}
349+
httprouteList = append(httprouteList, hrList.Items...)
350+
}
351+
var namespacedNameMap = make(map[types.NamespacedName]struct{})
352+
requests := make([]reconcile.Request, 0, len(httprouteList))
353+
for _, hr := range httprouteList {
354+
key := types.NamespacedName{
355+
Namespace: hr.Namespace,
356+
Name: hr.Name,
357+
}
358+
if _, ok := namespacedNameMap[key]; !ok {
359+
namespacedNameMap[key] = struct{}{}
360+
requests = append(requests, reconcile.Request{
361+
NamespacedName: client.ObjectKey{
362+
Namespace: hr.Namespace,
363+
Name: hr.Name,
364+
},
365+
})
366+
}
367+
}
368+
return requests
369+
}
370+
223371
func (r *HTTPRouteReconciler) listHTTPRoutesForGateway(ctx context.Context, obj client.Object) []reconcile.Request {
224372
gateway, ok := obj.(*gatewayv1.Gateway)
225373
if !ok {

internal/controller/indexer/indexer.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,9 @@ func SetupIndexer(mgr ctrl.Manager) error {
3737
if err := setupConsumerIndexer(mgr); err != nil {
3838
return err
3939
}
40-
/*
41-
if err := setupBackendTrafficPolicyIndexer(mgr); err != nil {
42-
return err
43-
}
44-
*/
40+
if err := setupBackendTrafficPolicyIndexer(mgr); err != nil {
41+
return err
42+
}
4543
return nil
4644
}
4745

@@ -183,7 +181,7 @@ func setupIngressIndexer(mgr ctrl.Manager) error {
183181
return nil
184182
}
185183

186-
func SetupBackendTrafficPolicyIndexer(mgr ctrl.Manager) error {
184+
func setupBackendTrafficPolicyIndexer(mgr ctrl.Manager) error {
187185
if err := mgr.GetFieldIndexer().IndexField(
188186
context.Background(),
189187
&v1alpha1.BackendTrafficPolicy{},

0 commit comments

Comments
 (0)