@@ -14,56 +14,269 @@ package controller
1414
1515import (
1616 "context"
17+ "fmt"
1718
1819 "github.com/go-logr/logr"
20+ corev1 "k8s.io/api/core/v1"
21+ networkingv1 "k8s.io/api/networking/v1"
1922 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2023 "k8s.io/apimachinery/pkg/runtime"
24+ "k8s.io/apimachinery/pkg/types"
2125 ctrl "sigs.k8s.io/controller-runtime"
26+ "sigs.k8s.io/controller-runtime/pkg/builder"
2227 "sigs.k8s.io/controller-runtime/pkg/client"
23- gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
28+ "sigs.k8s.io/controller-runtime/pkg/handler"
29+ "sigs.k8s.io/controller-runtime/pkg/predicate"
30+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
2431
2532 apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
33+ "github.com/apache/apisix-ingress-controller/internal/provider"
34+ "github.com/apache/apisix-ingress-controller/internal/utils"
2635)
2736
2837// ApisixTlsReconciler reconciles a ApisixTls object
2938type ApisixTlsReconciler struct {
3039 client.Client
31- Scheme * runtime.Scheme
32- Log logr.Logger
40+ Scheme * runtime.Scheme
41+ Log logr.Logger
42+ Provider provider.Provider
3343}
3444
35- // Reconcile FIXME: implement the reconcile logic (For now, it dose nothing other than directly accepting)
45+ // Reconcile processes ApisixTls resources
3646func (r * ApisixTlsReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
37- r .Log .Info ("reconcile" , "request" , req .NamespacedName )
47+ var tls apiv2.ApisixTls
48+ if err := r .Get (ctx , req .NamespacedName , & tls ); err != nil {
49+ if client .IgnoreNotFound (err ) == nil {
50+ tls .Namespace = req .Namespace
51+ tls .Name = req .Name
52+ tls .TypeMeta = metav1.TypeMeta {
53+ Kind : "ApisixTls" ,
54+ APIVersion : apiv2 .GroupVersion .String (),
55+ }
3856
39- var obj apiv2.ApisixTls
40- if err := r .Get (ctx , req .NamespacedName , & obj ); err != nil {
41- r .Log .Error (err , "failed to get ApisixConsumer" , "request" , req .NamespacedName )
57+ if err := r .Provider .Delete (ctx , & tls ); err != nil {
58+ r .Log .Error (err , "failed to delete ApisixTls" , "tls" , tls )
59+ return ctrl.Result {}, err
60+ }
61+ return ctrl.Result {}, nil
62+ }
4263 return ctrl.Result {}, err
4364 }
4465
45- obj .Status .Conditions = []metav1.Condition {
46- {
47- Type : string (gatewayv1 .RouteConditionAccepted ),
66+ var (
67+ tctx = provider .NewDefaultTranslateContext (ctx )
68+ ic * networkingv1.IngressClass
69+ err error
70+ )
71+ defer func () {
72+ r .updateStatus (& tls , err )
73+ }()
74+
75+ if ic , err = r .getIngressClass (& tls ); err != nil {
76+ return ctrl.Result {}, err
77+ }
78+ if err = r .processIngressClassParameters (ctx , tctx , & tls , ic ); err != nil {
79+ return ctrl.Result {}, err
80+ }
81+ if err = r .processApisixTls (ctx , tctx , & tls ); err != nil {
82+ return ctrl.Result {}, err
83+ }
84+ if err = r .Provider .Update (ctx , tctx , & tls ); err != nil {
85+ err = ReasonError {
86+ Reason : string (apiv2 .ConditionReasonSyncFailed ),
87+ Message : err .Error (),
88+ }
89+ r .Log .Error (err , "failed to process" , "ApisixTls" , tls )
90+ return ctrl.Result {}, err
91+ }
92+
93+ return ctrl.Result {}, nil
94+ }
95+
96+ func (r * ApisixTlsReconciler ) processApisixTls (ctx context.Context , tc * provider.TranslateContext , tls * apiv2.ApisixTls ) error {
97+ // Validate the main TLS secret
98+ if err := r .validateSecret (ctx , tc , tls .Spec .Secret ); err != nil {
99+ return ReasonError {
100+ Reason : string (apiv2 .ConditionReasonInvalidSpec ),
101+ Message : fmt .Sprintf ("invalid TLS secret: %s" , err .Error ()),
102+ }
103+ }
104+
105+ // Validate the client CA secret if mutual TLS is configured
106+ if tls .Spec .Client != nil {
107+ if err := r .validateSecret (ctx , tc , tls .Spec .Client .CASecret ); err != nil {
108+ return ReasonError {
109+ Reason : string (apiv2 .ConditionReasonInvalidSpec ),
110+ Message : fmt .Sprintf ("invalid client CA secret: %s" , err .Error ()),
111+ }
112+ }
113+ }
114+
115+ return nil
116+ }
117+
118+ func (r * ApisixTlsReconciler ) validateSecret (ctx context.Context , tc * provider.TranslateContext , secretRef apiv2.ApisixSecret ) error {
119+ secretKey := types.NamespacedName {
120+ Namespace : secretRef .Namespace ,
121+ Name : secretRef .Name ,
122+ }
123+
124+ var secret corev1.Secret
125+ if err := r .Get (ctx , secretKey , & secret ); err != nil {
126+ return fmt .Errorf ("secret %s not found: %w" , secretKey , err )
127+ }
128+
129+ tc .Secrets [secretKey ] = & secret
130+ return nil
131+ }
132+
133+ func (r * ApisixTlsReconciler ) getIngressClass (tls * apiv2.ApisixTls ) (* networkingv1.IngressClass , error ) {
134+ if tls .Spec .IngressClassName != "" {
135+ var ic networkingv1.IngressClass
136+ if err := r .Get (context .Background (), types.NamespacedName {Name : tls .Spec .IngressClassName }, & ic ); err != nil {
137+ return nil , fmt .Errorf ("ingressClass %s not found: %w" , tls .Spec .IngressClassName , err )
138+ }
139+ return & ic , nil
140+ }
141+ return r .getDefaultIngressClass ()
142+ }
143+
144+ func (r * ApisixTlsReconciler ) getDefaultIngressClass () (* networkingv1.IngressClass , error ) {
145+ var icList networkingv1.IngressClassList
146+ if err := r .List (context .Background (), & icList ); err != nil {
147+ return nil , fmt .Errorf ("failed to list IngressClasses: %w" , err )
148+ }
149+
150+ for _ , ic := range icList .Items {
151+ if ic .Annotations ["ingressclass.kubernetes.io/is-default-class" ] == "true" {
152+ return & ic , nil
153+ }
154+ }
155+
156+ return nil , fmt .Errorf ("no default IngressClass found" )
157+ }
158+
159+ func (r * ApisixTlsReconciler ) processIngressClassParameters (ctx context.Context , tc * provider.TranslateContext , tls * apiv2.ApisixTls , ingressClass * networkingv1.IngressClass ) error {
160+ // Similar to ApisixRoute controller, process IngressClass parameters if needed
161+ // For now, this is a placeholder
162+ return nil
163+ }
164+
165+ func (r * ApisixTlsReconciler ) updateStatus (tls * apiv2.ApisixTls , err error ) {
166+ var condition metav1.Condition
167+ if err != nil {
168+ if reasonErr , ok := err .(ReasonError ); ok {
169+ condition = metav1.Condition {
170+ Type : string (apiv2 .ConditionReasonAccepted ),
171+ Status : metav1 .ConditionFalse ,
172+ ObservedGeneration : tls .GetGeneration (),
173+ LastTransitionTime : metav1 .Now (),
174+ Reason : reasonErr .Reason ,
175+ Message : reasonErr .Message ,
176+ }
177+ } else {
178+ condition = metav1.Condition {
179+ Type : string (apiv2 .ConditionReasonAccepted ),
180+ Status : metav1 .ConditionFalse ,
181+ ObservedGeneration : tls .GetGeneration (),
182+ LastTransitionTime : metav1 .Now (),
183+ Reason : string (apiv2 .ConditionReasonSyncFailed ),
184+ Message : err .Error (),
185+ }
186+ }
187+ } else {
188+ condition = metav1.Condition {
189+ Type : string (apiv2 .ConditionReasonAccepted ),
48190 Status : metav1 .ConditionTrue ,
49- ObservedGeneration : obj .GetGeneration (),
191+ ObservedGeneration : tls .GetGeneration (),
50192 LastTransitionTime : metav1 .Now (),
51- Reason : string (gatewayv1 . RouteReasonAccepted ),
52- },
193+ Reason : string (apiv2 . ConditionReasonAccepted ),
194+ }
53195 }
54196
55- if err := r .Status ().Update (ctx , & obj ); err != nil {
56- r .Log .Error (err , "failed to update status" , "request" , req .NamespacedName )
57- return ctrl.Result {}, err
197+ tls .Status .Conditions = []metav1.Condition {condition }
198+
199+ if err := r .Status ().Update (context .Background (), tls ); err != nil {
200+ r .Log .Error (err , "failed to update ApisixTls status" )
58201 }
202+ }
59203
60- return ctrl.Result {}, nil
204+ func (r * ApisixTlsReconciler ) listApisixTlsForSecret (ctx context.Context , obj client.Object ) []reconcile.Request {
205+ secret , ok := obj .(* corev1.Secret )
206+ if ! ok {
207+ return nil
208+ }
209+
210+ var tlsList apiv2.ApisixTlsList
211+ if err := r .List (ctx , & tlsList ); err != nil {
212+ r .Log .Error (err , "failed to list ApisixTls" )
213+ return nil
214+ }
215+
216+ var requests []reconcile.Request
217+ for _ , tls := range tlsList .Items {
218+ // Check if this secret is referenced by the TLS resource
219+ if (tls .Spec .Secret .Namespace == secret .Namespace && tls .Spec .Secret .Name == secret .Name ) ||
220+ (tls .Spec .Client != nil && tls .Spec .Client .CASecret .Namespace == secret .Namespace && tls .Spec .Client .CASecret .Name == secret .Name ) {
221+ requests = append (requests , reconcile.Request {
222+ NamespacedName : utils .NamespacedName (& tls ),
223+ })
224+ }
225+ }
226+
227+ return requests
228+ }
229+
230+ func (r * ApisixTlsReconciler ) matchesIngressController (obj client.Object ) bool {
231+ return true // TODO: implement proper matching logic
61232}
62233
63234// SetupWithManager sets up the controller with the Manager.
64235func (r * ApisixTlsReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
65236 return ctrl .NewControllerManagedBy (mgr ).
66237 For (& apiv2.ApisixTls {}).
238+ WithEventFilter (
239+ predicate .Or (
240+ predicate.GenerationChangedPredicate {},
241+ predicate .NewPredicateFuncs (func (obj client.Object ) bool {
242+ _ , ok := obj .(* corev1.Secret )
243+ return ok
244+ }),
245+ ),
246+ ).
247+ Watches (& networkingv1.IngressClass {},
248+ handler .EnqueueRequestsFromMapFunc (r .listApisixTlsForIngressClass ),
249+ builder .WithPredicates (
250+ predicate .NewPredicateFuncs (r .matchesIngressController ),
251+ ),
252+ ).
253+ Watches (& corev1.Secret {},
254+ handler .EnqueueRequestsFromMapFunc (r .listApisixTlsForSecret ),
255+ ).
67256 Named ("apisixtls" ).
68257 Complete (r )
69258}
259+
260+ func (r * ApisixTlsReconciler ) listApisixTlsForIngressClass (ctx context.Context , obj client.Object ) []reconcile.Request {
261+ ic , ok := obj .(* networkingv1.IngressClass )
262+ if ! ok {
263+ return nil
264+ }
265+
266+ var tlsList apiv2.ApisixTlsList
267+ if err := r .List (ctx , & tlsList ); err != nil {
268+ r .Log .Error (err , "failed to list ApisixTls" )
269+ return nil
270+ }
271+
272+ var requests []reconcile.Request
273+ for _ , tls := range tlsList .Items {
274+ if tls .Spec .IngressClassName == ic .Name {
275+ requests = append (requests , reconcile.Request {
276+ NamespacedName : utils .NamespacedName (& tls ),
277+ })
278+ }
279+ }
280+
281+ return requests
282+ }
0 commit comments