Skip to content

Commit b4f4b6f

Browse files
committed
fix: r
Signed-off-by: ashing <[email protected]>
1 parent 3457348 commit b4f4b6f

File tree

5 files changed

+845
-10
lines changed

5 files changed

+845
-10
lines changed
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
// Licensed under the Apache License, Version 2.0 (the "License");
2+
// you may not use this file except in compliance with the License.
3+
// You may obtain a copy of the License at
4+
//
5+
// http://www.apache.org/licenses/LICENSE-2.0
6+
//
7+
// Unless required by applicable law or agreed to in writing, software
8+
// distributed under the License is distributed on an "AS IS" BASIS,
9+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
// See the License for the specific language governing permissions and
11+
// limitations under the License.
12+
13+
package controller
14+
15+
import (
16+
"context"
17+
"fmt"
18+
19+
"github.com/go-logr/logr"
20+
networkingv1 "k8s.io/api/networking/v1"
21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
"k8s.io/apimachinery/pkg/runtime"
23+
ctrl "sigs.k8s.io/controller-runtime"
24+
"sigs.k8s.io/controller-runtime/pkg/builder"
25+
"sigs.k8s.io/controller-runtime/pkg/client"
26+
"sigs.k8s.io/controller-runtime/pkg/handler"
27+
"sigs.k8s.io/controller-runtime/pkg/predicate"
28+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
29+
30+
"github.com/apache/apisix-ingress-controller/api/v1alpha1"
31+
apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
32+
"github.com/apache/apisix-ingress-controller/internal/controller/status"
33+
"github.com/apache/apisix-ingress-controller/internal/provider"
34+
"github.com/apache/apisix-ingress-controller/internal/utils"
35+
)
36+
37+
// ApisixPluginConfigReconciler reconciles a ApisixPluginConfig object
38+
type ApisixPluginConfigReconciler struct {
39+
client.Client
40+
Scheme *runtime.Scheme
41+
Log logr.Logger
42+
Provider provider.Provider
43+
Updater status.Updater
44+
}
45+
46+
// SetupWithManager sets up the controller with the Manager.
47+
func (r *ApisixPluginConfigReconciler) SetupWithManager(mgr ctrl.Manager) error {
48+
return ctrl.NewControllerManagedBy(mgr).
49+
For(&apiv2.ApisixPluginConfig{}).
50+
WithEventFilter(
51+
predicate.Or(
52+
predicate.GenerationChangedPredicate{},
53+
),
54+
).
55+
Watches(&networkingv1.IngressClass{},
56+
handler.EnqueueRequestsFromMapFunc(r.listApisixPluginConfigForIngressClass),
57+
builder.WithPredicates(
58+
predicate.NewPredicateFuncs(r.matchesIngressController),
59+
),
60+
).
61+
Watches(&v1alpha1.GatewayProxy{},
62+
handler.EnqueueRequestsFromMapFunc(r.listApisixPluginConfigForGatewayProxy),
63+
).
64+
Named("apisixpluginconfig").
65+
Complete(r)
66+
}
67+
68+
func (r *ApisixPluginConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
69+
var pc apiv2.ApisixPluginConfig
70+
if err := r.Get(ctx, req.NamespacedName, &pc); err != nil {
71+
if client.IgnoreNotFound(err) == nil {
72+
pc.Namespace = req.Namespace
73+
pc.Name = req.Name
74+
pc.TypeMeta = metav1.TypeMeta{
75+
Kind: KindApisixPluginConfig,
76+
APIVersion: apiv2.GroupVersion.String(),
77+
}
78+
79+
// if err := r.Provider.Delete(ctx, &pc); err != nil {
80+
// r.Log.Error(err, "failed to delete apisixpluginconfig", "apisixpluginconfig", pc)
81+
// return ctrl.Result{}, err
82+
// }
83+
return ctrl.Result{}, nil
84+
}
85+
return ctrl.Result{}, err
86+
}
87+
88+
var (
89+
tctx = provider.NewDefaultTranslateContext(ctx)
90+
ic *networkingv1.IngressClass
91+
err error
92+
)
93+
defer func() {
94+
r.updateStatus(&pc, err)
95+
}()
96+
97+
if ic, err = r.getIngressClass(&pc); err != nil {
98+
return ctrl.Result{}, err
99+
}
100+
if err = r.processIngressClassParameters(ctx, tctx, &pc, ic); err != nil {
101+
return ctrl.Result{}, err
102+
}
103+
if err = r.processApisixPluginConfig(ctx, tctx, &pc); err != nil {
104+
return ctrl.Result{}, err
105+
}
106+
// if err = r.Provider.Update(ctx, tctx, &pc); err != nil {
107+
// err = ReasonError{
108+
// Reason: string(apiv2.ConditionReasonSyncFailed),
109+
// Message: err.Error(),
110+
// }
111+
// r.Log.Error(err, "failed to process", "apisixpluginconfig", pc)
112+
// return ctrl.Result{}, err
113+
// }
114+
115+
return ctrl.Result{}, nil
116+
}
117+
118+
func (r *ApisixPluginConfigReconciler) processApisixPluginConfig(_ context.Context, _ *provider.TranslateContext, in *apiv2.ApisixPluginConfig) error {
119+
// Validate plugins
120+
for _, plugin := range in.Spec.Plugins {
121+
if plugin.Name == "" {
122+
return ReasonError{
123+
Reason: string(apiv2.ConditionReasonInvalidSpec),
124+
Message: "plugin name cannot be empty",
125+
}
126+
}
127+
}
128+
129+
return nil
130+
}
131+
132+
func (r *ApisixPluginConfigReconciler) listApisixPluginConfigForIngressClass(ctx context.Context, object client.Object) (requests []reconcile.Request) {
133+
ic, ok := object.(*networkingv1.IngressClass)
134+
if !ok {
135+
return nil
136+
}
137+
138+
isDefaultIngressClass := IsDefaultIngressClass(ic)
139+
var pcList apiv2.ApisixPluginConfigList
140+
if err := r.List(ctx, &pcList); err != nil {
141+
return nil
142+
}
143+
for _, pc := range pcList.Items {
144+
if pc.Spec.IngressClassName == ic.Name || (isDefaultIngressClass && pc.Spec.IngressClassName == "") {
145+
requests = append(requests, reconcile.Request{NamespacedName: utils.NamespacedName(&pc)})
146+
}
147+
}
148+
return requests
149+
}
150+
151+
func (r *ApisixPluginConfigReconciler) listApisixPluginConfigForGatewayProxy(ctx context.Context, object client.Object) (requests []reconcile.Request) {
152+
gp, ok := object.(*v1alpha1.GatewayProxy)
153+
if !ok {
154+
return nil
155+
}
156+
157+
var icList networkingv1.IngressClassList
158+
if err := r.List(ctx, &icList); err != nil {
159+
r.Log.Error(err, "failed to list ingress classes for gateway proxy", "gatewayproxy", gp.GetName())
160+
return nil
161+
}
162+
163+
for _, ic := range icList.Items {
164+
requests = append(requests, r.listApisixPluginConfigForIngressClass(ctx, &ic)...)
165+
}
166+
167+
return requests
168+
}
169+
170+
func (r *ApisixPluginConfigReconciler) matchesIngressController(obj client.Object) bool {
171+
ingressClass, ok := obj.(*networkingv1.IngressClass)
172+
if !ok {
173+
return false
174+
}
175+
return matchesController(ingressClass.Spec.Controller)
176+
}
177+
178+
func (r *ApisixPluginConfigReconciler) getIngressClass(pc *apiv2.ApisixPluginConfig) (*networkingv1.IngressClass, error) {
179+
if pc.Spec.IngressClassName == "" {
180+
return r.getDefaultIngressClass()
181+
}
182+
183+
var ic networkingv1.IngressClass
184+
if err := r.Get(context.Background(), client.ObjectKey{Name: pc.Spec.IngressClassName}, &ic); err != nil {
185+
return nil, err
186+
}
187+
return &ic, nil
188+
}
189+
190+
func (r *ApisixPluginConfigReconciler) getDefaultIngressClass() (*networkingv1.IngressClass, error) {
191+
var icList networkingv1.IngressClassList
192+
if err := r.List(context.Background(), &icList); err != nil {
193+
r.Log.Error(err, "failed to list ingress classes")
194+
return nil, err
195+
}
196+
for _, ic := range icList.Items {
197+
if IsDefaultIngressClass(&ic) && matchesController(ic.Spec.Controller) {
198+
return &ic, nil
199+
}
200+
}
201+
return nil, ReasonError{
202+
Reason: string(metav1.StatusReasonNotFound),
203+
Message: "default ingress class not found or does not match the controller",
204+
}
205+
}
206+
207+
// processIngressClassParameters processes the IngressClass parameters that reference GatewayProxy
208+
func (r *ApisixPluginConfigReconciler) processIngressClassParameters(ctx context.Context, tc *provider.TranslateContext, pc *apiv2.ApisixPluginConfig, ingressClass *networkingv1.IngressClass) error {
209+
if ingressClass == nil || ingressClass.Spec.Parameters == nil {
210+
return nil
211+
}
212+
213+
var (
214+
ingressClassKind = utils.NamespacedNameKind(ingressClass)
215+
pcKind = utils.NamespacedNameKind(pc)
216+
parameters = ingressClass.Spec.Parameters
217+
)
218+
if parameters.APIGroup == nil || *parameters.APIGroup != v1alpha1.GroupVersion.Group || parameters.Kind != KindGatewayProxy {
219+
return nil
220+
}
221+
222+
// check if the parameters reference GatewayProxy
223+
var (
224+
gatewayProxy v1alpha1.GatewayProxy
225+
ns = parameters.Namespace
226+
)
227+
if ns == nil {
228+
ns = &pc.Namespace
229+
}
230+
231+
if err := r.Get(ctx, client.ObjectKey{Namespace: *ns, Name: parameters.Name}, &gatewayProxy); err != nil {
232+
r.Log.Error(err, "failed to get GatewayProxy", "namespace", *ns, "name", parameters.Name)
233+
return err
234+
}
235+
236+
tc.GatewayProxies[ingressClassKind] = gatewayProxy
237+
tc.ResourceParentRefs[pcKind] = append(tc.ResourceParentRefs[pcKind], ingressClassKind)
238+
239+
return nil
240+
}
241+
242+
func (r *ApisixPluginConfigReconciler) updateStatus(pc *apiv2.ApisixPluginConfig, err error) {
243+
SetApisixPluginConfigConditionAccepted(&pc.Status, pc.GetGeneration(), err)
244+
r.Updater.Update(status.Update{
245+
NamespacedName: utils.NamespacedName(pc),
246+
Resource: &apiv2.ApisixPluginConfig{},
247+
Mutator: status.MutatorFunc(func(obj client.Object) client.Object {
248+
cp, ok := obj.(*apiv2.ApisixPluginConfig)
249+
if !ok {
250+
err := fmt.Errorf("unsupported object type %T", obj)
251+
panic(err)
252+
}
253+
cpCopy := cp.DeepCopy()
254+
cpCopy.Status = pc.Status
255+
return cpCopy
256+
}),
257+
})
258+
}

internal/controller/utils.go

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,17 @@ import (
4747
)
4848

4949
const (
50-
KindGateway = "Gateway"
51-
KindHTTPRoute = "HTTPRoute"
52-
KindGatewayClass = "GatewayClass"
53-
KindIngress = "Ingress"
54-
KindIngressClass = "IngressClass"
55-
KindGatewayProxy = "GatewayProxy"
56-
KindSecret = "Secret"
57-
KindService = "Service"
58-
KindApisixRoute = "ApisixRoute"
59-
KindApisixGlobalRule = "ApisixGlobalRule"
50+
KindGateway = "Gateway"
51+
KindHTTPRoute = "HTTPRoute"
52+
KindGatewayClass = "GatewayClass"
53+
KindIngress = "Ingress"
54+
KindIngressClass = "IngressClass"
55+
KindGatewayProxy = "GatewayProxy"
56+
KindSecret = "Secret"
57+
KindService = "Service"
58+
KindApisixRoute = "ApisixRoute"
59+
KindApisixGlobalRule = "ApisixGlobalRule"
60+
KindApisixPluginConfig = "ApisixPluginConfig"
6061
)
6162

6263
const defaultIngressClassAnnotation = "ingressclass.kubernetes.io/is-default-class"
@@ -432,6 +433,28 @@ func SetApisixRouteConditionAccepted(status *apiv2.ApisixStatus, generation int6
432433
status.Conditions = []metav1.Condition{condition}
433434
}
434435

436+
func SetApisixPluginConfigConditionAccepted(status *apiv2.ApisixStatus, generation int64, err error) {
437+
var condition = metav1.Condition{
438+
Type: string(apiv2.ConditionTypeAccepted),
439+
Status: metav1.ConditionTrue,
440+
ObservedGeneration: generation,
441+
LastTransitionTime: metav1.Now(),
442+
Reason: string(apiv2.ConditionReasonAccepted),
443+
}
444+
if err != nil {
445+
condition.Status = metav1.ConditionFalse
446+
condition.Reason = string(apiv2.ConditionReasonInvalidSpec)
447+
condition.Message = err.Error()
448+
449+
var re ReasonError
450+
if errors.As(err, &re) {
451+
condition.Reason = re.Reason
452+
}
453+
}
454+
455+
status.Conditions = []metav1.Condition{condition}
456+
}
457+
435458
func checkRouteAcceptedByListener(
436459
ctx context.Context,
437460
mgrc client.Client,

internal/manager/controllers.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,5 +134,12 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro
134134
Provider: pro,
135135
Updater: updater,
136136
},
137+
&controller.ApisixPluginConfigReconciler{
138+
Client: mgr.GetClient(),
139+
Scheme: mgr.GetScheme(),
140+
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixPluginConfig"),
141+
Provider: pro,
142+
Updater: updater,
143+
},
137144
}, nil
138145
}

0 commit comments

Comments
 (0)