@@ -22,6 +22,7 @@ import (
2222
2323 dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
2424 controllerv1alpha1 "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
25+ "github.com/devfile/devworkspace-operator/internal/images"
2526 "github.com/devfile/devworkspace-operator/pkg/conditions"
2627 "github.com/devfile/devworkspace-operator/pkg/config"
2728 "github.com/devfile/devworkspace-operator/pkg/constants"
@@ -137,11 +138,10 @@ func (r *BackupCronJobReconciler) SetupWithManager(mgr ctrl.Manager) error {
137138 Complete (r )
138139}
139140
140- // +kubebuilder:rbac:groups=batch,resources=cronjobs,verbs=get;list;create;update;patch;delete
141- // +kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list
142- // +kubebuilder:rbac:groups=controller.devfile.io,resources=devworkspaceoperatorconfigs,verbs=get;list;watch
143- // +kubebuilder:rbac:groups=workspace.devfile.io,resources=devworkspaces,verbs=get;list
144141// +kubebuilder:rbac:groups="",resources=persistentvolumeclaims,verbs=get;list
142+ // +kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;create;update;patch;delete
143+ // +kubebuilder:rbac:groups=controller.devfile.io,resources=devworkspaceoperatorconfigs,verbs=get;list;update;patch;watch
144+ // +kubebuilder:rbac:groups=workspace.devfile.io,resources=devworkspaces,verbs=get;list
145145
146146// Reconcile is the main reconciliation loop for the BackupCronJob controller.
147147func (r * BackupCronJobReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
@@ -180,7 +180,7 @@ func (r *BackupCronJobReconciler) isBackupEnabled(config *controllerv1alpha1.Dev
180180}
181181
182182// startCron starts the cron scheduler with the backup job according to the provided configuration.
183- func (r * BackupCronJobReconciler ) startCron (ctx context.Context , backUpConfig * controllerv1alpha1.BackupCronJobConfig , logger logr.Logger ) {
183+ func (r * BackupCronJobReconciler ) startCron (ctx context.Context , req ctrl. Request , backUpConfig * controllerv1alpha1.BackupCronJobConfig , logger logr.Logger ) {
184184 log := logger .WithName ("backup cron" )
185185 log .Info ("Starting backup cron scheduler" )
186186
@@ -198,7 +198,7 @@ func (r *BackupCronJobReconciler) startCron(ctx context.Context, backUpConfig *c
198198 taskLog := logger .WithName ("cronTask" )
199199
200200 taskLog .Info ("Starting DevWorkspace backup job" )
201- if err := r .executeBackupSync (ctx , logger ); err != nil {
201+ if err := r .executeBackupSync (ctx , req , backUpConfig , logger ); err != nil {
202202 taskLog .Error (err , "Failed to execute backup job for DevWorkspaces" )
203203 }
204204 taskLog .Info ("DevWorkspace backup job finished" )
@@ -231,7 +231,7 @@ func (r *BackupCronJobReconciler) stopCron(logger logr.Logger) {
231231
232232// executeBackupSync executes the backup job for all DevWorkspaces in the cluster that
233233// have been stopped in the last N minutes.
234- func (r * BackupCronJobReconciler ) executeBackupSync (ctx context.Context , logger logr.Logger ) error {
234+ func (r * BackupCronJobReconciler ) executeBackupSync (ctx context.Context , req ctrl. Request , backUpConfig * controllerv1alpha1. BackupCronJobConfig , logger logr.Logger ) error {
235235 log := logger .WithName ("executeBackupSync" )
236236 log .Info ("Executing backup sync for all DevWorkspaces" )
237237 devWorkspaces := & dw.DevWorkspaceList {}
@@ -248,7 +248,7 @@ func (r *BackupCronJobReconciler) executeBackupSync(ctx context.Context, logger
248248 dwID := dw .Status .DevWorkspaceId
249249 log .Info ("Found DevWorkspace" , "namespace" , dw .Namespace , "devworkspace" , dw .Name , "id" , dwID )
250250
251- if err := r .createBackupJob (& dw , ctx , logger ); err != nil {
251+ if err := r .createBackupJob (& dw , ctx , req , backUpConfig , logger ); err != nil {
252252 log .Error (err , "Failed to create backup Job for DevWorkspace" , "id" , dwID )
253253 continue
254254 }
@@ -285,8 +285,12 @@ func (r *BackupCronJobReconciler) wasStoppedInTimeRange(workspace *dw.DevWorkspa
285285 return false
286286}
287287
288+ func ptrInt64 (i int64 ) * int64 { return & i }
289+ func ptrInt32 (i int32 ) * int32 { return & i }
290+ func ptrBool (b bool ) * bool { return & b }
291+
288292// createBackupJob creates a Kubernetes Job to back up the workspace's PVC data.
289- func (r * BackupCronJobReconciler ) createBackupJob (workspace * dw.DevWorkspace , ctx context.Context , logger logr.Logger ) error {
293+ func (r * BackupCronJobReconciler ) createBackupJob (workspace * dw.DevWorkspace , ctx context.Context , req ctrl. Request , backUpConfig * controllerv1alpha1. BackupCronJobConfig , logger logr.Logger ) error {
290294 log := logger .WithName ("createBackupJob" )
291295 dwID := workspace .Status .DevWorkspaceId
292296
@@ -307,38 +311,47 @@ func (r *BackupCronJobReconciler) createBackupJob(workspace *dw.DevWorkspace, ct
307311 Template : corev1.PodTemplateSpec {
308312 Spec : corev1.PodSpec {
309313 RestartPolicy : corev1 .RestartPolicyNever ,
314+ SecurityContext : & corev1.PodSecurityContext {
315+ FSGroup : ptrInt64 (0 ),
316+ },
310317 Containers : []corev1.Container {
311318 {
312- Name : "backup" ,
313- Image : defaultBackupImage ,
314- Command : []string {"/bin/sh" , "-c" },
319+ Name : "backup-workspace" ,
315320 Env : []corev1.EnvVar {
316- {
317- Name : "DEVWORKSPACE_NAME" ,
318- Value : workspace .Name ,
319- },
320- {
321- Name : "DEVWORKSPACE_NAMESPACE" ,
322- Value : workspace .Namespace ,
323- },
324- {
325- Name : "WORKSPACE_ID" ,
326- Value : dwID ,
327- },
321+ {Name : "DEVWORKSPACE_NAME" , Value : workspace .Name },
322+ {Name : "DEVWORKSPACE_NAMESPACE" , Value : workspace .Namespace },
323+ {Name : "WORKSPACE_ID" , Value : dwID },
328324 {
329325 Name : "BACKUP_SOURCE_PATH" ,
330326 Value : "/workspace/" + dwID + "/" + constants .DefaultProjectsSourcesRoot ,
331327 },
328+ {Name : "STORAGE_DRIVER" , Value : "overlay" },
329+ {Name : "BUILDAH_ISOLATION" , Value : "chroot" },
330+ {Name : "DEVWORKSPACE_BACKUP_REGISTRY" , Value : backUpConfig .Registry },
331+ {Name : "BUILDAH_PUSH_OPTIONS" , Value : "--tls-verify=false" },
332332 },
333- // TODO: Replace the following command with actual backup logic
333+ Image : images .GetProjectBackupImage (),
334+ // Image: "localhost:5001/workspace-backup-image:v3",
334335 Args : []string {
335- "echo \" Starting backup for workspace $WORKSPACE_ID\" && ls -l \" $BACKUP_SOURCE_PATH\" && sleep 1 && echo Backup completed for workspace " + dwID ,
336+ "/workspace-recovery.sh" ,
337+ "--backup" ,
336338 },
337339 VolumeMounts : []corev1.VolumeMount {
338340 {
339341 MountPath : "/workspace" ,
340342 Name : "workspace-data" ,
341343 },
344+ {
345+ MountPath : "/var/lib/containers" ,
346+ Name : "build-storage" ,
347+ },
348+ },
349+ SecurityContext : & corev1.SecurityContext {
350+ RunAsUser : ptrInt64 (0 ),
351+ Capabilities : & corev1.Capabilities {
352+ Add : []corev1.Capability {"SYS_ADMIN" , "SYS_CHROOT" },
353+ },
354+ AllowPrivilegeEscalation : ptrBool (false ),
342355 },
343356 },
344357 },
@@ -351,6 +364,12 @@ func (r *BackupCronJobReconciler) createBackupJob(workspace *dw.DevWorkspace, ct
351364 },
352365 },
353366 },
367+ {
368+ Name : "build-storage" ,
369+ VolumeSource : corev1.VolumeSource {
370+ EmptyDir : & corev1.EmptyDirVolumeSource {},
371+ },
372+ },
354373 },
355374 },
356375 },
0 commit comments