@@ -9,11 +9,11 @@ import (
99 "time"
1010
1111 cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
12- "github.com/go-logr/logr"
1312 snapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
1413 apierrors "k8s.io/apimachinery/pkg/api/errors"
1514 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1615 "k8s.io/apimachinery/pkg/runtime"
16+ "k8s.io/client-go/tools/record"
1717 ctrl "sigs.k8s.io/controller-runtime"
1818 "sigs.k8s.io/controller-runtime/pkg/client"
1919 "sigs.k8s.io/controller-runtime/pkg/log"
@@ -24,12 +24,13 @@ import (
2424// BackupReconciler reconciles a Backup object
2525type BackupReconciler struct {
2626 client.Client
27- Scheme * runtime.Scheme
27+ Scheme * runtime.Scheme
28+ Recorder record.EventRecorder
2829}
2930
3031// Reconcile handles the reconciliation loop for Backup resources.
3132func (r * BackupReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
32- logger := log .FromContext (ctx , "namespace" , req . NamespacedName . Namespace , "backupName" , req . NamespacedName . Name )
33+ logger := log .FromContext (ctx )
3334
3435 // Fetch the Backup resource
3536 backup := & dbpreview.Backup {}
@@ -44,12 +45,17 @@ func (r *BackupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
4445
4546 // Delete the Backup resource if it has expired
4647 if backup .Status .IsExpired () {
47- logger . Info ( " Backup has expired, deleting it " )
48+ r . Recorder . Event ( backup , "Normal" , "BackupExpired" , " Backup has expired and will be deleted " )
4849 if err := r .Delete (ctx , backup ); err != nil {
49- logger . Error ( err , "Failed to delete expired Backup" )
50+ r . Recorder . Event ( backup , "Warning" , "BackupDeleteFailed" , " Failed to delete expired Backup: " + err . Error () )
5051 return ctrl.Result {}, err
5152 }
52- logger .Info ("Successfully deleted expired Backup" )
53+ r .Recorder .Event (backup , "Normal" , "BackupDeleted" , "Expired Backup has been deleted" )
54+ return ctrl.Result {}, nil
55+ }
56+
57+ // No further action needed for completed backups
58+ if backup .Status .IsDone () {
5359 return ctrl.Result {}, nil
5460 }
5561
@@ -60,18 +66,12 @@ func (r *BackupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
6066 Namespace : backup .Namespace ,
6167 }
6268 if err := r .Get (ctx , clusterKey , cluster ); err != nil {
63- logger .Error (err , "Failed to get cluster for Backup" , "clusterName" , backup .Spec .Cluster .Name )
64- return ctrl.Result {}, err
69+ return r .SetBackupPhaseFailed (ctx , backup , "Failed to get associated DocumentDB cluster: " + err .Error (), nil )
6570 }
6671
6772 // Ensure VolumeSnapshotClass exists
6873 if err := r .ensureVolumeSnapshotClass (ctx , cluster .Spec .Environment ); err != nil {
69- backup .Status .Error = "Failed to ensure VolumeSnapshotClass: " + err .Error ()
70- backup .Status .Phase = cnpgv1 .BackupPhaseFailed
71- if updateErr := r .Status ().Update (ctx , backup ); updateErr != nil {
72- return ctrl.Result {}, updateErr
73- }
74- return ctrl.Result {}, err
74+ return r .SetBackupPhaseFailed (ctx , backup , "Failed to ensure VolumeSnapshotClass: " + err .Error (), cluster .Spec .Backup )
7575 }
7676
7777 // Get or create the CNPG Backup
@@ -82,15 +82,14 @@ func (r *BackupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
8282 }
8383 if err := r .Get (ctx , cnpgBackupKey , cnpgBackup ); err != nil {
8484 if apierrors .IsNotFound (err ) {
85- logger .Info ("Creating new CNPG Backup for DocumentDB Backup" )
86- return r .createCNPGBackup (ctx , backup , logger )
85+ return r .createCNPGBackup (ctx , backup , cluster .Spec .Backup )
8786 }
8887 logger .Error (err , "Failed to get CNPG Backup" )
8988 return ctrl.Result {}, err
9089 }
9190
9291 // Update status based on CNPG Backup status
93- return r .updateBackupStatus (ctx , backup , cnpgBackup , cluster .Spec .Backup , logger )
92+ return r .updateBackupStatus (ctx , backup , cnpgBackup , cluster .Spec .Backup )
9493}
9594
9695// ensureVolumeSnapshotClass creates a VolumeSnapshotClass based on the cloud environment
@@ -110,7 +109,7 @@ func (r *BackupReconciler) ensureVolumeSnapshotClass(ctx context.Context, enviro
110109 }
111110 }
112111
113- logger . Info ( " No default VolumeSnapshotClass found, will create one" )
112+ r . Recorder . Event ( nil , "Normal" , "VolumeSnapshotClass" , " No default VolumeSnapshotClass found, creating one" )
114113 vsc := buildVolumeSnapshotClass (environment )
115114 if vsc == nil {
116115 err := fmt .Errorf ("Please create a default VolumeSnapshotClass before creating backups" )
@@ -123,7 +122,7 @@ func (r *BackupReconciler) ensureVolumeSnapshotClass(ctx context.Context, enviro
123122 return err
124123 }
125124
126- logger . Info ( "Successfully created VolumeSnapshotClass" , "name " , vsc . Name , "driver " , vsc .Driver )
125+ r . Recorder . Event ( nil , "Normal " , "VolumeSnapshotClass " , "Successfully created VolumeSnapshotClass " + vsc .Name )
127126 return nil
128127}
129128
@@ -156,30 +155,30 @@ func buildVolumeSnapshotClass(environment string) *snapshotv1.VolumeSnapshotClas
156155}
157156
158157// createCNPGBackup creates a new CNPG Backup resource
159- func (r * BackupReconciler ) createCNPGBackup (ctx context.Context , backup * dbpreview.Backup , logger logr. Logger ) (ctrl.Result , error ) {
158+ func (r * BackupReconciler ) createCNPGBackup (ctx context.Context , backup * dbpreview.Backup , backupConfiguration * dbpreview. BackupConfiguration ) (ctrl.Result , error ) {
160159 cnpgBackup , err := backup .CreateCNPGBackup (r .Scheme )
161160 if err != nil {
162- logger .Error (err , "Failed to build CNPG Backup" )
163- return ctrl.Result {}, err
161+ return r .SetBackupPhaseFailed (ctx , backup , "Failed to initialize backup: " + err .Error (), backupConfiguration )
164162 }
165163
166164 if err := r .Create (ctx , cnpgBackup ); err != nil {
167- logger .Error (err , "Failed to create CNPG Backup" )
168- return ctrl.Result {}, err
165+ return r .SetBackupPhaseFailed (ctx , backup , "Failed to initialize backup: " + err .Error (), backupConfiguration )
169166 }
170- logger .Info ("Successfully created CNPG Backup" , "name" , cnpgBackup .Name )
167+
168+ r .Recorder .Event (backup , "Normal" , "BackupInitialized" , "Successfully initialized backup" )
171169
172170 // Requeue to check status
173171 return ctrl.Result {RequeueAfter : 5 * time .Second }, nil
174172}
175173
176174// updateBackupStatus updates the Backup status based on CNPG Backup status
177- func (r * BackupReconciler ) updateBackupStatus (ctx context.Context , backup * dbpreview.Backup , cnpgBackup * cnpgv1.Backup , backupConfiguration * dbpreview.BackupConfiguration , logger logr. Logger ) (ctrl.Result , error ) {
175+ func (r * BackupReconciler ) updateBackupStatus (ctx context.Context , backup * dbpreview.Backup , cnpgBackup * cnpgv1.Backup , backupConfiguration * dbpreview.BackupConfiguration ) (ctrl.Result , error ) {
178176 original := backup .DeepCopy ()
179177 needsUpdate := backup .UpdateStatus (cnpgBackup , backupConfiguration )
180178
181179 if needsUpdate {
182180 if err := r .Status ().Patch (ctx , backup , client .MergeFrom (original )); err != nil {
181+ logger := log .FromContext (ctx )
183182 logger .Error (err , "Failed to patch Backup status" )
184183 return ctrl.Result {}, err
185184 }
@@ -197,6 +196,23 @@ func (r *BackupReconciler) updateBackupStatus(ctx context.Context, backup *dbpre
197196 return ctrl.Result {RequeueAfter : 10 * time .Second }, nil
198197}
199198
199+ func (r * BackupReconciler ) SetBackupPhaseFailed (ctx context.Context , backup * dbpreview.Backup , errMessage string , backupConfiguration * dbpreview.BackupConfiguration ) (ctrl.Result , error ) {
200+ original := backup .DeepCopy ()
201+
202+ backup .Status .Phase = cnpgv1 .BackupPhaseFailed
203+ backup .Status .Error = errMessage
204+ backup .Status .ExpiredAt = backup .CalculateExpirationTime (backupConfiguration )
205+
206+ if err := r .Status ().Patch (ctx , backup , client .MergeFrom (original )); err != nil {
207+ logger := log .FromContext (ctx )
208+ logger .Error (err , "Failed to patch Backup status" )
209+ return ctrl.Result {}, err
210+ }
211+
212+ r .Recorder .Event (backup , "Warning" , "BackupFailed" , errMessage )
213+ return ctrl.Result {}, nil
214+ }
215+
200216// SetupWithManager sets up the controller with the Manager.
201217func (r * BackupReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
202218 // Register VolumeSnapshotClass with the scheme
0 commit comments