@@ -18,6 +18,7 @@ package controllers
1818import (
1919 "context"
2020
21+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2122 "sigs.k8s.io/controller-runtime/pkg/reconcile"
2223
2324 dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
@@ -180,7 +181,7 @@ func (r *BackupCronJobReconciler) isBackupEnabled(config *controllerv1alpha1.Dev
180181}
181182
182183// startCron starts the cron scheduler with the backup job according to the provided configuration.
183- func (r * BackupCronJobReconciler ) startCron (ctx context.Context , req ctrl. Request , backUpConfig * controllerv1alpha1.BackupCronJobConfig , logger logr.Logger ) {
184+ func (r * BackupCronJobReconciler ) startCron (ctx context.Context , dwOperatorConfig * controllerv1alpha1.DevWorkspaceOperatorConfig , logger logr.Logger ) {
184185 log := logger .WithName ("backup cron" )
185186 log .Info ("Starting backup cron scheduler" )
186187
@@ -193,12 +194,13 @@ func (r *BackupCronJobReconciler) startCron(ctx context.Context, req ctrl.Reques
193194 }
194195
195196 // add cronjob task
197+ backUpConfig := dwOperatorConfig .Config .Workspace .BackupCronJob
196198 log .Info ("Adding cronjob task" , "schedule" , backUpConfig .Schedule )
197199 _ , err := r .cron .AddFunc (backUpConfig .Schedule , func () {
198200 taskLog := logger .WithName ("cronTask" )
199201
200202 taskLog .Info ("Starting DevWorkspace backup job" )
201- if err := r .executeBackupSync (ctx , req , backUpConfig , logger ); err != nil {
203+ if err := r .executeBackupSync (ctx , dwOperatorConfig , logger ); err != nil {
202204 taskLog .Error (err , "Failed to execute backup job for DevWorkspaces" )
203205 }
204206 taskLog .Info ("DevWorkspace backup job finished" )
@@ -224,43 +226,54 @@ func (r *BackupCronJobReconciler) stopCron(logger logr.Logger) {
224226 }
225227
226228 ctx := r .cron .Stop ()
227- ctx .Done ()
229+ <- ctx .Done ()
228230
229231 log .Info ("Cron scheduler stopped" )
230232}
231233
232234// executeBackupSync executes the backup job for all DevWorkspaces in the cluster that
233235// have been stopped in the last N minutes.
234- func (r * BackupCronJobReconciler ) executeBackupSync (ctx context.Context , req ctrl. Request , backUpConfig * controllerv1alpha1.BackupCronJobConfig , logger logr.Logger ) error {
236+ func (r * BackupCronJobReconciler ) executeBackupSync (ctx context.Context , dwOperatorConfig * controllerv1alpha1.DevWorkspaceOperatorConfig , logger logr.Logger ) error {
235237 log := logger .WithName ("executeBackupSync" )
236238 log .Info ("Executing backup sync for all DevWorkspaces" )
239+ backUpConfig := dwOperatorConfig .Config .Workspace .BackupCronJob
237240 devWorkspaces := & dw.DevWorkspaceList {}
238241 err := r .List (ctx , devWorkspaces )
239242 if err != nil {
240243 log .Error (err , "Failed to list DevWorkspaces" )
241244 return err
242245 }
246+ lastBackupTime := dwOperatorConfig .Status .LastBackupTime
243247 for _ , dw := range devWorkspaces .Items {
244- if ! r .wasStoppedInTimeRange (& dw , 30 , ctx , logger ) {
248+ if ! r .wasStoppedSinceLastBackup (& dw , lastBackupTime , ctx , logger ) {
245249 log .Info ("Skipping backup for DevWorkspace that wasn't stopped recently" , "namespace" , dw .Namespace , "name" , dw .Name )
246250 continue
247251 }
248252 dwID := dw .Status .DevWorkspaceId
249253 log .Info ("Found DevWorkspace" , "namespace" , dw .Namespace , "devworkspace" , dw .Name , "id" , dwID )
250254
251- if err := r .createBackupJob (& dw , ctx , req , backUpConfig , logger ); err != nil {
255+ if err := r .createBackupJob (& dw , ctx , backUpConfig , logger ); err != nil {
252256 log .Error (err , "Failed to create backup Job for DevWorkspace" , "id" , dwID )
253257 continue
254258 }
255259 log .Info ("Backup Job created for DevWorkspace" , "id" , dwID )
256260
257261 }
262+ if dwOperatorConfig .Status == nil {
263+ dwOperatorConfig .Status = & controllerv1alpha1.OperatorConfigurationStatus {}
264+ }
265+ dwOperatorConfig .Status .LastBackupTime = & metav1.Time {Time : metav1 .Now ().Time }
266+ err = r .Status ().Update (ctx , dwOperatorConfig )
267+ if err != nil {
268+ log .Error (err , "Failed to update DevWorkspaceOperatorConfig status with last backup time" )
269+ // Not returning error as the backup jobs were created successfully
270+ }
258271 return nil
259272}
260273
261- // wasStoppedInTimeRange checks if the DevWorkspace was stopped in the last N minutes .
262- func (r * BackupCronJobReconciler ) wasStoppedInTimeRange (workspace * dw.DevWorkspace , timeRangeInMinute float64 , ctx context. Context , logger logr.Logger ) bool {
263- log := logger .WithName ("wasStoppedInTimeRange " )
274+ // wasStoppedSinceLastBackup checks if the DevWorkspace was stopped since the last backup time .
275+ func (r * BackupCronJobReconciler ) wasStoppedSinceLastBackup (workspace * dw.DevWorkspace , lastBackupTime * metav1. Time , logger logr.Logger ) bool {
276+ log := logger .WithName ("wasStoppedSinceLastBackup " )
264277 if workspace .Status .Phase != dw .DevWorkspaceStatusStopped {
265278 return false
266279 }
@@ -273,11 +286,13 @@ func (r *BackupCronJobReconciler) wasStoppedInTimeRange(workspace *dw.DevWorkspa
273286 lastTimeStopped = condition .LastTransitionTime
274287 }
275288 }
276- // Calculate the time difference
277289 if ! lastTimeStopped .IsZero () {
278- timeDiff := metav1 .Now ().Sub (lastTimeStopped .Time )
279- if timeDiff .Minutes () <= timeRangeInMinute {
280- log .Info ("DevWorkspace was stopped recently" , "namespace" , workspace .Namespace , "name" , workspace .Name )
290+ if lastBackupTime == nil {
291+ // No previous backup, so consider it stopped since last backup
292+ return true
293+ }
294+ if lastTimeStopped .Time .After (lastBackupTime .Time ) {
295+ log .Info ("DevWorkspace was stopped since last backup" , "namespace" , workspace .Namespace , "name" , workspace .Name )
281296 return true
282297 }
283298 }
@@ -290,7 +305,7 @@ func ptrInt32(i int32) *int32 { return &i }
290305func ptrBool (b bool ) * bool { return & b }
291306
292307// createBackupJob creates a Kubernetes Job to back up the workspace's PVC data.
293- func (r * BackupCronJobReconciler ) createBackupJob (workspace * dw.DevWorkspace , ctx context.Context , req ctrl. Request , backUpConfig * controllerv1alpha1.BackupCronJobConfig , logger logr.Logger ) error {
308+ func (r * BackupCronJobReconciler ) createBackupJob (workspace * dw.DevWorkspace , ctx context.Context , backUpConfig * controllerv1alpha1.BackupCronJobConfig , logger logr.Logger ) error {
294309 log := logger .WithName ("createBackupJob" )
295310 dwID := workspace .Status .DevWorkspaceId
296311
@@ -304,8 +319,12 @@ func (r *BackupCronJobReconciler) createBackupJob(workspace *dw.DevWorkspace, ct
304319
305320 job := & batchv1.Job {
306321 ObjectMeta : metav1.ObjectMeta {
307- GenerateName : "backup-job-" ,
322+ GenerateName : constants . DevWorkspaceBackupJobNamePrefix ,
308323 Namespace : workspace .Namespace ,
324+ Labels : map [string ]string {
325+ constants .DevWorkspaceIDLabel : dwID ,
326+ constants .DevWorkspaceBackupJobLabel : "true" ,
327+ },
309328 },
310329 Spec : batchv1.JobSpec {
311330 Template : corev1.PodTemplateSpec {
@@ -375,6 +394,9 @@ func (r *BackupCronJobReconciler) createBackupJob(workspace *dw.DevWorkspace, ct
375394 },
376395 },
377396 }
397+ if err := controllerutil .SetControllerReference (workspace , job , r .Scheme ); err != nil {
398+ return err
399+ }
378400 err = r .Create (ctx , job )
379401 if err != nil {
380402 log .Error (err , "Failed to create backup Job for DevWorkspace" , "devworkspace" , workspace .Name )
0 commit comments