diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi_test.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi_test.go index a301316902..555d8c6e73 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi_test.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi_test.go @@ -184,6 +184,13 @@ var _ = Describe("ObjectRef ClusterVirtualImage", func() { It("waits for the first consumer", func() { dv.Status.Phase = cdiv1.PendingPopulation + dv.Status.Conditions = []cdiv1.DataVolumeCondition{ + { + Type: cdiv1.DataVolumeRunning, + Status: corev1.ConditionFalse, + Reason: "", + }, + } sc.VolumeBindingMode = ptr.To(storagev1.VolumeBindingWaitForFirstConsumer) client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(pvc, dv, sc).Build() diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_test.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_test.go index cd640d4161..f7509c2d80 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_test.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_test.go @@ -184,6 +184,13 @@ var _ = Describe("ObjectRef VirtualImage", func() { It("waits for the first consumer", func() { dv.Status.Phase = cdiv1.PendingPopulation + dv.Status.Conditions = []cdiv1.DataVolumeCondition{ + { + Type: cdiv1.DataVolumeRunning, + Status: corev1.ConditionFalse, + Reason: "", + }, + } sc.VolumeBindingMode = ptr.To(storagev1.VolumeBindingWaitForFirstConsumer) client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(pvc, dv, sc).Build() diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go index aeb6ecc3ee..6ca60ae7a0 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go @@ -181,7 +181,9 @@ func setPhaseConditionForPVCProvisioningDisk( Message("Waiting for the pvc importer to be created") return nil } - if isStorageClassWFFC(sc) && (dv.Status.Phase == cdiv1.PendingPopulation || dv.Status.Phase == cdiv1.WaitForFirstConsumer) { + + dvRunningCond, _ := conditions.GetDataVolumeCondition(conditions.DVRunningConditionType, dv.Status.Conditions) + if isStorageClassWFFC(sc) && (dv.Status.Phase == cdiv1.PendingPopulation || dv.Status.Phase == cdiv1.WaitForFirstConsumer) && dvRunningCond.Status == corev1.ConditionFalse && dvRunningCond.Reason == "" { vd.Status.Phase = v1alpha2.DiskWaitForFirstConsumer cb. Status(metav1.ConditionFalse). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/step/wait_for_dv_step.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/step/wait_for_dv_step.go index 656d60dd72..5b474b1c73 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/step/wait_for_dv_step.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/step/wait_for_dv_step.go @@ -126,13 +126,18 @@ func (s WaitForDVStep) setForProvisioning(vd *v1alpha2.VirtualDisk) (set bool) { } func (s WaitForDVStep) setForFirstConsumerIsAwaited(ctx context.Context, vd *v1alpha2.VirtualDisk) (set bool, err error) { + if vd.Status.StorageClassName == "" { + return false, nil + } + sc, err := object.FetchObject(ctx, types.NamespacedName{Name: vd.Status.StorageClassName}, s.client, &storagev1.StorageClass{}) if err != nil { return false, fmt.Errorf("get sc: %w", err) } + dvRunningCond, _ := conditions.GetDataVolumeCondition(conditions.DVRunningConditionType, s.dv.Status.Conditions) isWFFC := sc != nil && sc.VolumeBindingMode != nil && *sc.VolumeBindingMode == storagev1.VolumeBindingWaitForFirstConsumer - if isWFFC && (s.dv.Status.Phase == cdiv1.PendingPopulation || s.dv.Status.Phase == cdiv1.WaitForFirstConsumer) { + if isWFFC && (s.dv.Status.Phase == cdiv1.PendingPopulation || s.dv.Status.Phase == cdiv1.WaitForFirstConsumer) && dvRunningCond.Status == corev1.ConditionFalse && dvRunningCond.Reason == "" { vd.Status.Phase = v1alpha2.DiskWaitForFirstConsumer s.cb. Status(metav1.ConditionFalse). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/watcher/datavolume_watcher.go b/images/virtualization-artifact/pkg/controller/vd/internal/watcher/datavolume_watcher.go index ffbaccf88d..70d83da98d 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/watcher/datavolume_watcher.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/watcher/datavolume_watcher.go @@ -73,6 +73,13 @@ func (w *DataVolumeWatcher) Watch(mgr manager.Manager, ctr controller.Controller return true } + oldDVRunning, _ := conditions.GetDataVolumeCondition(conditions.DVRunningConditionType, e.ObjectOld.Status.Conditions) + newDVRunning, _ := conditions.GetDataVolumeCondition(conditions.DVRunningConditionType, e.ObjectNew.Status.Conditions) + + if oldDVRunning.Reason != newDVRunning.Reason { + return true + } + dvRunning := service.GetDataVolumeCondition(cdiv1.DataVolumeRunning, e.ObjectNew.Status.Conditions) return dvRunning != nil && (dvRunning.Reason == "Error" || dvRunning.Reason == "ImagePullFailed") }, diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/block_device_condition.go b/images/virtualization-artifact/pkg/controller/vm/internal/block_device_condition.go index 3adb173d1c..b0a4bc3637 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/block_device_condition.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/block_device_condition.go @@ -21,8 +21,11 @@ import ( "fmt" "strings" + storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "github.com/deckhouse/virtualization-controller/pkg/common/object" "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" "github.com/deckhouse/virtualization-controller/pkg/controller/vm/internal/state" "github.com/deckhouse/virtualization-controller/pkg/logger" @@ -54,8 +57,17 @@ func (h *BlockDeviceHandler) checkVirtualDisksToBeWFFC(ctx context.Context, s st } for _, vd := range vds { - if vd.Status.Phase == v1alpha2.DiskWaitForFirstConsumer { - return true, nil + scName := vd.Status.StorageClassName + sc, err := object.FetchObject(ctx, types.NamespacedName{Name: scName}, h.client, &storagev1.StorageClass{}) + if err != nil { + return false, fmt.Errorf("fetch storage class %s: %w", scName, err) + } + + if sc != nil && sc.VolumeBindingMode != nil && *sc.VolumeBindingMode == storagev1.VolumeBindingWaitForFirstConsumer { + readyCondition, _ := conditions.GetCondition(vdcondition.ReadyType, vd.Status.Conditions) + if readyCondition.Status != metav1.ConditionTrue { + return true, nil + } } } diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/block_devices_test.go b/images/virtualization-artifact/pkg/controller/vm/internal/block_devices_test.go index 6d521d5bbf..fe73ceca21 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/block_devices_test.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/block_devices_test.go @@ -24,6 +24,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" apiruntime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -58,6 +59,7 @@ var _ = Describe("Test BlockDeviceReady condition", func() { v1alpha2.AddToScheme, virtv1.AddToScheme, corev1.AddToScheme, + storagev1.AddToScheme, } { err := f(scheme) Expect(err).NotTo(HaveOccurred(), "failed to add scheme: %s", err) @@ -203,7 +205,8 @@ var _ = Describe("Test BlockDeviceReady condition", func() { Namespace: namespacedName.Namespace, }, Status: v1alpha2.VirtualDiskStatus{ - Phase: v1alpha2.DiskWaitForFirstConsumer, + Phase: v1alpha2.DiskWaitForFirstConsumer, + StorageClassName: "wffc-storage", Target: v1alpha2.DiskTarget{ PersistentVolumeClaim: "testPvc", }, @@ -222,8 +225,19 @@ var _ = Describe("Test BlockDeviceReady condition", func() { } } + getWFFCStorageClass := func() *storagev1.StorageClass { + bindingMode := storagev1.VolumeBindingWaitForFirstConsumer + return &storagev1.StorageClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "wffc-storage", + }, + VolumeBindingMode: &bindingMode, + } + } + DescribeTable("One wffc disk", func(vd *v1alpha2.VirtualDisk, vm *v1alpha2.VirtualMachine, status metav1.ConditionStatus, msg string) { - fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(vm, vd).Build() + sc := getWFFCStorageClass() + fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(vm, vd, sc).Build() vmResource := reconciler.NewResource(namespacedName, fakeClient, vmFactoryByVM(vm), vmStatusGetter) err := vmResource.Fetch(ctx)