@@ -18,18 +18,21 @@ package postgresql
1818
1919import (
2020 "context"
21+ "reflect"
2122 "time"
2223
2324 "github.com/go-logr/logr"
2425 "github.com/prometheus/client_golang/prometheus"
26+ "k8s.io/apimachinery/pkg/api/errors"
2527 "k8s.io/apimachinery/pkg/runtime"
2628 "k8s.io/client-go/tools/record"
2729 "sigs.k8s.io/controller-runtime/pkg/client"
30+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2831
2932 ctrl "sigs.k8s.io/controller-runtime"
30- logf "sigs.k8s.io/controller-runtime/pkg/log"
3133
3234 postgresqlv1alpha1 "github.com/easymile/postgresql-operator/api/postgresql/v1alpha1"
35+ "github.com/easymile/postgresql-operator/internal/controller/config"
3336)
3437
3538// PostgresqlBackupReconciler reconciles a PostgresqlBackup object.
@@ -57,9 +60,172 @@ type PostgresqlBackupReconciler struct {
5760// For more details, check Reconcile and its Result here:
5861// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.21.0/pkg/reconcile
5962func (r * PostgresqlBackupReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
60- _ = logf .FromContext (ctx )
63+ // Issue with this logger: controller and controllerKind are incorrect
64+ // Build another logger from upper to fix this.
65+ // reqLogger := log.FromContext(ctx)
66+ reqLogger := r .Log .WithValues ("Request.Namespace" , req .Namespace , "Request.Name" , req .Name )
67+ reqLogger .Info ("Reconciling PostgresqlBackup" )
6168
62- // TODO(user): your logic here
69+ // Fetch the PostgresqlDatabase instance
70+ instance := & postgresqlv1alpha1.PostgresqlBackup {}
71+
72+ err := r .Get (ctx , req .NamespacedName , instance )
73+ if err != nil {
74+ if errors .IsNotFound (err ) {
75+ // Request object not found, could have been deleted after reconcile request.
76+ // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
77+ // Return and don't requeue
78+ return ctrl.Result {}, nil
79+ }
80+ // Error reading the object - requeue the request.
81+ return ctrl.Result {}, err
82+ }
83+
84+ // Original patch
85+ originalPatch := client .MergeFrom (instance .DeepCopy ())
86+
87+ // Create timeout in ctx
88+ timeoutCtx , cancel := context .WithTimeout (ctx , r .ReconcileTimeout )
89+ // Defer cancel
90+ defer cancel ()
91+
92+ // Init result
93+ var res ctrl.Result
94+
95+ errC := make (chan error , 1 )
96+
97+ // Create wrapping function
98+ cb := func () {
99+ a , err := r .mainReconcile (timeoutCtx , reqLogger , instance , originalPatch )
100+ // Save result
101+ res = a
102+ // Send error
103+ errC <- err
104+ }
105+
106+ // Start wrapped function
107+ go cb ()
108+
109+ // Run or timeout
110+ select {
111+ case <- timeoutCtx .Done ():
112+ // ? Note: Here use primary context otherwise update to set error will be aborted
113+ return r .manageError (ctx , reqLogger , instance , originalPatch , timeoutCtx .Err ())
114+ case err := <- errC :
115+ return res , err
116+ }
117+ }
118+
119+ func (r * PostgresqlBackupReconciler ) mainReconcile (
120+ ctx context.Context ,
121+ reqLogger logr.Logger ,
122+ instance * postgresqlv1alpha1.PostgresqlBackup ,
123+ originalPatch client.Patch ,
124+ ) (ctrl.Result , error ) {
125+ // Deletion case
126+ if ! instance .GetDeletionTimestamp ().IsZero () {
127+ // Deletion in progress detected
128+ // TODO wait for children
129+
130+ // Remove finalizer
131+ controllerutil .RemoveFinalizer (instance , config .Finalizer )
132+ // Update CR
133+ err := r .Update (ctx , instance )
134+ if err != nil {
135+ return r .manageError (ctx , reqLogger , instance , originalPatch , err )
136+ }
137+ // Stop reconcile
138+ return ctrl.Result {}, nil
139+ }
140+
141+ // Creation case
142+
143+ // Add finalizer, owners and default values
144+ updated , err := r .updateInstance (ctx , instance )
145+ // Check error
146+ if err != nil {
147+ return r .manageError (ctx , reqLogger , instance , originalPatch , err )
148+ }
149+ // Check if it has been updated in order to stop this reconcile loop here for the moment
150+ if updated {
151+ return ctrl.Result {}, nil
152+ }
153+
154+ // Success
155+ return r .manageSuccess (ctx , reqLogger , instance , originalPatch )
156+ }
157+
158+ func (r * PostgresqlBackupReconciler ) updateInstance (
159+ ctx context.Context ,
160+ instance * postgresqlv1alpha1.PostgresqlBackup ,
161+ ) (bool , error ) {
162+ // Deep copy
163+ oCopy := instance .DeepCopy ()
164+
165+ // Add finalizer
166+ controllerutil .AddFinalizer (instance , config .Finalizer )
167+
168+ // Check if update is needed
169+ if ! reflect .DeepEqual (oCopy .ObjectMeta , instance .ObjectMeta ) {
170+ return true , r .Update (ctx , instance )
171+ }
172+
173+ return false , nil
174+ }
175+
176+ func (r * PostgresqlBackupReconciler ) manageError (
177+ ctx context.Context ,
178+ logger logr.Logger ,
179+ instance * postgresqlv1alpha1.PostgresqlBackup ,
180+ originalPatch client.Patch ,
181+ issue error ,
182+ ) (ctrl.Result , error ) {
183+ logger .Error (issue , "issue raised in reconcile" )
184+ // Add kubernetes event
185+ r .Recorder .Event (instance , "Warning" , "ProcessingError" , issue .Error ())
186+
187+ // Update status
188+ instance .Status .Message = issue .Error ()
189+ instance .Status .Ready = false
190+ instance .Status .Phase = postgresqlv1alpha1 .BackupErrorPhase
191+
192+ // Increase fail counter
193+ r .ControllerRuntimeDetailedErrorTotal .WithLabelValues (r .ControllerName , instance .Namespace , instance .Name ).Inc ()
194+
195+ // Patch status
196+ err := r .Status ().Patch (ctx , instance , originalPatch )
197+ if err != nil {
198+ logger .Error (err , "unable to update status" )
199+ }
200+
201+ // Return error
202+ return ctrl.Result {}, issue
203+ }
204+
205+ func (r * PostgresqlBackupReconciler ) manageSuccess (
206+ ctx context.Context ,
207+ logger logr.Logger ,
208+ instance * postgresqlv1alpha1.PostgresqlBackup ,
209+ originalPatch client.Patch ,
210+ ) (ctrl.Result , error ) {
211+ // Update status
212+ instance .Status .Message = ""
213+ instance .Status .Ready = true
214+ instance .Status .Phase = postgresqlv1alpha1 .BackupValidPhase
215+
216+ // Patch status
217+ err := r .Status ().Patch (ctx , instance , originalPatch )
218+ if err != nil {
219+ // Increase fail counter
220+ r .ControllerRuntimeDetailedErrorTotal .WithLabelValues (r .ControllerName , instance .Namespace , instance .Name ).Inc ()
221+
222+ logger .Error (err , "unable to update status" )
223+
224+ // Return error
225+ return ctrl.Result {}, err
226+ }
227+
228+ logger .Info ("Reconcile done" )
63229
64230 return ctrl.Result {}, nil
65231}
0 commit comments