Skip to content

Commit f083043

Browse files
committed
Use namespace auth pull secret
Instead of using global secret for a whole cluster the controller search for namespace specific secret and use it if available. If not found it fallback to the global secret. Signed-off-by: Ales Raszka <[email protected]>
1 parent 142a502 commit f083043

File tree

4 files changed

+101
-36
lines changed

4 files changed

+101
-36
lines changed

apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ type RegistryConfig struct {
7979
Path string `json:"path,omitempty"`
8080
// AuthSecret is the name of a Kubernetes secret of
8181
// type kubernetes.io/dockerconfigjson.
82-
// The secret is expected to be in the same namespace
82+
// The secret is expected to be in the same namespace the workspace is running in.
83+
// If secret is not found in the workspace namespace, the operator will look for the secret
84+
// in the namespace where the operator is running in.
8385
// as the DevWorkspaceOperatorCongfig.
8486
// +kubebuilder:validation:Optional
8587
AuthSecret string `json:"authSecret,omitempty"`

controllers/backupcronjob/backupcronjob_controller.go

Lines changed: 53 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,8 @@ func (r *BackupCronJobReconciler) stopCron(log logr.Logger) {
210210
func (r *BackupCronJobReconciler) executeBackupSync(ctx context.Context, dwOperatorConfig *controllerv1alpha1.DevWorkspaceOperatorConfig, log logr.Logger) error {
211211
log.Info("Executing backup sync for all DevWorkspaces")
212212

213-
registryAuthSecret, err := r.getRegistryAuthSecret(ctx, dwOperatorConfig, log)
214-
if err != nil {
215-
log.Error(err, "Failed to get registry auth secret for backup job")
216-
return err
217-
}
218213
devWorkspaces := &dw.DevWorkspaceList{}
219-
err = r.List(ctx, devWorkspaces)
214+
err := r.List(ctx, devWorkspaces)
220215
if err != nil {
221216
log.Error(err, "Failed to list DevWorkspaces")
222217
return err
@@ -239,7 +234,7 @@ func (r *BackupCronJobReconciler) executeBackupSync(ctx context.Context, dwOpera
239234
continue
240235
}
241236

242-
if err := r.createBackupJob(&dw, ctx, dwOperatorConfig, registryAuthSecret, log); err != nil {
237+
if err = r.createBackupJob(&dw, ctx, dwOperatorConfig, log); err != nil {
243238
log.Error(err, "Failed to create backup Job for DevWorkspace", "id", dwID)
244239
continue
245240
}
@@ -260,23 +255,6 @@ func (r *BackupCronJobReconciler) executeBackupSync(ctx context.Context, dwOpera
260255
return nil
261256
}
262257

263-
func (r *BackupCronJobReconciler) getRegistryAuthSecret(ctx context.Context, dwOperatorConfig *controllerv1alpha1.DevWorkspaceOperatorConfig, log logr.Logger) (*corev1.Secret, error) {
264-
registryAuthSecret := &corev1.Secret{}
265-
if dwOperatorConfig.Config.Workspace.BackupCronJob.Registry.AuthSecret != "" {
266-
err := r.NonCachingClient.Get(ctx, client.ObjectKey{
267-
Name: dwOperatorConfig.Config.Workspace.BackupCronJob.Registry.AuthSecret,
268-
Namespace: dwOperatorConfig.Namespace,
269-
}, registryAuthSecret)
270-
if err != nil {
271-
log.Error(err, "Failed to get registry auth secret for backup job", "secretName", dwOperatorConfig.Config.Workspace.BackupCronJob.Registry.AuthSecret)
272-
return nil, err
273-
}
274-
log.Info("Successfully retrieved registry auth secret for backup job", "secretName", dwOperatorConfig.Config.Workspace.BackupCronJob.Registry.AuthSecret)
275-
return registryAuthSecret, nil
276-
}
277-
return nil, nil
278-
}
279-
280258
// wasStoppedSinceLastBackup checks if the DevWorkspace was stopped since the last backup time.
281259
func (r *BackupCronJobReconciler) wasStoppedSinceLastBackup(workspace *dw.DevWorkspace, lastBackupTime *metav1.Time, log logr.Logger) bool {
282260
if workspace.Status.Phase != dw.DevWorkspaceStatusStopped {
@@ -310,12 +288,17 @@ func (r *BackupCronJobReconciler) createBackupJob(
310288
workspace *dw.DevWorkspace,
311289
ctx context.Context,
312290
dwOperatorConfig *controllerv1alpha1.DevWorkspaceOperatorConfig,
313-
registryAuthSecret *corev1.Secret,
314291
log logr.Logger,
315292
) error {
316293
dwID := workspace.Status.DevWorkspaceId
317294
backUpConfig := dwOperatorConfig.Config.Workspace.BackupCronJob
318295

296+
registryAuthSecret, err := r.handleRegistryAuthSecret(workspace, ctx, dwOperatorConfig, log)
297+
if err != nil {
298+
log.Error(err, "Failed to handle registry auth secret for DevWorkspace", "devworkspace", workspace.Name)
299+
return err
300+
}
301+
319302
// Find a PVC with the name "claim-devworkspace" or based on the name from the operator config
320303
pvcName, workspacePath, err := r.getWorkspacePVCName(workspace, dwOperatorConfig, ctx, log)
321304
if err != nil {
@@ -413,15 +396,11 @@ func (r *BackupCronJobReconciler) createBackupJob(
413396
},
414397
}
415398
if registryAuthSecret != nil {
416-
secret, err := r.copySecret(workspace, ctx, registryAuthSecret, log)
417-
if err != nil {
418-
return err
419-
}
420399
job.Spec.Template.Spec.Volumes = append(job.Spec.Template.Spec.Volumes, corev1.Volume{
421400
Name: "registry-auth-secret",
422401
VolumeSource: corev1.VolumeSource{
423402
Secret: &corev1.SecretVolumeSource{
424-
SecretName: secret.Name,
403+
SecretName: registryAuthSecret.Name,
425404
},
426405
},
427406
})
@@ -474,6 +453,47 @@ func (r *BackupCronJobReconciler) getWorkspacePVCName(workspace *dw.DevWorkspace
474453
return "", "", nil
475454
}
476455

456+
func (r *BackupCronJobReconciler) handleRegistryAuthSecret(workspace *dw.DevWorkspace,
457+
ctx context.Context,
458+
dwOperatorConfig *controllerv1alpha1.DevWorkspaceOperatorConfig, log logr.Logger,
459+
) (*corev1.Secret, error) {
460+
if dwOperatorConfig.Config.Workspace.BackupCronJob.Registry.AuthSecret == "" {
461+
// No auth secret configured - anonymous access to registry
462+
return nil, nil
463+
}
464+
secretName := dwOperatorConfig.Config.Workspace.BackupCronJob.Registry.AuthSecret
465+
466+
// First check the workspace namespace for the secret
467+
registryAuthSecret := &corev1.Secret{}
468+
err := r.NonCachingClient.Get(ctx, client.ObjectKey{
469+
Name: secretName,
470+
Namespace: workspace.Namespace}, registryAuthSecret)
471+
if err == nil {
472+
log.Info("Successfully retrieved registry auth secret for backup from workspace namespace", "secretName", secretName)
473+
return registryAuthSecret, nil
474+
}
475+
if client.IgnoreNotFound(err) != nil {
476+
return nil, err
477+
}
478+
479+
log.Info("Registry auth secret not found in workspace namespace, checking operator namespace", "secretName", secretName)
480+
481+
// If the secret is not found in the workspace namespace, check the operator namespace as fallback
482+
if dwOperatorConfig.Config.Workspace.BackupCronJob.Registry.AuthSecret != "" {
483+
err := r.NonCachingClient.Get(ctx, client.ObjectKey{
484+
Name: dwOperatorConfig.Config.Workspace.BackupCronJob.Registry.AuthSecret,
485+
Namespace: dwOperatorConfig.Namespace,
486+
}, registryAuthSecret)
487+
if err != nil {
488+
log.Error(err, "Failed to get registry auth secret for backup job", "secretName", dwOperatorConfig.Config.Workspace.BackupCronJob.Registry.AuthSecret)
489+
return nil, err
490+
}
491+
log.Info("Successfully retrieved registry auth secret for backup job", "secretName", dwOperatorConfig.Config.Workspace.BackupCronJob.Registry.AuthSecret)
492+
return r.copySecret(workspace, ctx, registryAuthSecret, log)
493+
}
494+
return nil, nil
495+
}
496+
477497
func (r *BackupCronJobReconciler) copySecret(workspace *dw.DevWorkspace, ctx context.Context, sourceSecret *corev1.Secret, log logr.Logger) (namespaceSecret *corev1.Secret, err error) {
478498
existingNamespaceSecret := &corev1.Secret{}
479499
err = r.NonCachingClient.Get(ctx, client.ObjectKey{
@@ -484,12 +504,10 @@ func (r *BackupCronJobReconciler) copySecret(workspace *dw.DevWorkspace, ctx con
484504
return nil, err
485505
}
486506
if err == nil {
487-
log.Info("Deleting existing registry auth secret in workspace namespace", "namespace", workspace.Namespace)
488507
err = r.Delete(ctx, existingNamespaceSecret)
489508
if err != nil {
490509
return nil, err
491510
}
492-
log.Info("Successfully deleted existing registry auth secret in workspace namespace", "namespace", workspace.Namespace)
493511
}
494512
namespaceSecret = &corev1.Secret{
495513
ObjectMeta: metav1.ObjectMeta{
@@ -507,5 +525,8 @@ func (r *BackupCronJobReconciler) copySecret(workspace *dw.DevWorkspace, ctx con
507525
return nil, err
508526
}
509527
err = r.Create(ctx, namespaceSecret)
528+
if err == nil {
529+
log.Info("Sucesfully created secret", "name", namespaceSecret.Name, "namespace", workspace.Namespace)
530+
}
510531
return namespaceSecret, err
511532
}

controllers/backupcronjob/backupcronjob_controller_test.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,12 @@ var _ = Describe("BackupCronJobReconciler", func() {
306306
dw.Status.DevWorkspaceId = "id-recent"
307307
Expect(fakeClient.Create(ctx, dw)).To(Succeed())
308308

309-
Expect(reconciler.executeBackupSync(ctx, dwoc, log)).To(HaveOccurred())
309+
err := reconciler.executeBackupSync(ctx, dwoc, log)
310+
Expect(err).ToNot(HaveOccurred())
311+
312+
jobList := &batchv1.JobList{}
313+
Expect(fakeClient.List(ctx, jobList, &client.ListOptions{Namespace: dw.Namespace})).To(Succeed())
314+
Expect(jobList.Items).To(HaveLen(0))
310315
})
311316

312317
It("creates a Job for a DevWorkspace stopped with no previous backup", func() {
@@ -429,7 +434,7 @@ var _ = Describe("BackupCronJobReconciler", func() {
429434
Expect(jobList.Items).To(HaveLen(0))
430435
})
431436

432-
It("creates a Job for a DevWorkspace stopped with no previous backup and auth registry", func() {
437+
It("creates a Job for a DevWorkspace stopped with no previous backup and global auth registry", func() {
433438
enabled := true
434439
schedule := "* * * * *"
435440
dwoc := &controllerv1alpha1.DevWorkspaceOperatorConfig{
@@ -460,6 +465,41 @@ var _ = Describe("BackupCronJobReconciler", func() {
460465

461466
Expect(reconciler.executeBackupSync(ctx, dwoc, log)).To(Succeed())
462467

468+
jobList := &batchv1.JobList{}
469+
Expect(fakeClient.List(ctx, jobList, &client.ListOptions{Namespace: dw.Namespace})).To(Succeed())
470+
Expect(jobList.Items).To(HaveLen(1))
471+
})
472+
It("creates a Job for a DevWorkspace stopped with no previous backup and local auth registry", func() {
473+
enabled := true
474+
schedule := "* * * * *"
475+
dwoc := &controllerv1alpha1.DevWorkspaceOperatorConfig{
476+
ObjectMeta: metav1.ObjectMeta{Name: nameNamespace.Name, Namespace: nameNamespace.Namespace},
477+
Config: &controllerv1alpha1.OperatorConfiguration{
478+
Workspace: &controllerv1alpha1.WorkspaceConfig{
479+
BackupCronJob: &controllerv1alpha1.BackupCronJobConfig{
480+
Enable: &enabled,
481+
Schedule: schedule,
482+
Registry: &controllerv1alpha1.RegistryConfig{
483+
Path: "my-registry:5000",
484+
AuthSecret: "my-secret",
485+
},
486+
},
487+
},
488+
},
489+
}
490+
dw := createDevWorkspace("dw-recent", "ns-a", false, metav1.NewTime(time.Now().Add(-10*time.Minute)))
491+
dw.Status.Phase = dwv2.DevWorkspaceStatusStopped
492+
dw.Status.DevWorkspaceId = "id-recent"
493+
Expect(fakeClient.Create(ctx, dw)).To(Succeed())
494+
495+
pvc := &corev1.PersistentVolumeClaim{ObjectMeta: metav1.ObjectMeta{Name: "claim-devworkspace", Namespace: dw.Namespace}}
496+
Expect(fakeClient.Create(ctx, pvc)).To(Succeed())
497+
498+
authSecret := createAuthSecret("my-secret", "ns-a", map[string][]byte{})
499+
Expect(fakeClient.Create(ctx, authSecret)).To(Succeed())
500+
501+
Expect(reconciler.executeBackupSync(ctx, dwoc, log)).To(Succeed())
502+
463503
jobList := &batchv1.JobList{}
464504
Expect(fakeClient.List(ctx, jobList, &client.ListOptions{Namespace: dw.Namespace})).To(Succeed())
465505
Expect(jobList.Items).To(HaveLen(1))

deploy/templates/crd/bases/controller.devfile.io_devworkspaceoperatorconfigs.yaml

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)