Skip to content

Commit c4ce1c0

Browse files
committed
record events
1 parent 2a140ab commit c4ce1c0

File tree

3 files changed

+63
-44
lines changed

3 files changed

+63
-44
lines changed

cmd/main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,9 @@ func main() {
202202
}
203203

204204
if err = (&controller.BackupReconciler{
205-
Client: mgr.GetClient(),
206-
Scheme: mgr.GetScheme(),
205+
Client: mgr.GetClient(),
206+
Scheme: mgr.GetScheme(),
207+
Recorder: mgr.GetEventRecorderFor("backup-controller"),
207208
}).SetupWithManager(mgr); err != nil {
208209
setupLog.Error(err, "unable to create controller", "controller", "Backup")
209210
os.Exit(1)

internal/controller/backup_controller.go

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -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
2525
type 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.
3132
func (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.
201217
func (r *BackupReconciler) SetupWithManager(mgr ctrl.Manager) error {
202218
// Register VolumeSnapshotClass with the scheme

internal/controller/backup_controller_test.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@ import (
88
"time"
99

1010
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
11-
"github.com/go-logr/logr"
1211
. "github.com/onsi/ginkgo/v2"
1312
. "github.com/onsi/gomega"
1413
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1514
"k8s.io/apimachinery/pkg/runtime"
16-
ctrl "sigs.k8s.io/controller-runtime"
15+
"k8s.io/client-go/tools/record"
1716
"sigs.k8s.io/controller-runtime/pkg/client"
1817
"sigs.k8s.io/controller-runtime/pkg/client/fake"
1918

@@ -28,15 +27,15 @@ var _ = Describe("Backup Controller", func() {
2827
)
2928

3029
var (
31-
ctx context.Context
32-
scheme *runtime.Scheme
33-
logger logr.Logger
30+
ctx context.Context
31+
scheme *runtime.Scheme
32+
recorder record.EventRecorder
3433
)
3534

3635
BeforeEach(func() {
3736
ctx = context.Background()
3837
scheme = runtime.NewScheme()
39-
logger = ctrl.Log.WithName("test")
38+
recorder = record.NewFakeRecorder(10)
4039
// register both preview and CNPG types used by the controller
4140
Expect(dbpreview.AddToScheme(scheme)).To(Succeed())
4241
Expect(cnpgv1.AddToScheme(scheme)).To(Succeed())
@@ -50,8 +49,9 @@ var _ = Describe("Backup Controller", func() {
5049
Build()
5150

5251
reconciler := &BackupReconciler{
53-
Client: fakeClient,
54-
Scheme: scheme,
52+
Client: fakeClient,
53+
Scheme: scheme,
54+
Recorder: recorder,
5555
}
5656

5757
// input dbpreview Backup
@@ -66,7 +66,7 @@ var _ = Describe("Backup Controller", func() {
6666
}
6767

6868
// Call under test
69-
res, err := reconciler.createCNPGBackup(ctx, backup, logger)
69+
res, err := reconciler.createCNPGBackup(ctx, backup, nil)
7070
Expect(err).ToNot(HaveOccurred())
7171
// controller uses a 5s requeue
7272
Expect(res.RequeueAfter).To(Equal(5 * time.Second))
@@ -115,8 +115,9 @@ var _ = Describe("Backup Controller", func() {
115115
Build()
116116

117117
reconciler := &BackupReconciler{
118-
Client: fakeClient,
119-
Scheme: scheme,
118+
Client: fakeClient,
119+
Scheme: scheme,
120+
Recorder: recorder,
120121
}
121122

122123
now := time.Now().UTC()
@@ -132,7 +133,7 @@ var _ = Describe("Backup Controller", func() {
132133
},
133134
}
134135

135-
res, err := reconciler.updateBackupStatus(ctx, backup, cnpgBackup, nil, logger)
136+
res, err := reconciler.updateBackupStatus(ctx, backup, cnpgBackup, nil)
136137
Expect(err).ToNot(HaveOccurred())
137138
Expect(res.RequeueAfter).NotTo(Equal(0))
138139

@@ -168,8 +169,9 @@ var _ = Describe("Backup Controller", func() {
168169
Build()
169170

170171
reconciler := &BackupReconciler{
171-
Client: fakeClient,
172-
Scheme: scheme,
172+
Client: fakeClient,
173+
Scheme: scheme,
174+
Recorder: recorder,
173175
}
174176

175177
startTime := time.Now().UTC().Add(-10 * time.Minute)
@@ -187,7 +189,7 @@ var _ = Describe("Backup Controller", func() {
187189
},
188190
}
189191

190-
res, err := reconciler.updateBackupStatus(ctx, backup, cnpgBackup, nil, logger)
192+
res, err := reconciler.updateBackupStatus(ctx, backup, cnpgBackup, nil)
191193
Expect(err).ToNot(HaveOccurred())
192194
Expect(res.RequeueAfter).NotTo(Equal(0))
193195

@@ -238,7 +240,7 @@ var _ = Describe("Backup Controller", func() {
238240
},
239241
}
240242

241-
res, err := reconciler.updateBackupStatus(ctx, backup, cnpgBackup, nil, logger)
243+
res, err := reconciler.updateBackupStatus(ctx, backup, cnpgBackup, nil)
242244
Expect(err).ToNot(HaveOccurred())
243245
// Still in progress, requeue
244246
Expect(res.RequeueAfter).To(Equal(10 * time.Second))

0 commit comments

Comments
 (0)