@@ -48,8 +48,9 @@ const (
4848// BackupCronJobReconciler reconciles `BackupCronJob` configuration for the purpose of backing up workspace PVCs.
4949type BackupCronJobReconciler struct {
5050 client.Client
51- Log logr.Logger
52- Scheme * runtime.Scheme
51+ NonCachingClient client.Client
52+ Log logr.Logger
53+ Scheme * runtime.Scheme
5354
5455 cron * cron.Cron
5556}
@@ -94,6 +95,12 @@ func shouldReconcileOnUpdate(e event.UpdateEvent, log logr.Logger) bool {
9495 if oldBackup .Schedule != newBackup .Schedule {
9596 return true
9697 }
98+ if oldBackup .Registry != newBackup .Registry {
99+ return true
100+ }
101+ if oldBackup .RegistryAuthSecret != newBackup .RegistryAuthSecret {
102+ return true
103+ }
97104
98105 return false
99106}
@@ -139,6 +146,7 @@ func (r *BackupCronJobReconciler) SetupWithManager(mgr ctrl.Manager) error {
139146 Complete (r )
140147}
141148
149+ // +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;create;update;patch;delete
142150// +kubebuilder:rbac:groups="",resources=persistentvolumeclaims,verbs=get;list
143151// +kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;create;update;patch;delete
144152// +kubebuilder:rbac:groups=controller.devfile.io,resources=devworkspaceoperatorconfigs,verbs=get;list;update;patch;watch
@@ -235,8 +243,14 @@ func (r *BackupCronJobReconciler) stopCron(logger logr.Logger) {
235243func (r * BackupCronJobReconciler ) executeBackupSync (ctx context.Context , dwOperatorConfig * controllerv1alpha1.DevWorkspaceOperatorConfig , logger logr.Logger ) error {
236244 log := logger .WithName ("executeBackupSync" )
237245 log .Info ("Executing backup sync for all DevWorkspaces" )
246+
247+ registyAuthSecret , err := r .getRegistryAuthSecret (ctx , dwOperatorConfig , logger )
248+ if err != nil {
249+ log .Error (err , "Failed to get registry auth secret for backup job" )
250+ return err
251+ }
238252 devWorkspaces := & dw.DevWorkspaceList {}
239- err : = r .List (ctx , devWorkspaces )
253+ err = r .List (ctx , devWorkspaces )
240254 if err != nil {
241255 log .Error (err , "Failed to list DevWorkspaces" )
242256 return err
@@ -253,7 +267,7 @@ func (r *BackupCronJobReconciler) executeBackupSync(ctx context.Context, dwOpera
253267 dwID := dw .Status .DevWorkspaceId
254268 log .Info ("Found DevWorkspace" , "namespace" , dw .Namespace , "devworkspace" , dw .Name , "id" , dwID )
255269
256- if err := r .createBackupJob (& dw , ctx , dwOperatorConfig , logger ); err != nil {
270+ if err := r .createBackupJob (& dw , ctx , dwOperatorConfig , registyAuthSecret , logger ); err != nil {
257271 log .Error (err , "Failed to create backup Job for DevWorkspace" , "id" , dwID )
258272 continue
259273 }
@@ -274,6 +288,24 @@ func (r *BackupCronJobReconciler) executeBackupSync(ctx context.Context, dwOpera
274288 return nil
275289}
276290
291+ func (r * BackupCronJobReconciler ) getRegistryAuthSecret (ctx context.Context , dwOperatorConfig * controllerv1alpha1.DevWorkspaceOperatorConfig , logger logr.Logger ) (* corev1.Secret , error ) {
292+ log := logger .WithName ("getRegistryAuthSecret" )
293+ registryAuthSecret := & corev1.Secret {}
294+ if dwOperatorConfig .Config .Workspace .BackupCronJob .RegistryAuthSecret != "" {
295+ err := r .NonCachingClient .Get (ctx , client.ObjectKey {
296+ Name : dwOperatorConfig .Config .Workspace .BackupCronJob .RegistryAuthSecret ,
297+ Namespace : dwOperatorConfig .Namespace ,
298+ }, registryAuthSecret )
299+ if err != nil {
300+ log .Error (err , "Failed to get registry auth secret for backup job" , "secretName" , dwOperatorConfig .Config .Workspace .BackupCronJob .RegistryAuthSecret )
301+ return nil , err
302+ }
303+ log .Info ("Successfully retrieved registry auth secret for backup job" , "secretName" , dwOperatorConfig .Config .Workspace .BackupCronJob .RegistryAuthSecret )
304+ return registryAuthSecret , nil
305+ }
306+ return nil , nil
307+ }
308+
277309// wasStoppedSinceLastBackup checks if the DevWorkspace was stopped since the last backup time.
278310func (r * BackupCronJobReconciler ) wasStoppedSinceLastBackup (workspace * dw.DevWorkspace , lastBackupTime * metav1.Time , logger logr.Logger ) bool {
279311 log := logger .WithName ("wasStoppedSinceLastBackup" )
@@ -308,7 +340,13 @@ func ptrInt32(i int32) *int32 { return &i }
308340func ptrBool (b bool ) * bool { return & b }
309341
310342// createBackupJob creates a Kubernetes Job to back up the workspace's PVC data.
311- func (r * BackupCronJobReconciler ) createBackupJob (workspace * dw.DevWorkspace , ctx context.Context , dwOperatorConfig * controllerv1alpha1.DevWorkspaceOperatorConfig , logger logr.Logger ) error {
343+ func (r * BackupCronJobReconciler ) createBackupJob (
344+ workspace * dw.DevWorkspace ,
345+ ctx context.Context ,
346+ dwOperatorConfig * controllerv1alpha1.DevWorkspaceOperatorConfig ,
347+ registyAuthSecret * corev1.Secret ,
348+ logger logr.Logger ,
349+ ) error {
312350 log := logger .WithName ("createBackupJob" )
313351 dwID := workspace .Status .DevWorkspaceId
314352 backUpConfig := dwOperatorConfig .Config .Workspace .BackupCronJob
@@ -358,7 +396,6 @@ func (r *BackupCronJobReconciler) createBackupJob(workspace *dw.DevWorkspace, ct
358396 {Name : "BUILDAH_PUSH_OPTIONS" , Value : "--tls-verify=false" },
359397 },
360398 Image : images .GetProjectBackupImage (),
361- // Image: "localhost:5001/workspace-backup-image:v3",
362399 Args : []string {
363400 "/workspace-recovery.sh" ,
364401 "--backup" ,
@@ -402,6 +439,30 @@ func (r *BackupCronJobReconciler) createBackupJob(workspace *dw.DevWorkspace, ct
402439 },
403440 },
404441 }
442+ if registyAuthSecret != nil {
443+ secret , err := r .copySecret (workspace , ctx , registyAuthSecret , logger )
444+ if err != nil {
445+ return err
446+ }
447+ job .Spec .Template .Spec .Volumes = append (job .Spec .Template .Spec .Volumes , corev1.Volume {
448+ Name : "registry-auth-secret" ,
449+ VolumeSource : corev1.VolumeSource {
450+ Secret : & corev1.SecretVolumeSource {
451+ SecretName : secret .Name ,
452+ },
453+ },
454+ })
455+ job .Spec .Template .Spec .Containers [0 ].VolumeMounts = append (job .Spec .Template .Spec .Containers [0 ].VolumeMounts , corev1.VolumeMount {
456+ Name : "registry-auth-secret" ,
457+ MountPath : "/home/user/.docker" ,
458+ ReadOnly : true ,
459+ })
460+ job .Spec .Template .Spec .Containers [0 ].Env = append (job .Spec .Template .Spec .Containers [0 ].Env , corev1.EnvVar {
461+ Name : "REGISTRY_AUTH_FILE" ,
462+ Value : "/home/user/.docker/.dockerconfigjson" ,
463+ })
464+
465+ }
405466 if err := controllerutil .SetControllerReference (workspace , job , r .Scheme ); err != nil {
406467 return err
407468 }
@@ -413,3 +474,40 @@ func (r *BackupCronJobReconciler) createBackupJob(workspace *dw.DevWorkspace, ct
413474 log .Info ("Created backup Job for DevWorkspace" , "jobName" , job .Name , "devworkspace" , workspace .Name )
414475 return nil
415476}
477+
478+ func (r * BackupCronJobReconciler ) copySecret (workspace * dw.DevWorkspace , ctx context.Context , sourceSecret * corev1.Secret , logger logr.Logger ) (namespaceSecret * corev1.Secret , err error ) {
479+ log := logger .WithName ("copySecret" )
480+ existingNamespaceSecret := & corev1.Secret {}
481+ err = r .NonCachingClient .Get (ctx , client.ObjectKey {
482+ Name : constants .DevWorkspaceBackuptAuthSecretName ,
483+ Namespace : workspace .Namespace }, existingNamespaceSecret )
484+ if client .IgnoreNotFound (err ) != nil {
485+ log .Error (err , "Failed to check for existing registry auth secret in workspace namespace" , "namespace" , workspace .Namespace )
486+ return nil , err
487+ }
488+ if err == nil {
489+ log .Info ("Deleting existing registry auth secret in workspace namespace" , "namespace" , workspace .Namespace )
490+ err = r .Delete (ctx , existingNamespaceSecret )
491+ if err != nil {
492+ return nil , err
493+ }
494+ log .Info ("Successfully deleted existing registry auth secret in workspace namespace" , "namespace" , workspace .Namespace )
495+ }
496+ namespaceSecret = & corev1.Secret {
497+ ObjectMeta : metav1.ObjectMeta {
498+ Name : constants .DevWorkspaceBackuptAuthSecretName ,
499+ Namespace : workspace .Namespace ,
500+ Labels : map [string ]string {
501+ constants .DevWorkspaceIDLabel : workspace .Status .DevWorkspaceId ,
502+ constants .DevWorkspaceWatchSecretLabel : "true" ,
503+ },
504+ },
505+ Data : sourceSecret .Data ,
506+ Type : sourceSecret .Type ,
507+ }
508+ if err := controllerutil .SetControllerReference (workspace , namespaceSecret , r .Scheme ); err != nil {
509+ return nil , err
510+ }
511+ err = r .Create (ctx , namespaceSecret )
512+ return namespaceSecret , err
513+ }
0 commit comments