diff --git a/pkg/controller/common/util.go b/pkg/controller/common/util.go index a59a3f591f..6c377df0bd 100644 --- a/pkg/controller/common/util.go +++ b/pkg/controller/common/util.go @@ -241,6 +241,9 @@ const ( // be dynamically provisioned. Its value is the name of the selected node. AnnSelectedNode = "volume.kubernetes.io/selected-node" + // AnnGarbageCollected is a PVC annotation indicating that the PVC was garbage collected + AnnGarbageCollected = AnnAPIGroup + "/garbageCollected" + // CloneUniqueID is used as a special label to be used when we search for the pod CloneUniqueID = "cdi.kubevirt.io/storage.clone.cloneUniqeId" diff --git a/pkg/controller/datavolume/garbagecollect.go b/pkg/controller/datavolume/garbagecollect.go index 99016cc7e1..2d6bf3a953 100644 --- a/pkg/controller/datavolume/garbagecollect.go +++ b/pkg/controller/datavolume/garbagecollect.go @@ -104,6 +104,7 @@ func (r *ReconcilerBase) canUpdateFinalizers(ownerRef metav1.OwnerReference) (bo func (r *ReconcilerBase) detachPvcDeleteDv(syncState *dvSyncState) error { updatePvcOwnerRefs(syncState.pvc, syncState.dv) delete(syncState.pvc.Annotations, cc.AnnPopulatedFor) + cc.AddAnnotation(syncState.pvc, cc.AnnGarbageCollected, "true") if err := r.updatePVC(syncState.pvc); err != nil { return err } diff --git a/pkg/controller/datavolume/import-controller_test.go b/pkg/controller/datavolume/import-controller_test.go index 4f3f359d47..8fc19acd12 100644 --- a/pkg/controller/datavolume/import-controller_test.go +++ b/pkg/controller/datavolume/import-controller_test.go @@ -1630,6 +1630,34 @@ var _ = Describe("All DataVolume Tests", func() { Expect(pvc.OwnerReferences).To(HaveLen(4)) Expect(pvc.OwnerReferences).To(Equal([]metav1.OwnerReference{ref("1"), ref("2"), ref("3"), vmOwnerRef})) }) + + It("should update PVC when garbage collecting", func() { + dv := NewImportDataVolume("test-dv") + AddAnnotation(dv, AnnDeleteAfterCompletion, "true") + dv.Status.Phase = cdiv1.Succeeded + vmOwnerRef := metav1.OwnerReference{Kind: "VirtualMachine", Name: "test-vm", UID: "test-vm-uid", Controller: pointer.Bool(true)} + dv.OwnerReferences = append(dv.OwnerReferences, vmOwnerRef) + + pvc := CreatePvc("test-dv", metav1.NamespaceDefault, nil, nil) + dvOwnerRef := metav1.OwnerReference{Kind: "DataVolume", Name: "test-dv", UID: dv.UID, Controller: pointer.Bool(true)} + pvc.OwnerReferences = append(pvc.OwnerReferences, dvOwnerRef) + + cdiConfig := MakeEmptyCDIConfigSpec(common.ConfigName) + cdiConfig.Status = cdiv1.CDIConfigStatus{ + ScratchSpaceStorageClass: testStorageClass, + } + cdiConfig.Spec.FeatureGates = []string{featuregates.HonorWaitForFirstConsumer} + cdiConfig.Spec.DataVolumeTTLSeconds = pointer.Int32(int32(0)) + + reconciler = createImportReconcilerWithoutConfig(dv, pvc, cdiConfig) + _, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: types.NamespacedName{Name: "test-dv", Namespace: metav1.NamespaceDefault}}) + Expect(err).ToNot(HaveOccurred()) + pvc = &corev1.PersistentVolumeClaim{} + err = reconciler.client.Get(context.TODO(), types.NamespacedName{Name: "test-dv", Namespace: metav1.NamespaceDefault}, pvc) + Expect(err).ToNot(HaveOccurred()) + Expect(pvc.OwnerReferences).To(Equal([]metav1.OwnerReference{vmOwnerRef})) + Expect(pvc.Annotations[AnnGarbageCollected]).To(Equal("true")) + }) }) var _ = Describe("shouldUseCDIPopulator", func() {