Skip to content

Commit cb81148

Browse files
authored
feat: Handling related resources which references to GatewayProxy (#90)
Signed-off-by: ashing <[email protected]>
1 parent 9e4e35b commit cb81148

File tree

15 files changed

+795
-51
lines changed

15 files changed

+795
-51
lines changed

api/v1alpha1/gatewayproxy_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ type ControlPlaneProvider struct {
113113
// +kubebuilder:validation:MinItems=1
114114
Endpoints []string `json:"endpoints"`
115115

116+
// TlsVerify specifies whether to verify the TLS certificate of the control plane
117+
// +optional
118+
TlsVerify *bool `json:"tlsVerify,omitempty"`
119+
116120
// Auth specifies the authentication configuration
117121
// +kubebuilder:validation:Required
118122
Auth ControlPlaneAuth `json:"auth"`

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ spec:
108108
type: string
109109
minItems: 1
110110
type: array
111+
tlsVerify:
112+
description: TlsVerify specifies whether to verify the TLS
113+
certificate of the control plane
114+
type: boolean
111115
required:
112116
- auth
113117
- endpoints

config/samples/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ gateway_configs: # The configuration of the API7 Gateway.
2424
control_plane:
2525
admin_key: "${ADMIN_KEY}" # The admin key of the control plane.
2626
endpoints:
27-
- ${ENDPOINT} # The endpoint of the control plane.
27+
- ${ENDPOINT} # The endpoint of the control plane.
2828
tls_verify: false
2929
addresses: # record the status address of the gateway-api gateway
3030
- "172.18.0.4" # The LB IP of the gateway service.

internal/controller/consumer_controller.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,23 @@ func (r *ConsumerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
138138
var statusErr error
139139
tctx := provider.NewDefaultTranslateContext(ctx)
140140

141+
gateway, err := r.getGateway(ctx, consumer)
142+
if err != nil {
143+
r.Log.Error(err, "failed to get gateway", "consumer", consumer)
144+
statusErr = err
145+
}
146+
147+
rk := provider.ResourceKind{
148+
Kind: consumer.Kind,
149+
Namespace: consumer.Namespace,
150+
Name: consumer.Name,
151+
}
152+
153+
if err := ProcessGatewayProxy(r.Client, tctx, gateway, rk); err != nil {
154+
r.Log.Error(err, "failed to process gateway proxy", "gateway", gateway)
155+
statusErr = err
156+
}
157+
141158
if err := r.processSpec(ctx, tctx, consumer); err != nil {
142159
r.Log.Error(err, "failed to process consumer spec", "consumer", consumer)
143160
statusErr = err
@@ -201,6 +218,22 @@ func (r *ConsumerReconciler) updateStatus(ctx context.Context, consumer *v1alpha
201218
return nil
202219
}
203220

221+
func (r *ConsumerReconciler) getGateway(ctx context.Context, consumer *v1alpha1.Consumer) (*gatewayv1.Gateway, error) {
222+
ns := consumer.GetNamespace()
223+
if consumer.Spec.GatewayRef.Namespace != nil {
224+
ns = *consumer.Spec.GatewayRef.Namespace
225+
}
226+
gateway := &gatewayv1.Gateway{}
227+
if err := r.Get(ctx, client.ObjectKey{
228+
Name: consumer.Spec.GatewayRef.Name,
229+
Namespace: ns,
230+
}, gateway); err != nil {
231+
r.Log.Error(err, "failed to get gateway", "gateway", consumer.Spec.GatewayRef.Name)
232+
return nil, err
233+
}
234+
return gateway, nil
235+
}
236+
204237
func (r *ConsumerReconciler) checkGatewayRef(object client.Object) bool {
205238
consumer, ok := object.(*v1alpha1.Consumer)
206239
if !ok {

internal/controller/gateway_controller.go

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,10 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
107107
status: true,
108108
msg: acceptedMessage("gateway"),
109109
}
110-
tctx := &provider.TranslateContext{
111-
Secrets: make(map[types.NamespacedName]*corev1.Secret),
112-
}
110+
111+
// create a translate context
112+
tctx := provider.NewDefaultTranslateContext(ctx)
113+
113114
r.processListenerConfig(tctx, gateway)
114115
if err := r.processInfrastructure(tctx, gateway); err != nil {
115116
acceptStatus = status{
@@ -267,28 +268,12 @@ func (r *GatewayReconciler) listGatewaysForHTTPRoute(_ context.Context, obj clie
267268
}
268269

269270
func (r *GatewayReconciler) processInfrastructure(tctx *provider.TranslateContext, gateway *gatewayv1.Gateway) error {
270-
infra := gateway.Spec.Infrastructure
271-
if infra == nil || infra.ParametersRef == nil {
272-
return nil
271+
rk := provider.ResourceKind{
272+
Kind: gateway.Kind,
273+
Namespace: gateway.Namespace,
274+
Name: gateway.Name,
273275
}
274-
275-
ns := gateway.GetNamespace()
276-
paramRef := infra.ParametersRef
277-
if string(paramRef.Group) == v1alpha1.GroupVersion.Group && string(paramRef.Kind) == "GatewayProxy" {
278-
gatewayProxy := &v1alpha1.GatewayProxy{}
279-
if err := r.Get(context.Background(), client.ObjectKey{
280-
Namespace: ns,
281-
Name: paramRef.Name,
282-
}, gatewayProxy); err != nil {
283-
log.Error(err, "failed to get GatewayProxy", "namespace", ns, "name", paramRef.Name)
284-
return err
285-
} else {
286-
log.Info("found GatewayProxy for Gateway", "gateway", gateway.Name, "gatewayproxy", gatewayProxy.Name)
287-
tctx.GatewayProxy = gatewayProxy
288-
}
289-
}
290-
291-
return nil
276+
return ProcessGatewayProxy(r.Client, tctx, gateway, rk)
292277
}
293278

294279
func (r *GatewayReconciler) processListenerConfig(tctx *provider.TranslateContext, gateway *gatewayv1.Gateway) {

internal/controller/httproute_controller.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
114114

115115
tctx := provider.NewDefaultTranslateContext(ctx)
116116

117+
rk := provider.ResourceKind{
118+
Kind: hr.Kind,
119+
Namespace: hr.Namespace,
120+
Name: hr.Name,
121+
}
122+
for _, gateway := range gateways {
123+
if err := ProcessGatewayProxy(r.Client, tctx, gateway.Gateway, rk); err != nil {
124+
acceptStatus.status = false
125+
acceptStatus.msg = err.Error()
126+
}
127+
}
128+
117129
if err := r.processHTTPRoute(tctx, hr); err != nil {
118130
acceptStatus.status = false
119131
acceptStatus.msg = err.Error()

internal/controller/ingress_controller.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ package controller
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"reflect"
78

9+
"github.com/api7/api7-ingress-controller/api/v1alpha1"
810
"github.com/api7/api7-ingress-controller/internal/controller/config"
911
"github.com/api7/api7-ingress-controller/internal/controller/indexer"
1012
"github.com/api7/api7-ingress-controller/internal/provider"
@@ -95,6 +97,12 @@ func (r *IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
9597
// create a translate context
9698
tctx := provider.NewDefaultTranslateContext(ctx)
9799

100+
// process IngressClass parameters if they reference GatewayProxy
101+
if err := r.processIngressClassParameters(ctx, tctx, ingress); err != nil {
102+
r.Log.Error(err, "failed to process IngressClass parameters", "ingress", ingress.Name)
103+
return ctrl.Result{}, err
104+
}
105+
98106
// process TLS configuration
99107
if err := r.processTLS(tctx, ingress); err != nil {
100108
r.Log.Error(err, "failed to process TLS configuration", "ingress", ingress.Name)
@@ -122,6 +130,46 @@ func (r *IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
122130
return ctrl.Result{}, nil
123131
}
124132

133+
// getIngressClass get the ingress class for the ingress
134+
func (r *IngressReconciler) getIngressClass(obj client.Object) (*networkingv1.IngressClass, error) {
135+
ingress := obj.(*networkingv1.Ingress)
136+
137+
if ingress.Spec.IngressClassName == nil {
138+
// handle the case where IngressClassName is not specified
139+
// find all ingress classes and check if any of them is marked as default
140+
ingressClassList := &networkingv1.IngressClassList{}
141+
if err := r.List(context.Background(), ingressClassList, client.MatchingFields{
142+
indexer.IngressClass: config.GetControllerName(),
143+
}); err != nil {
144+
r.Log.Error(err, "failed to list ingress classes")
145+
return nil, err
146+
}
147+
148+
// find the ingress class that is marked as default
149+
for _, ic := range ingressClassList.Items {
150+
if IsDefaultIngressClass(&ic) && matchesController(ic.Spec.Controller) {
151+
log.Debugw("match the default ingress class")
152+
return &ic, nil
153+
}
154+
}
155+
156+
log.Debugw("no default ingress class found")
157+
return nil, errors.New("no default ingress class found")
158+
}
159+
160+
// if it does not match, check if the ingress class is controlled by us
161+
ingressClass := networkingv1.IngressClass{}
162+
if err := r.Client.Get(context.Background(), client.ObjectKey{Name: *ingress.Spec.IngressClassName}, &ingressClass); err != nil {
163+
return nil, err
164+
}
165+
166+
if matchesController(ingressClass.Spec.Controller) {
167+
return &ingressClass, nil
168+
}
169+
170+
return nil, errors.New("ingress class is not controlled by us")
171+
}
172+
125173
// checkIngressClass check if the ingress uses the ingress class that we control
126174
func (r *IngressReconciler) checkIngressClass(obj client.Object) bool {
127175
ingress := obj.(*networkingv1.Ingress)
@@ -413,6 +461,8 @@ func (r *IngressReconciler) processBackendService(tctx *provider.TranslateContex
413461
func (r *IngressReconciler) updateStatus(ctx context.Context, ingress *networkingv1.Ingress) error {
414462
var loadBalancerStatus networkingv1.IngressLoadBalancerStatus
415463

464+
// todo: remove using default config, use the StatusAddress And PublishService in the gateway proxy
465+
416466
// 1. use the IngressStatusAddress in the config
417467
statusAddresses := config.GetIngressStatusAddress()
418468
if len(statusAddresses) > 0 {
@@ -469,3 +519,84 @@ func (r *IngressReconciler) updateStatus(ctx context.Context, ingress *networkin
469519

470520
return nil
471521
}
522+
523+
// processIngressClassParameters processes the IngressClass parameters that reference GatewayProxy
524+
func (r *IngressReconciler) processIngressClassParameters(ctx context.Context, tctx *provider.TranslateContext, ingress *networkingv1.Ingress) error {
525+
ingressClass, err := r.getIngressClass(ingress)
526+
if err != nil {
527+
r.Log.Error(err, "failed to get IngressClass", "name", ingress.Spec.IngressClassName)
528+
return err
529+
}
530+
531+
if ingressClass.Spec.Parameters == nil {
532+
return nil
533+
}
534+
535+
ingressClassKind := provider.ResourceKind{
536+
Kind: ingressClass.Kind,
537+
Namespace: ingressClass.Namespace,
538+
Name: ingressClass.Name,
539+
}
540+
541+
ingressKind := provider.ResourceKind{
542+
Kind: ingress.Kind,
543+
Namespace: ingress.Namespace,
544+
Name: ingress.Name,
545+
}
546+
547+
parameters := ingressClass.Spec.Parameters
548+
// check if the parameters reference GatewayProxy
549+
if parameters.APIGroup != nil && *parameters.APIGroup == v1alpha1.GroupVersion.Group && parameters.Kind == "GatewayProxy" {
550+
ns := ingress.GetNamespace()
551+
if parameters.Namespace != nil {
552+
ns = *parameters.Namespace
553+
}
554+
555+
gatewayProxy := &v1alpha1.GatewayProxy{}
556+
if err := r.Get(ctx, client.ObjectKey{
557+
Namespace: ns,
558+
Name: parameters.Name,
559+
}, gatewayProxy); err != nil {
560+
r.Log.Error(err, "failed to get GatewayProxy", "namespace", ns, "name", parameters.Name)
561+
return err
562+
}
563+
564+
r.Log.Info("found GatewayProxy for IngressClass", "ingressClass", ingressClass.Name, "gatewayproxy", gatewayProxy.Name)
565+
tctx.GatewayProxies[ingressClassKind] = *gatewayProxy
566+
tctx.ResourceParentRefs[ingressKind] = append(tctx.ResourceParentRefs[ingressKind], ingressClassKind)
567+
568+
// check if the provider field references a secret
569+
if gatewayProxy.Spec.Provider != nil && gatewayProxy.Spec.Provider.Type == v1alpha1.ProviderTypeControlPlane {
570+
if gatewayProxy.Spec.Provider.ControlPlane != nil &&
571+
gatewayProxy.Spec.Provider.ControlPlane.Auth.Type == v1alpha1.AuthTypeAdminKey &&
572+
gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey != nil &&
573+
gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey.ValueFrom != nil &&
574+
gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey.ValueFrom.SecretKeyRef != nil {
575+
576+
secretRef := gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey.ValueFrom.SecretKeyRef
577+
secret := &corev1.Secret{}
578+
if err := r.Get(ctx, client.ObjectKey{
579+
Namespace: ns,
580+
Name: secretRef.Name,
581+
}, secret); err != nil {
582+
r.Log.Error(err, "failed to get secret for GatewayProxy provider",
583+
"namespace", ns,
584+
"name", secretRef.Name)
585+
return err
586+
}
587+
588+
r.Log.Info("found secret for GatewayProxy provider",
589+
"ingressClass", ingressClass.Name,
590+
"gatewayproxy", gatewayProxy.Name,
591+
"secret", secretRef.Name)
592+
593+
tctx.Secrets[types.NamespacedName{
594+
Namespace: ns,
595+
Name: secretRef.Name,
596+
}] = secret
597+
}
598+
}
599+
}
600+
601+
return nil
602+
}

0 commit comments

Comments
 (0)