Skip to content

Commit df0ec27

Browse files
committed
feat: support gateway proxy plugin metadata
1 parent 27e4bf7 commit df0ec27

File tree

11 files changed

+183
-9
lines changed

11 files changed

+183
-9
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,11 @@ endif
196196

197197
.PHONY: install-gateway-api
198198
install-gateway-api: ## Install Gateway API CRDs into the K8s cluster specified in ~/.kube/config.
199-
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/$(GATEAY_API_VERSION)/standard-install.yaml
199+
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/$(GATEAY_API_VERSION)/experimental-install.yaml
200200

201201
.PHONY: uninstall-gateway-api
202202
uninstall-gateway-api: ## Uninstall Gateway API CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
203-
kubectl delete -f https://github.com/kubernetes-sigs/gateway-api/releases/download/$(GATEAY_API_VERSION)/standard-install.yaml
203+
kubectl delete -f https://github.com/kubernetes-sigs/gateway-api/releases/download/$(GATEAY_API_VERSION)/experimental-install.yaml
204204

205205
.PHONY: install
206206
install: manifests kustomize install-gateway-api ## Install CRDs into the K8s cluster specified in ~/.kube/config.

config/rbac/role.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ rules:
5555
- get
5656
- list
5757
- watch
58+
- apiGroups:
59+
- gateway.apisix.io
60+
resources:
61+
- gatewayproxies
62+
verbs:
63+
- get
64+
- list
65+
- watch
5866
- apiGroups:
5967
- gateway.apisix.io
6068
resources:

internal/controller/gateway_controller.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import (
55
"fmt"
66
"reflect"
77

8+
"github.com/api7/api7-ingress-controller/api/v1alpha1"
89
"github.com/api7/api7-ingress-controller/internal/controller/config"
10+
"github.com/api7/api7-ingress-controller/internal/controller/indexer"
911
"github.com/api7/api7-ingress-controller/internal/provider"
1012
"github.com/api7/gopkg/pkg/log"
1113
"github.com/go-logr/logr"
@@ -33,8 +35,23 @@ type GatewayReconciler struct { //nolint:revive
3335
Provider provider.Provider
3436
}
3537

38+
func (r *GatewayReconciler) setupIndexer(mgr ctrl.Manager) error {
39+
if err := mgr.GetFieldIndexer().IndexField(
40+
context.Background(),
41+
&gatewayv1.Gateway{},
42+
indexer.ParametersRef,
43+
indexer.GatewayParametersRefIndexFunc,
44+
); err != nil {
45+
return err
46+
}
47+
return nil
48+
}
49+
3650
// SetupWithManager sets up the controller with the Manager.
3751
func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error {
52+
if err := r.setupIndexer(mgr); err != nil {
53+
return err
54+
}
3855
return ctrl.NewControllerManagedBy(mgr).
3956
For(&gatewayv1.Gateway{}).
4057
Watches(
@@ -46,6 +63,10 @@ func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error {
4663
&gatewayv1.HTTPRoute{},
4764
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForHTTPRoute),
4865
).
66+
Watches(
67+
&v1alpha1.GatewayProxy{},
68+
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForGatewayProxy),
69+
).
4970
Complete(r)
5071
}
5172

@@ -99,6 +120,13 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
99120
Secrets: make(map[types.NamespacedName]*corev1.Secret),
100121
}
101122
r.processListenerConfig(tctx, gateway, ns)
123+
if err := r.processGatewayProxy(tctx, gateway, ns); err != nil {
124+
acceptStatus = status{
125+
status: false,
126+
msg: err.Error(),
127+
}
128+
}
129+
102130
if err := r.Provider.Update(ctx, tctx, gateway); err != nil {
103131
acceptStatus = status{
104132
status: false,
@@ -181,6 +209,35 @@ func (r *GatewayReconciler) checkGatewayClass(gateway *gatewayv1.Gateway) bool {
181209
return matchesController(string(gatewayClass.Spec.ControllerName))
182210
}
183211

212+
func (r *GatewayReconciler) listGatewaysForGatewayProxy(ctx context.Context, obj client.Object) []reconcile.Request {
213+
gatewayProxy, ok := obj.(*v1alpha1.GatewayProxy)
214+
if !ok {
215+
r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to GatewayProxy")
216+
return nil
217+
}
218+
namespace := gatewayProxy.GetNamespace()
219+
name := gatewayProxy.GetName()
220+
221+
gatewayList := &gatewayv1.GatewayList{}
222+
if err := r.List(ctx, gatewayList, client.MatchingFields{
223+
indexer.ParametersRef: indexer.GenIndexKey(namespace, name),
224+
}); err != nil {
225+
r.Log.Error(err, "failed to list gateways for gateway proxy", "gatewayproxy", gatewayProxy.GetName())
226+
return nil
227+
}
228+
229+
recs := make([]reconcile.Request, 0, len(gatewayList.Items))
230+
for _, gateway := range gatewayList.Items {
231+
recs = append(recs, reconcile.Request{
232+
NamespacedName: client.ObjectKey{
233+
Namespace: gateway.GetNamespace(),
234+
Name: gateway.GetName(),
235+
},
236+
})
237+
}
238+
return recs
239+
}
240+
184241
func (r *GatewayReconciler) listGatewaysForHTTPRoute(_ context.Context, obj client.Object) []reconcile.Request {
185242
httpRoute, ok := obj.(*gatewayv1.HTTPRoute)
186243
if !ok {
@@ -215,6 +272,28 @@ func (r *GatewayReconciler) listGatewaysForHTTPRoute(_ context.Context, obj clie
215272
return recs
216273
}
217274

275+
func (r *GatewayReconciler) processGatewayProxy(tctx *provider.TranslateContext, gateway *gatewayv1.Gateway, ns string) error {
276+
infra := gateway.Spec.Infrastructure
277+
if infra != nil && infra.ParametersRef != nil {
278+
paramRef := infra.ParametersRef
279+
if string(paramRef.Group) == v1alpha1.GroupVersion.Group && string(paramRef.Kind) == "GatewayProxy" {
280+
gatewayProxy := &v1alpha1.GatewayProxy{}
281+
if err := r.Get(context.Background(), client.ObjectKey{
282+
Namespace: ns,
283+
Name: paramRef.Name,
284+
}, gatewayProxy); err != nil {
285+
log.Error(err, "failed to get GatewayProxy", "namespace", ns, "name", paramRef.Name)
286+
return err
287+
} else {
288+
log.Info("found GatewayProxy for Gateway", "gateway", gateway.Name, "gatewayproxy", gatewayProxy.Name)
289+
tctx.GatewayProxy = gatewayProxy
290+
}
291+
}
292+
}
293+
294+
return nil
295+
}
296+
218297
func (r *GatewayReconciler) processListenerConfig(tctx *provider.TranslateContext, gateway *gatewayv1.Gateway, ns string) {
219298
listeners := gateway.Spec.Listeners
220299
for _, listener := range listeners {

internal/controller/indexer/indexer.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
const (
99
ServiceIndexRef = "serviceRef"
1010
ExtensionRef = "extensionRef"
11+
ParametersRef = "parametersRef"
1112
)
1213

1314
func GenIndexKey(namespace, name string) string {
@@ -50,3 +51,14 @@ func HTTPRouteExtensionIndexFunc(rawObj client.Object) []string {
5051
}
5152
return keys
5253
}
54+
55+
func GatewayParametersRefIndexFunc(rawObj client.Object) []string {
56+
gw := rawObj.(*gatewayv1.Gateway)
57+
if gw.Spec.Infrastructure != nil && gw.Spec.Infrastructure.ParametersRef != nil {
58+
// now we only care about kind: GatewayProxy
59+
if gw.Spec.Infrastructure.ParametersRef.Kind == "GatewayProxy" {
60+
return []string{GenIndexKey(gw.GetNamespace(), gw.Spec.Infrastructure.ParametersRef.Name)}
61+
}
62+
}
63+
return nil
64+
}

internal/manager/controllers.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch
1818
// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch
1919
// +kubebuilder:rbac:groups=gateway.apisix.io,resources=pluginconfigs,verbs=get;list;watch
20+
// +kubebuilder:rbac:groups=gateway.apisix.io,resources=gatewayproxies,verbs=get;list;watch
2021

2122
type Controller interface {
2223
SetupWithManager(mgr manager.Manager) error

internal/provider/adc/adc.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ func (d *adcClient) Update(ctx context.Context, tctx *provider.TranslateContext,
4949
switch obj := obj.(type) {
5050
case *gatewayv1.HTTPRoute:
5151
result, err = d.translator.TranslateHTTPRoute(tctx, obj.DeepCopy())
52+
case *gatewayv1.Gateway:
53+
result, err = d.translator.TranslateGateway(tctx, obj.DeepCopy())
5254
}
5355
if err != nil {
5456
return err
@@ -58,7 +60,9 @@ func (d *adcClient) Update(ctx context.Context, tctx *provider.TranslateContext,
5860
}
5961

6062
resources := types.Resources{
61-
Services: result.Services,
63+
GlobalRules: result.GlobalRules,
64+
PluginMetadata: result.PluginMetadata,
65+
Services: result.Services,
6266
}
6367

6468
return d.sync(Task{
@@ -78,7 +82,7 @@ func (d *adcClient) Delete(ctx context.Context, obj client.Object) error {
7882
func (d *adcClient) sync(task Task) error {
7983
log.Debugw("syncing task", zap.Any("task", task))
8084

81-
yaml, err := yaml.Marshal(task.Resources)
85+
data, err := yaml.Marshal(task.Resources)
8286
if err != nil {
8387
return err
8488
}
@@ -92,15 +96,17 @@ func (d *adcClient) sync(task Task) error {
9296
_ = os.Remove(tmpFile.Name())
9397
}()
9498

95-
log.Debugw("syncing resources", zap.String("file", tmpFile.Name()), zap.String("yaml", string(yaml)))
99+
log.Debugw("syncing resources", zap.String("file", tmpFile.Name()), zap.String("yaml", string(data)))
96100

97-
if _, err := tmpFile.Write(yaml); err != nil {
101+
if _, err := tmpFile.Write(data); err != nil {
98102
return err
99103
}
100104
args := []string{
101105
"sync",
102106
"-f", tmpFile.Name(),
103107
"--include-resource-type", "service",
108+
"--include-resource-type", "global_rule",
109+
"--include-resource-type", "plugin_metadata",
104110
"--tls-skip-verify",
105111
}
106112

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,64 @@
11
package translator
2+
3+
import (
4+
"encoding/json"
5+
6+
adctypes "github.com/api7/api7-ingress-controller/api/adc"
7+
"github.com/api7/api7-ingress-controller/api/v1alpha1"
8+
"github.com/api7/api7-ingress-controller/internal/provider"
9+
"github.com/api7/gopkg/pkg/log"
10+
"go.uber.org/zap"
11+
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
12+
)
13+
14+
// FillPluginsFromGatewayProxy fill plugins from GatewayProxy to given plugins
15+
func (t *Translator) FillPluginsFromGatewayProxy(plugins adctypes.Plugins, gatewayProxy *v1alpha1.GatewayProxy) {
16+
if gatewayProxy == nil {
17+
return
18+
}
19+
20+
for _, plugin := range gatewayProxy.Spec.Plugins {
21+
// only apply enabled plugins
22+
if !plugin.Enabled {
23+
continue
24+
}
25+
26+
pluginName := plugin.Name
27+
var pluginConfig map[string]any
28+
if err := json.Unmarshal(plugin.Config.Raw, &pluginConfig); err != nil {
29+
log.Errorw("gateway proxy plugin config unmarshal failed", zap.Error(err), zap.String("plugin", pluginName))
30+
continue
31+
}
32+
33+
log.Debugw("fill plugin from gateway proxy", zap.String("plugin", pluginName), zap.Any("config", pluginConfig))
34+
plugins[pluginName] = pluginConfig
35+
}
36+
}
37+
38+
func (t *Translator) FillPluginMetadataFromGatewayProxy(pluginMetadata adctypes.Plugins, gatewayProxy *v1alpha1.GatewayProxy) {
39+
if gatewayProxy == nil {
40+
return
41+
}
42+
for k, v := range gatewayProxy.Spec.PluginMetadata {
43+
pluginMetadata[k] = v
44+
}
45+
}
46+
47+
// TranslateGateway translate gateway to adc resources
48+
func (t *Translator) TranslateGateway(tctx *provider.TranslateContext, gateway *gatewayv1.Gateway) (*TranslateResult, error) {
49+
result := &TranslateResult{}
50+
51+
// if gateway has a GatewayProxy resource, create a global service and apply plugins
52+
if tctx.GatewayProxy != nil {
53+
var (
54+
globalRules = adctypes.Plugins{}
55+
pluginMetadata = adctypes.Plugins{}
56+
)
57+
// apply plugins from GatewayProxy to global rules
58+
t.FillPluginsFromGatewayProxy(globalRules, tctx.GatewayProxy)
59+
t.FillPluginMetadataFromGatewayProxy(pluginMetadata, tctx.GatewayProxy)
60+
result.GlobalRules = globalRules
61+
}
62+
63+
return result, nil
64+
}

internal/provider/adc/translator/translator.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ type Translator struct {
1010
Log logr.Logger
1111
}
1212
type TranslateResult struct {
13-
Routes []*adctypes.Route
14-
Services []*adctypes.Service
15-
SSL []*adctypes.SSL
13+
Routes []*adctypes.Route
14+
Services []*adctypes.Service
15+
SSL []*adctypes.SSL
16+
GlobalRules adctypes.Plugins
17+
PluginMetadata adctypes.Plugins
1618
}

internal/provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Provider interface {
2020
type TranslateContext struct {
2121
BackendRefs []gatewayv1.BackendRef
2222
GatewayTLSConfig []gatewayv1.GatewayTLSConfig
23+
GatewayProxy *v1alpha1.GatewayProxy
2324
EndpointSlices map[types.NamespacedName][]discoveryv1.EndpointSlice
2425
Secrets map[types.NamespacedName]*corev1.Secret
2526
PluginConfigs map[types.NamespacedName]*v1alpha1.PluginConfig

test/e2e/framework/manifests/ingress.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ rules:
160160
- gateway.apisix.io
161161
resources:
162162
- pluginconfigs
163+
- gatewayproxies
163164
verbs:
164165
- get
165166
- list

0 commit comments

Comments
 (0)