From c5ad953db2206972734bba24996f78432e2c5ef2 Mon Sep 17 00:00:00 2001 From: Daniil Antoshin Date: Wed, 25 Mar 2026 12:45:22 +0200 Subject: [PATCH 1/8] feat(vd): add quota override label for PVC migration - Add resource-quota-overrides.deckhouse.io/ignore label to target PVC when it is created during migration (handleMigratePrepareTarget) - Remove the label from target PVC before deleting source PVC (handleComplete) to avoid x0 quota scenario During migration, the quota will be x2 for a short time, but that's expected. The main goal is to avoid x0 quota. Signed-off-by: Daniil Antoshin --- .../pkg/controller/vd/internal/migration.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go index 6579c01682..c95bbac0f2 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go @@ -34,6 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" + "github.com/deckhouse/virtualization-controller/pkg/common/annotations" "github.com/deckhouse/virtualization-controller/pkg/common/object" pvcspec "github.com/deckhouse/virtualization-controller/pkg/common/pvc" commonvd "github.com/deckhouse/virtualization-controller/pkg/common/vd" @@ -594,6 +595,17 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu } log.Info("Complete migration. Delete source PersistentVolumeClaim", slog.String("pvc.name", vd.Status.MigrationState.SourcePVC), slog.String("pvc.namespace", vd.Namespace)) + + // Remove quota override label from target PVC before deleting source PVC. + // During migration, the quota would be x2 for a short time, but that's expected. + // The main goal is to avoid x0 quota. + if targetPVC.Labels != nil { + delete(targetPVC.Labels, annotations.QuotaExcludeLabel) + } + if err := h.client.Update(ctx, targetPVC); err != nil && !k8serrors.IsNotFound(err) { + return fmt.Errorf("remove quota override label from target PVC: %w", err) + } + err = h.deleteSourcePersistentVolumeClaim(ctx, vd) if err != nil { return err @@ -662,6 +674,8 @@ func (h MigrationHandler) createTargetPersistentVolumeClaim(ctx context.Context, ), } + annotations.AddLabel(pvc, annotations.QuotaExcludeLabel, annotations.QuotaExcludeValue) + err = h.client.Create(ctx, pvc) return pvc, err } From 4599790aa83ce3f7f8a62afd38e022766ff9e34a Mon Sep 17 00:00:00 2001 From: Daniil Antoshin Date: Wed, 25 Mar 2026 12:49:24 +0200 Subject: [PATCH 2/8] refactor(vd): set quota override label directly in PVC ObjectMeta Signed-off-by: Daniil Antoshin --- .../pkg/controller/vd/internal/migration.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go index c95bbac0f2..602525a838 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go @@ -596,9 +596,7 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu log.Info("Complete migration. Delete source PersistentVolumeClaim", slog.String("pvc.name", vd.Status.MigrationState.SourcePVC), slog.String("pvc.namespace", vd.Namespace)) - // Remove quota override label from target PVC before deleting source PVC. - // During migration, the quota would be x2 for a short time, but that's expected. - // The main goal is to avoid x0 quota. + // Remove quota override label before deleting source PVC. if targetPVC.Labels != nil { delete(targetPVC.Labels, annotations.QuotaExcludeLabel) } @@ -667,6 +665,9 @@ func (h MigrationHandler) createTargetPersistentVolumeClaim(ctx context.Context, OwnerReferences: []metav1.OwnerReference{ service.MakeControllerOwnerReference(vd), }, + Labels: map[string]string{ + annotations.QuotaExcludeLabel: annotations.QuotaExcludeValue, + }, }, Spec: ptr.Deref( pvcspec.CreateSpec(&sc.Name, size, accessMode, volumeMode), @@ -674,8 +675,6 @@ func (h MigrationHandler) createTargetPersistentVolumeClaim(ctx context.Context, ), } - annotations.AddLabel(pvc, annotations.QuotaExcludeLabel, annotations.QuotaExcludeValue) - err = h.client.Create(ctx, pvc) return pvc, err } From 06b077d1dc78a37371131bf0169e491ce86c51b4 Mon Sep 17 00:00:00 2001 From: Daniil Antoshin Date: Wed, 25 Mar 2026 13:53:13 +0200 Subject: [PATCH 3/8] refactor(vd): remove quota label after source PVC deletion Signed-off-by: Daniil Antoshin --- .../pkg/controller/vd/internal/migration.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go index 602525a838..8d7e3e642e 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go @@ -596,7 +596,13 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu log.Info("Complete migration. Delete source PersistentVolumeClaim", slog.String("pvc.name", vd.Status.MigrationState.SourcePVC), slog.String("pvc.namespace", vd.Namespace)) - // Remove quota override label before deleting source PVC. + err = h.deleteSourcePersistentVolumeClaim(ctx, vd) + if err != nil { + return err + } + log.Debug("Source PersistentVolumeClaim was deleted", slog.String("pvc.name", vd.Status.MigrationState.SourcePVC), slog.String("pvc.namespace", vd.Namespace)) + + // Remove quota override label from target PVC. if targetPVC.Labels != nil { delete(targetPVC.Labels, annotations.QuotaExcludeLabel) } @@ -604,12 +610,6 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu return fmt.Errorf("remove quota override label from target PVC: %w", err) } - err = h.deleteSourcePersistentVolumeClaim(ctx, vd) - if err != nil { - return err - } - log.Debug("Source PersistentVolumeClaim was deleted", slog.String("pvc.name", vd.Status.MigrationState.SourcePVC), slog.String("pvc.namespace", vd.Namespace)) - if sc := vd.Spec.PersistentVolumeClaim.StorageClass; sc != nil && *sc != "" { vd.Status.StorageClassName = *sc } From 2fbd13158291c6be8d092ef85b73823df7463503 Mon Sep 17 00:00:00 2001 From: Daniil Antoshin Date: Wed, 25 Mar 2026 13:54:58 +0200 Subject: [PATCH 4/8] refactor(vd): use Patch instead of Update to remove quota label Signed-off-by: Daniil Antoshin --- .../pkg/controller/vd/internal/migration.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go index 8d7e3e642e..0612b99710 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go @@ -604,10 +604,11 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu // Remove quota override label from target PVC. if targetPVC.Labels != nil { + original := targetPVC.DeepCopy() delete(targetPVC.Labels, annotations.QuotaExcludeLabel) - } - if err := h.client.Update(ctx, targetPVC); err != nil && !k8serrors.IsNotFound(err) { - return fmt.Errorf("remove quota override label from target PVC: %w", err) + if err := h.client.Patch(ctx, targetPVC, client.MergeFrom(original)); err != nil && !k8serrors.IsNotFound(err) { + return fmt.Errorf("remove quota override label from target PVC: %w", err) + } } if sc := vd.Spec.PersistentVolumeClaim.StorageClass; sc != nil && *sc != "" { From 523f12473801f89ad1f911632dd8a44a28881d64 Mon Sep 17 00:00:00 2001 From: Daniil Antoshin Date: Wed, 25 Mar 2026 13:56:37 +0200 Subject: [PATCH 5/8] fix(vd): ignore NotFound error when deleting source PVC Signed-off-by: Daniil Antoshin --- .../pkg/controller/vd/internal/migration.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go index 0612b99710..418852672c 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go @@ -699,9 +699,12 @@ func (h MigrationHandler) deleteTargetPersistentVolumeClaim(ctx context.Context, func (h MigrationHandler) deleteSourcePersistentVolumeClaim(ctx context.Context, vd *v1alpha2.VirtualDisk) error { pvc, err := h.getSourcePersistentVolumeClaim(ctx, vd) - if pvc == nil || err != nil { + if err != nil && !k8serrors.IsNotFound(err) { return err } + if pvc == nil { + return nil + } return deletePersistentVolumeClaim(ctx, pvc, h.client) } From 481dee0b588830cd3c42c78ffac15500a34d49af Mon Sep 17 00:00:00 2001 From: Daniil Antoshin Date: Wed, 25 Mar 2026 14:51:00 +0200 Subject: [PATCH 6/8] feat(vd): add quota override label to source PVC during migration Move quota override label from target PVC to source PVC during migration: - Add label to source PVC after target PVC is successfully created (prevents x0 quota) - Remove label from source PVC if migration fails (handleRevert, handleComplete) - Source PVC is excluded from quota while migration is in progress - If migration fails, quota starts counting source PVC again This prevents double counting of storage resources during PVC migration when both source and target PVCs exist simultaneously. Signed-off-by: Daniil Antoshin --- .../pkg/controller/vd/internal/migration.go | 71 +++++++++++++++---- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go index 418852672c..5c111e1af9 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go @@ -422,6 +422,12 @@ func (h MigrationHandler) handleMigratePrepareTarget(ctx context.Context, vd *v1 return errors.New("the target PersistentVolumeClaim name matched the source PersistentVolumeClaim name, please report a bug") } + // Add quota override label to source PVC after target is created (prevents x0 quota). + sourcePVCName := vd.Status.Target.PersistentVolumeClaim + if err := h.addQuotaOverrideLabelToPVC(ctx, sourcePVCName, vd.Namespace); err != nil { + return fmt.Errorf("add quota override label to source PVC: %w", err) + } + vd.Status.MigrationState = v1alpha2.VirtualDiskMigrationState{ SourcePVC: vd.Status.Target.PersistentVolumeClaim, TargetPVC: pvc.Name, @@ -544,6 +550,11 @@ func (h MigrationHandler) handleRevert(ctx context.Context, vd *v1alpha2.Virtual } log.Debug("Target PersistentVolumeClaim was deleted", slog.String("pvc.name", vd.Status.MigrationState.TargetPVC), slog.String("pvc.namespace", vd.Namespace)) + // Remove quota override label from source PVC. + if err := h.removeQuotaOverrideLabelFromPVC(ctx, vd.Status.MigrationState.SourcePVC, vd.Namespace); err != nil { + return fmt.Errorf("remove quota override label from source PVC: %w", err) + } + vd.Status.MigrationState.EndTimestamp = metav1.Now() vd.Status.MigrationState.Result = v1alpha2.VirtualDiskMigrationResultFailed vd.Status.MigrationState.Message = "Migration reverted." @@ -565,6 +576,12 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu // revert old PVC and remove migration condition. if targetPVC == nil { log.Info("Target PersistentVolumeClaim is not found. Revert old PersistentVolumeClaim and remove migration condition.", slog.String("pvc.name", vd.Status.MigrationState.TargetPVC), slog.String("pvc.namespace", vd.Namespace)) + + // Remove quota override label from source PVC. + if err := h.removeQuotaOverrideLabelFromPVC(ctx, vd.Status.MigrationState.SourcePVC, vd.Namespace); err != nil { + return fmt.Errorf("remove quota override label from source PVC: %w", err) + } + vd.Status.MigrationState.EndTimestamp = metav1.Now() vd.Status.MigrationState.Result = v1alpha2.VirtualDiskMigrationResultFailed vd.Status.MigrationState.Message = "Migration failed: target PVC is not found." @@ -585,6 +602,11 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu } log.Debug("Target PersistentVolumeClaim was deleted", slog.String("pvc.name", vd.Status.MigrationState.TargetPVC), slog.String("pvc.namespace", vd.Namespace)) + // Remove quota override label from source PVC. + if err := h.removeQuotaOverrideLabelFromPVC(ctx, vd.Status.MigrationState.SourcePVC, vd.Namespace); err != nil { + return fmt.Errorf("remove quota override label from source PVC: %w", err) + } + vd.Status.MigrationState.EndTimestamp = metav1.Now() vd.Status.MigrationState.Result = v1alpha2.VirtualDiskMigrationResultFailed vd.Status.MigrationState.Message = "Migration failed: target PVC is not bound." @@ -602,15 +624,6 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu } log.Debug("Source PersistentVolumeClaim was deleted", slog.String("pvc.name", vd.Status.MigrationState.SourcePVC), slog.String("pvc.namespace", vd.Namespace)) - // Remove quota override label from target PVC. - if targetPVC.Labels != nil { - original := targetPVC.DeepCopy() - delete(targetPVC.Labels, annotations.QuotaExcludeLabel) - if err := h.client.Patch(ctx, targetPVC, client.MergeFrom(original)); err != nil && !k8serrors.IsNotFound(err) { - return fmt.Errorf("remove quota override label from target PVC: %w", err) - } - } - if sc := vd.Spec.PersistentVolumeClaim.StorageClass; sc != nil && *sc != "" { vd.Status.StorageClassName = *sc } @@ -666,9 +679,6 @@ func (h MigrationHandler) createTargetPersistentVolumeClaim(ctx context.Context, OwnerReferences: []metav1.OwnerReference{ service.MakeControllerOwnerReference(vd), }, - Labels: map[string]string{ - annotations.QuotaExcludeLabel: annotations.QuotaExcludeValue, - }, }, Spec: ptr.Deref( pvcspec.CreateSpec(&sc.Name, size, accessMode, volumeMode), @@ -680,6 +690,43 @@ func (h MigrationHandler) createTargetPersistentVolumeClaim(ctx context.Context, return pvc, err } +func (h MigrationHandler) addQuotaOverrideLabelToPVC(ctx context.Context, pvcName, namespace string) error { + pvc := &corev1.PersistentVolumeClaim{} + if err := h.client.Get(ctx, types.NamespacedName{Name: pvcName, Namespace: namespace}, pvc); err != nil { + if k8serrors.IsNotFound(err) { + return nil + } + return err + } + + original := pvc.DeepCopy() + if pvc.Labels == nil { + pvc.Labels = make(map[string]string) + } + pvc.Labels[annotations.QuotaExcludeLabel] = annotations.QuotaExcludeValue + + return h.client.Patch(ctx, pvc, client.MergeFrom(original)) +} + +func (h MigrationHandler) removeQuotaOverrideLabelFromPVC(ctx context.Context, pvcName, namespace string) error { + pvc := &corev1.PersistentVolumeClaim{} + if err := h.client.Get(ctx, types.NamespacedName{Name: pvcName, Namespace: namespace}, pvc); err != nil { + if k8serrors.IsNotFound(err) { + return nil + } + return err + } + + if pvc.Labels == nil { + return nil + } + + original := pvc.DeepCopy() + delete(pvc.Labels, annotations.QuotaExcludeLabel) + + return h.client.Patch(ctx, pvc, client.MergeFrom(original)) +} + func (h MigrationHandler) getTargetPersistentVolumeClaim(ctx context.Context, vd *v1alpha2.VirtualDisk) (*corev1.PersistentVolumeClaim, error) { return object.FetchObject(ctx, types.NamespacedName{Name: vd.Status.MigrationState.TargetPVC, Namespace: vd.Namespace}, h.client, &corev1.PersistentVolumeClaim{}) } From 9237a40b73fd332abac789ccd8c4fec0b76ffaa4 Mon Sep 17 00:00:00 2001 From: Daniil Antoshin Date: Wed, 25 Mar 2026 15:25:52 +0200 Subject: [PATCH 7/8] Revert "feat(vd): add quota override label to source PVC during migration" This reverts commit 481dee0b588830cd3c42c78ffac15500a34d49af. Signed-off-by: Daniil Antoshin --- .../pkg/controller/vd/internal/migration.go | 71 ++++--------------- 1 file changed, 12 insertions(+), 59 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go index 5c111e1af9..418852672c 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go @@ -422,12 +422,6 @@ func (h MigrationHandler) handleMigratePrepareTarget(ctx context.Context, vd *v1 return errors.New("the target PersistentVolumeClaim name matched the source PersistentVolumeClaim name, please report a bug") } - // Add quota override label to source PVC after target is created (prevents x0 quota). - sourcePVCName := vd.Status.Target.PersistentVolumeClaim - if err := h.addQuotaOverrideLabelToPVC(ctx, sourcePVCName, vd.Namespace); err != nil { - return fmt.Errorf("add quota override label to source PVC: %w", err) - } - vd.Status.MigrationState = v1alpha2.VirtualDiskMigrationState{ SourcePVC: vd.Status.Target.PersistentVolumeClaim, TargetPVC: pvc.Name, @@ -550,11 +544,6 @@ func (h MigrationHandler) handleRevert(ctx context.Context, vd *v1alpha2.Virtual } log.Debug("Target PersistentVolumeClaim was deleted", slog.String("pvc.name", vd.Status.MigrationState.TargetPVC), slog.String("pvc.namespace", vd.Namespace)) - // Remove quota override label from source PVC. - if err := h.removeQuotaOverrideLabelFromPVC(ctx, vd.Status.MigrationState.SourcePVC, vd.Namespace); err != nil { - return fmt.Errorf("remove quota override label from source PVC: %w", err) - } - vd.Status.MigrationState.EndTimestamp = metav1.Now() vd.Status.MigrationState.Result = v1alpha2.VirtualDiskMigrationResultFailed vd.Status.MigrationState.Message = "Migration reverted." @@ -576,12 +565,6 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu // revert old PVC and remove migration condition. if targetPVC == nil { log.Info("Target PersistentVolumeClaim is not found. Revert old PersistentVolumeClaim and remove migration condition.", slog.String("pvc.name", vd.Status.MigrationState.TargetPVC), slog.String("pvc.namespace", vd.Namespace)) - - // Remove quota override label from source PVC. - if err := h.removeQuotaOverrideLabelFromPVC(ctx, vd.Status.MigrationState.SourcePVC, vd.Namespace); err != nil { - return fmt.Errorf("remove quota override label from source PVC: %w", err) - } - vd.Status.MigrationState.EndTimestamp = metav1.Now() vd.Status.MigrationState.Result = v1alpha2.VirtualDiskMigrationResultFailed vd.Status.MigrationState.Message = "Migration failed: target PVC is not found." @@ -602,11 +585,6 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu } log.Debug("Target PersistentVolumeClaim was deleted", slog.String("pvc.name", vd.Status.MigrationState.TargetPVC), slog.String("pvc.namespace", vd.Namespace)) - // Remove quota override label from source PVC. - if err := h.removeQuotaOverrideLabelFromPVC(ctx, vd.Status.MigrationState.SourcePVC, vd.Namespace); err != nil { - return fmt.Errorf("remove quota override label from source PVC: %w", err) - } - vd.Status.MigrationState.EndTimestamp = metav1.Now() vd.Status.MigrationState.Result = v1alpha2.VirtualDiskMigrationResultFailed vd.Status.MigrationState.Message = "Migration failed: target PVC is not bound." @@ -624,6 +602,15 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu } log.Debug("Source PersistentVolumeClaim was deleted", slog.String("pvc.name", vd.Status.MigrationState.SourcePVC), slog.String("pvc.namespace", vd.Namespace)) + // Remove quota override label from target PVC. + if targetPVC.Labels != nil { + original := targetPVC.DeepCopy() + delete(targetPVC.Labels, annotations.QuotaExcludeLabel) + if err := h.client.Patch(ctx, targetPVC, client.MergeFrom(original)); err != nil && !k8serrors.IsNotFound(err) { + return fmt.Errorf("remove quota override label from target PVC: %w", err) + } + } + if sc := vd.Spec.PersistentVolumeClaim.StorageClass; sc != nil && *sc != "" { vd.Status.StorageClassName = *sc } @@ -679,6 +666,9 @@ func (h MigrationHandler) createTargetPersistentVolumeClaim(ctx context.Context, OwnerReferences: []metav1.OwnerReference{ service.MakeControllerOwnerReference(vd), }, + Labels: map[string]string{ + annotations.QuotaExcludeLabel: annotations.QuotaExcludeValue, + }, }, Spec: ptr.Deref( pvcspec.CreateSpec(&sc.Name, size, accessMode, volumeMode), @@ -690,43 +680,6 @@ func (h MigrationHandler) createTargetPersistentVolumeClaim(ctx context.Context, return pvc, err } -func (h MigrationHandler) addQuotaOverrideLabelToPVC(ctx context.Context, pvcName, namespace string) error { - pvc := &corev1.PersistentVolumeClaim{} - if err := h.client.Get(ctx, types.NamespacedName{Name: pvcName, Namespace: namespace}, pvc); err != nil { - if k8serrors.IsNotFound(err) { - return nil - } - return err - } - - original := pvc.DeepCopy() - if pvc.Labels == nil { - pvc.Labels = make(map[string]string) - } - pvc.Labels[annotations.QuotaExcludeLabel] = annotations.QuotaExcludeValue - - return h.client.Patch(ctx, pvc, client.MergeFrom(original)) -} - -func (h MigrationHandler) removeQuotaOverrideLabelFromPVC(ctx context.Context, pvcName, namespace string) error { - pvc := &corev1.PersistentVolumeClaim{} - if err := h.client.Get(ctx, types.NamespacedName{Name: pvcName, Namespace: namespace}, pvc); err != nil { - if k8serrors.IsNotFound(err) { - return nil - } - return err - } - - if pvc.Labels == nil { - return nil - } - - original := pvc.DeepCopy() - delete(pvc.Labels, annotations.QuotaExcludeLabel) - - return h.client.Patch(ctx, pvc, client.MergeFrom(original)) -} - func (h MigrationHandler) getTargetPersistentVolumeClaim(ctx context.Context, vd *v1alpha2.VirtualDisk) (*corev1.PersistentVolumeClaim, error) { return object.FetchObject(ctx, types.NamespacedName{Name: vd.Status.MigrationState.TargetPVC, Namespace: vd.Namespace}, h.client, &corev1.PersistentVolumeClaim{}) } From 38dbb63b7158cffac1eafb31fb496a731b76af75 Mon Sep 17 00:00:00 2001 From: Daniil Antoshin Date: Wed, 25 Mar 2026 17:14:22 +0200 Subject: [PATCH 8/8] refactor(vd): simplify quota label removal with RawPatch Signed-off-by: Daniil Antoshin --- .../pkg/common/object/object.go | 12 ++++++++++++ .../pkg/controller/vd/internal/migration.go | 8 ++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/images/virtualization-artifact/pkg/common/object/object.go b/images/virtualization-artifact/pkg/common/object/object.go index 43bb089e94..ffd5642a6a 100644 --- a/images/virtualization-artifact/pkg/common/object/object.go +++ b/images/virtualization-artifact/pkg/common/object/object.go @@ -182,3 +182,15 @@ func RemoveAnnotation(ctx context.Context, cl client.Client, obj client.Object, } return cl.Patch(ctx, obj, client.RawPatch(types.JSONPatchType, bytes)) } + +func RemoveLabel(ctx context.Context, cl client.Client, obj client.Object, labelKey string) error { + if _, exist := obj.GetLabels()[labelKey]; !exist { + return nil + } + jsonOp := patch.WithRemove(fmt.Sprintf("/metadata/labels/%s", patch.EscapeJSONPointer(labelKey))) + bytes, err := patch.NewJSONPatch(jsonOp).Bytes() + if err != nil { + return err + } + return cl.Patch(ctx, obj, client.RawPatch(types.JSONPatchType, bytes)) +} diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go index 418852672c..c2484af2b8 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/migration.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/migration.go @@ -603,12 +603,8 @@ func (h MigrationHandler) handleComplete(ctx context.Context, vd *v1alpha2.Virtu log.Debug("Source PersistentVolumeClaim was deleted", slog.String("pvc.name", vd.Status.MigrationState.SourcePVC), slog.String("pvc.namespace", vd.Namespace)) // Remove quota override label from target PVC. - if targetPVC.Labels != nil { - original := targetPVC.DeepCopy() - delete(targetPVC.Labels, annotations.QuotaExcludeLabel) - if err := h.client.Patch(ctx, targetPVC, client.MergeFrom(original)); err != nil && !k8serrors.IsNotFound(err) { - return fmt.Errorf("remove quota override label from target PVC: %w", err) - } + if err := object.RemoveLabel(ctx, h.client, targetPVC, annotations.QuotaExcludeLabel); err != nil && !k8serrors.IsNotFound(err) { + return fmt.Errorf("remove quota override label from target PVC: %w", err) } if sc := vd.Spec.PersistentVolumeClaim.StorageClass; sc != nil && *sc != "" {