diff --git a/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle.go index 04f9863892..53bd353254 100644 --- a/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle.go +++ b/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle.go @@ -414,6 +414,22 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vdSnapshot *v1alpha2.Virtu } } + // Check if we can unfreeze now or need to wait for other VDSnapshots. + canUnfreeze, err := h.snapshotter.CanUnfreezeWithVirtualDiskSnapshot(ctx, vdSnapshot.Name, vm, kvvmi) + if err != nil { + setPhaseConditionToFailed(cb, &vdSnapshot.Status.Phase, err) + return reconcile.Result{}, err + } + if !canUnfreeze { + log.Debug("waiting for other virtual disk snapshots to be ready before unfreezing filesystem") + vdSnapshot.Status.Phase = v1alpha2.VirtualDiskSnapshotPhaseInProgress + cb. + Status(metav1.ConditionFalse). + Reason(vdscondition.Snapshotting). + Message(service.CapitalizeFirstLetter("Waiting for other virtual disk snapshots to be ready before unfreezing filesystem.")) + return reconcile.Result{RequeueAfter: 5 * time.Second}, nil + } + err = h.unfreezeFilesystem(ctx, vdSnapshot.Name, vm, kvvmi) if err != nil { if k8serrors.IsConflict(err) { diff --git a/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle_test.go b/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle_test.go index bf74a51a36..7dbffb4a25 100644 --- a/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle_test.go +++ b/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle_test.go @@ -100,6 +100,9 @@ var _ = Describe("LifeCycle handler", func() { SyncFSFreezeRequestFunc: func(_ context.Context, _ *virtv1.VirtualMachineInstance) error { return nil }, + UnfreezeFunc: func(_ context.Context, _ *virtv1.VirtualMachineInstance) error { + return nil + }, } }) @@ -187,7 +190,7 @@ var _ = Describe("LifeCycle handler", func() { return vs, nil } snapshotter.CanUnfreezeWithVirtualDiskSnapshotFunc = func(_ context.Context, _ string, _ *v1alpha2.VirtualMachine, _ *virtv1.VirtualMachineInstance) (bool, error) { - return false, nil + return true, nil } h := NewLifeCycleHandler(snapshotter) @@ -203,6 +206,34 @@ var _ = Describe("LifeCycle handler", func() { Expect(ready.Message).To(BeEmpty()) }) + It("waits for other VDSnapshots before unfreezing", func() { + vdSnapshot.Status.Phase = v1alpha2.VirtualDiskSnapshotPhaseInProgress + // Set Consistent to skip the early branch that sets consistent=true + vdSnapshot.Status.Consistent = ptr.To(true) + + snapshotter.GetVolumeSnapshotFunc = func(_ context.Context, _, _ string) (*vsv1.VolumeSnapshot, error) { + vs.Status = &vsv1.VolumeSnapshotStatus{ + ReadyToUse: ptr.To(true), + } + return vs, nil + } + snapshotter.CanUnfreezeWithVirtualDiskSnapshotFunc = func(_ context.Context, _ string, _ *v1alpha2.VirtualMachine, _ *virtv1.VirtualMachineInstance) (bool, error) { + // Simulate other VDSnapshots are still in progress + return false, nil + } + + h := NewLifeCycleHandler(snapshotter) + + _, err := h.Handle(testContext(), vdSnapshot) + Expect(err).To(BeNil()) + // Should stay in InProgress when other snapshots are active + Expect(vdSnapshot.Status.Phase).To(Equal(v1alpha2.VirtualDiskSnapshotPhaseInProgress)) + ready, _ := conditions.GetCondition(vdscondition.VirtualDiskSnapshotReadyType, vdSnapshot.Status.Conditions) + Expect(ready.Status).To(Equal(metav1.ConditionFalse)) + Expect(ready.Reason).To(Equal(vdscondition.Snapshotting.String())) + Expect(ready.Message).To(ContainSubstring("other virtual disk snapshots")) + }) + It("fails when the virtual disk is missing", func() { snapshotter.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { return nil, nil diff --git a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/interfaces.go b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/interfaces.go index 4744a2b801..be50acb95a 100644 --- a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/interfaces.go +++ b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/interfaces.go @@ -20,7 +20,6 @@ import ( "context" corev1 "k8s.io/api/core/v1" - virtv1 "kubevirt.io/api/core/v1" "github.com/deckhouse/virtualization/api/core/v1alpha2" ) @@ -38,11 +37,4 @@ type Snapshotter interface { GetPersistentVolumeClaim(ctx context.Context, name, namespace string) (*corev1.PersistentVolumeClaim, error) GetVirtualDiskSnapshot(ctx context.Context, name, namespace string) (*v1alpha2.VirtualDiskSnapshot, error) CreateVirtualDiskSnapshot(ctx context.Context, vdSnapshot *v1alpha2.VirtualDiskSnapshot) (*v1alpha2.VirtualDiskSnapshot, error) - Freeze(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error - Unfreeze(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error - IsFrozen(kvvmi *virtv1.VirtualMachineInstance) (bool, error) - CanFreeze(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) (bool, error) - CanUnfreezeWithVirtualMachineSnapshot(ctx context.Context, vmSnapshotName string, vm *v1alpha2.VirtualMachine, kvvmi *virtv1.VirtualMachineInstance) (bool, error) - SyncFSFreezeRequest(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error - GetVirtualMachineInstance(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachineInstance, error) } diff --git a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go index abb7d775f6..fed7ae1d12 100644 --- a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go +++ b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go @@ -21,14 +21,11 @@ import ( "errors" "fmt" "strings" - "time" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" - virtv1 "kubevirt.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -76,81 +73,12 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmSnapshot *v1alpha2.Virtu return reconcile.Result{}, err } - var frozen bool - if vm != nil { - frozenCondition, ok := conditions.GetCondition(vmcondition.TypeFilesystemFrozen, vm.Status.Conditions) - if ok && frozenCondition.Status == metav1.ConditionTrue { - frozen = true - } - } - - kvvmi, err := h.snapshotter.GetVirtualMachineInstance(ctx, vm) - if err != nil { - h.setPhaseConditionToFailed(cb, vmSnapshot, err) - return reconcile.Result{}, err - } - - err = h.snapshotter.SyncFSFreezeRequest(ctx, kvvmi) - switch { - case err == nil: - // OK. - case errors.Is(err, service.ErrUntrustedFilesystemFrozenCondition): - log.Debug(err.Error()) - cb. - Status(metav1.ConditionFalse). - Reason(vmscondition.Snapshotting). - Message(service.CapitalizeFirstLetter("Waiting for the filesystem of the virtual machine to be synced.")) - return reconcile.Result{}, nil - case k8serrors.IsConflict(err): - log.Debug(fmt.Sprintf("failed to sync filesystem status; resource update conflict error: %s", err)) - cb. - Status(metav1.ConditionFalse). - Reason(vmscondition.Snapshotting). - Message(service.CapitalizeFirstLetter("Waiting for the filesystem of the virtual machine to be synced.")) - return reconcile.Result{RequeueAfter: 5 * time.Second}, nil - default: - err = fmt.Errorf("failed to sync filesystem status: %w", err) - h.setPhaseConditionToFailed(cb, vmSnapshot, err) - return reconcile.Result{}, err - } - if vmSnapshot.DeletionTimestamp != nil { vmSnapshot.Status.Phase = v1alpha2.VirtualMachineSnapshotPhaseTerminating cb. Status(metav1.ConditionUnknown). Reason(conditions.ReasonUnknown). Message("") - - if !frozen { - return reconcile.Result{}, nil - } - - canUnfreeze, err := h.unfreezeVirtualMachineIfCan(ctx, vmSnapshot, vm, kvvmi) - if err != nil { - if errors.Is(err, service.ErrUntrustedFilesystemFrozenCondition) { - log.Debug(err.Error()) - cb. - Status(metav1.ConditionFalse). - Reason(vmscondition.Snapshotting). - Message(service.CapitalizeFirstLetter("Waiting for the filesystem of the virtual machine to be synced.")) - return reconcile.Result{}, nil - } - if k8serrors.IsConflict(err) { - log.Debug(fmt.Sprintf("failed to freeze filesystem; resource update conflict error: %s", err)) - cb. - Status(metav1.ConditionFalse). - Reason(vmscondition.Snapshotting). - Message(service.CapitalizeFirstLetter("Waiting for the filesystem of the virtual machine to be synced.")) - return reconcile.Result{RequeueAfter: 5 * time.Second}, nil - } - h.setPhaseConditionToFailed(cb, vmSnapshot, err) - return reconcile.Result{}, err - } - - if !canUnfreeze { - return reconcile.Result{RequeueAfter: 5 * time.Second}, nil - } - return reconcile.Result{}, nil } @@ -163,27 +91,6 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmSnapshot *v1alpha2.Virtu Status(readyCondition.Status). Reason(conditions.CommonReason(readyCondition.Reason)). Message(readyCondition.Message) - - if !frozen { - return reconcile.Result{}, nil - } - - canUnfreeze, err := h.unfreezeVirtualMachineIfCan(ctx, vmSnapshot, vm, kvvmi) - if err != nil { - if errors.Is(err, service.ErrUntrustedFilesystemFrozenCondition) { - log.Debug(err.Error()) - return reconcile.Result{}, nil - } - if k8serrors.IsConflict(err) { - log.Debug(fmt.Sprintf("failed to unfreeze filesystem; resource update conflict error: %s", err)) - return reconcile.Result{RequeueAfter: 5 * time.Second}, nil - } - cb.Message(fmt.Sprintf("%s, %s", err.Error(), cb.Condition().Message)) - return reconcile.Result{}, fmt.Errorf("failed to unfreeze filesystem: %w", err) - } - if !canUnfreeze { - return reconcile.Result{RequeueAfter: 5 * time.Second}, nil - } return reconcile.Result{}, nil case v1alpha2.VirtualMachineSnapshotPhaseReady: // Ensure vd snapshots aren't lost. @@ -291,45 +198,6 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmSnapshot *v1alpha2.Virtu return reconcile.Result{}, err } - needToFreeze, err := h.needToFreeze(vm, kvvmi, vmSnapshot) - if err != nil { - return reconcile.Result{}, err - } - - canFreeze, err := h.snapshotter.CanFreeze(ctx, kvvmi) - if err != nil { - h.setPhaseConditionToFailed(cb, vmSnapshot, err) - return reconcile.Result{}, err - } - isAwaitingConsistency := needToFreeze && !canFreeze && vmSnapshot.Spec.RequiredConsistency - if isAwaitingConsistency { - vmSnapshot.Status.Phase = v1alpha2.VirtualMachineSnapshotPhaseFailed - msg := fmt.Sprintf( - "Cannot take a consistent snapshot of virtual machine %q.", - vm.Name, - ) - - agentReadyCondition, _ := conditions.GetCondition(vmcondition.TypeAgentReady, vm.Status.Conditions) - if agentReadyCondition.Status != metav1.ConditionTrue { - msg = fmt.Sprintf( - "Cannot take a consistent snapshot of virtual machine %q: virtual machine agent is not ready and the virtual machine cannot be frozen.", - vm.Name, - ) - } - - h.recorder.Event( - vmSnapshot, - corev1.EventTypeWarning, - v1alpha2.ReasonVMSnapshottingFailed, - msg, - ) - cb. - Status(metav1.ConditionFalse). - Reason(vmscondition.PotentiallyInconsistent). - Message(msg) - return reconcile.Result{}, nil - } - if vmSnapshot.Status.Phase == v1alpha2.VirtualMachineSnapshotPhasePending { vmSnapshot.Status.Phase = v1alpha2.VirtualMachineSnapshotPhaseInProgress h.recorder.Event( @@ -340,39 +208,11 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmSnapshot *v1alpha2.Virtu ) cb. Status(metav1.ConditionFalse). - Reason(vmscondition.FileSystemFreezing). + Reason(vmscondition.Snapshotting). Message("The snapshotting process has started.") return reconcile.Result{Requeue: true}, nil } - var hasFrozen bool - - // 2. Ensure the virtual machine is consistent for snapshotting. - if needToFreeze { - hasFrozen, err = h.freezeVirtualMachine(ctx, kvvmi, vmSnapshot) - if err != nil { - if k8serrors.IsConflict(err) { - log.Debug(fmt.Sprintf("failed to freeze filesystem; resource update conflict error: %s", err)) - cb. - Status(metav1.ConditionFalse). - Reason(vmscondition.Snapshotting). - Message(service.CapitalizeFirstLetter("Waiting for the filesystem of the virtual machine to be synced.")) - return reconcile.Result{RequeueAfter: 5 * time.Second}, nil - } - h.setPhaseConditionToFailed(cb, vmSnapshot, err) - return reconcile.Result{}, err - } - } - - if hasFrozen { - vmSnapshot.Status.Phase = v1alpha2.VirtualMachineSnapshotPhaseInProgress - cb. - Status(metav1.ConditionFalse). - Reason(vmscondition.FileSystemFreezing). - Message(fmt.Sprintf("The virtual machine %q is in the process of being frozen for taking a snapshot.", vm.Name)) - return reconcile.Result{}, nil - } - // 3. Create secret. err = h.ensureSecret(ctx, vm, vmSnapshot) if err != nil { @@ -446,59 +286,15 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmSnapshot *v1alpha2.Virtu vmSnapshot.Status.Consistent = nil } - // 7. Unfreeze VirtualMachine if can. - unfrozen, err := h.unfreezeVirtualMachineIfCan(ctx, vmSnapshot, vm, kvvmi) - if err != nil { - if k8serrors.IsConflict(err) { - log.Debug(fmt.Sprintf("failed to unfreeze filesystem; resource update conflict error: %s", err)) - cb. - Status(metav1.ConditionFalse). - Reason(vmscondition.Snapshotting). - Message(service.CapitalizeFirstLetter("Waiting for the filesystem of the virtual machine to be synced.")) - return reconcile.Result{RequeueAfter: 5 * time.Second}, nil - } - vmSnapshot.Status.Phase = v1alpha2.VirtualMachineSnapshotPhaseInProgress - cb. - Status(metav1.ConditionFalse). - Reason(vmscondition.FileSystemUnfreezing). - Message(service.CapitalizeFirstLetter(err.Error() + ".")) - return reconcile.Result{}, err - } - - // 8. Fill status resources. + // 7. Fill status resources. err = h.fillStatusResources(ctx, vmSnapshot, vm) if err != nil { h.setPhaseConditionToFailed(cb, vmSnapshot, err) return reconcile.Result{}, err } - // 9. Synchronize FSFreezeRequest with KVVMI status. - err = h.snapshotter.SyncFSFreezeRequest(ctx, kvvmi) - switch { - case err == nil: - // OK. - case errors.Is(err, service.ErrUntrustedFilesystemFrozenCondition): - log.Debug(err.Error()) - cb. - Status(metav1.ConditionFalse). - Reason(vmscondition.Snapshotting). - Message(service.CapitalizeFirstLetter("Waiting for the filesystem of the virtual machine to be synced.")) - return reconcile.Result{}, nil - case k8serrors.IsConflict(err): - log.Debug(fmt.Sprintf("failed to sync filesystem status; resource update conflict error: %s", err)) - cb. - Status(metav1.ConditionFalse). - Reason(vmscondition.Snapshotting). - Message(service.CapitalizeFirstLetter("Waiting for the filesystem of the virtual machine to be synced.")) - return reconcile.Result{RequeueAfter: 5 * time.Second}, nil - default: - err = fmt.Errorf("failed to sync filesystem status: %w", err) - h.setPhaseConditionToFailed(cb, vmSnapshot, err) - return reconcile.Result{}, err - } - - // 10. Move to Ready phase. - log.Debug("The virtual disk snapshots are taken: the virtual machine snapshot is Ready now", "unfrozen", unfrozen) + // 8. Move to Ready phase. + log.Debug("The virtual disk snapshots are taken: the virtual machine snapshot is Ready now") vmSnapshot.Status.Phase = v1alpha2.VirtualMachineSnapshotPhaseReady h.recorder.Event( @@ -641,87 +437,6 @@ func (h LifeCycleHandler) areVirtualDiskSnapshotsConsistent(vdSnapshots []*v1alp return true } -func (h LifeCycleHandler) needToFreeze(vm *v1alpha2.VirtualMachine, kvvmi *virtv1.VirtualMachineInstance, vmsnapshot *v1alpha2.VirtualMachineSnapshot) (bool, error) { - if vmsnapshot.Status.Consistent != nil && *vmsnapshot.Status.Consistent { - return false, nil - } - - if !vmsnapshot.Spec.RequiredConsistency { - return false, nil - } - - if vm.Status.Phase == v1alpha2.MachineStopped { - return false, nil - } - - isFrozen, err := h.snapshotter.IsFrozen(kvvmi) - if err != nil { - return false, err - } - if isFrozen { - return false, nil - } - - return true, nil -} - -func (h LifeCycleHandler) freezeVirtualMachine(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance, vmSnapshot *v1alpha2.VirtualMachineSnapshot) (bool, error) { - if kvvmi.Status.Phase != virtv1.Running { - return false, fmt.Errorf("cannot freeze not Running %s/%s virtual machine", kvvmi.Namespace, kvvmi.Name) - } - - err := h.snapshotter.Freeze(ctx, kvvmi) - if err != nil { - return false, fmt.Errorf("freeze the virtual machine %s/%s: %w", kvvmi.Namespace, kvvmi.Name, err) - } - - h.recorder.Event( - vmSnapshot, - corev1.EventTypeNormal, - v1alpha2.ReasonVMSnapshottingFrozen, - fmt.Sprintf("The file system of the virtual machine %q is frozen.", kvvmi.Name), - ) - - return true, nil -} - -func (h LifeCycleHandler) unfreezeVirtualMachineIfCan(ctx context.Context, vmSnapshot *v1alpha2.VirtualMachineSnapshot, vm *v1alpha2.VirtualMachine, kvvmi *virtv1.VirtualMachineInstance) (bool, error) { - if vm == nil || vm.Status.Phase != v1alpha2.MachineRunning { - return false, nil - } - - isFrozen, err := h.snapshotter.IsFrozen(kvvmi) - if err != nil { - return false, err - } - if !isFrozen { - return false, nil - } - - canUnfreeze, err := h.snapshotter.CanUnfreezeWithVirtualMachineSnapshot(ctx, vmSnapshot.Name, vm, kvvmi) - if err != nil { - return false, err - } - - if !canUnfreeze { - return false, nil - } - - err = h.snapshotter.Unfreeze(ctx, kvvmi) - if err != nil { - return false, fmt.Errorf("unfreeze the virtual machine %q: %w", vm.Name, err) - } - - h.recorder.Event( - vmSnapshot, - corev1.EventTypeNormal, - v1alpha2.ReasonVMSnapshottingThawed, - fmt.Sprintf("The file system of the virtual machine %q is thawed.", vm.Name), - ) - - return true, nil -} - var ( ErrBlockDevicesNotReady = errors.New("block devices not ready") ErrVirtualDiskNotReady = errors.New("virtual disk not ready") diff --git a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go index ae8fc6d345..2b93af3ea5 100644 --- a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go +++ b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go @@ -25,7 +25,6 @@ import ( apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" - virtv1 "kubevirt.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/deckhouse/virtualization-controller/pkg/common/testutil" @@ -43,7 +42,6 @@ var _ = Describe("LifeCycle handler", func() { var storer *StorerMock var vd *v1alpha2.VirtualDisk var vm *v1alpha2.VirtualMachine - var kvvmi *virtv1.VirtualMachineInstance var secret *corev1.Secret var vdSnapshot *v1alpha2.VirtualDiskSnapshot var vmSnapshot *v1alpha2.VirtualMachineSnapshot @@ -90,13 +88,6 @@ var _ = Describe("LifeCycle handler", func() { }, } - kvvmi = &virtv1.VirtualMachineInstance{ - ObjectMeta: metav1.ObjectMeta{Name: "vm"}, - Status: virtv1.VirtualMachineInstanceStatus{ - Phase: virtv1.Running, - }, - } - secret = &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Name: vm.Name}, } @@ -133,30 +124,12 @@ var _ = Describe("LifeCycle handler", func() { GetVirtualMachineFunc: func(_ context.Context, _, _ string) (*v1alpha2.VirtualMachine, error) { return vm, nil }, - IsFrozenFunc: func(*virtv1.VirtualMachineInstance) (bool, error) { - return true, nil - }, - CanUnfreezeWithVirtualMachineSnapshotFunc: func(_ context.Context, _ string, _ *v1alpha2.VirtualMachine, _ *virtv1.VirtualMachineInstance) (bool, error) { - return true, nil - }, - CanFreezeFunc: func(_ context.Context, _ *virtv1.VirtualMachineInstance) (bool, error) { - return false, nil - }, - UnfreezeFunc: func(ctx context.Context, _ *virtv1.VirtualMachineInstance) error { - return nil - }, GetSecretFunc: func(_ context.Context, _, _ string) (*corev1.Secret, error) { return secret, nil }, GetVirtualDiskSnapshotFunc: func(_ context.Context, _, _ string) (*v1alpha2.VirtualDiskSnapshot, error) { return vdSnapshot, nil }, - GetVirtualMachineInstanceFunc: func(_ context.Context, _ *v1alpha2.VirtualMachine) (*virtv1.VirtualMachineInstance, error) { - return kvvmi, nil - }, - SyncFSFreezeRequestFunc: func(_ context.Context, _ *virtv1.VirtualMachineInstance) error { - return nil - }, } var err error @@ -293,50 +266,9 @@ var _ = Describe("LifeCycle handler", func() { Expect(vmSnapshot.Status.Phase).To(Equal(v1alpha2.VirtualMachineSnapshotPhaseInProgress)) ready, _ := conditions.GetCondition(vmscondition.VirtualMachineSnapshotReadyType, vmSnapshot.Status.Conditions) Expect(ready.Status).To(Equal(metav1.ConditionFalse)) - Expect(ready.Reason).To(Equal(vmscondition.FileSystemFreezing.String())) + Expect(ready.Reason).To(Equal(vmscondition.Snapshotting.String())) Expect(ready.Message).To(Equal("The snapshotting process has started.")) }) - - It("The virtual machine is potentially inconsistent", func() { - snapshotter.IsFrozenFunc = func(_ *virtv1.VirtualMachineInstance) (bool, error) { - return false, nil - } - snapshotter.CanFreezeFunc = func(_ context.Context, _ *virtv1.VirtualMachineInstance) (bool, error) { - return false, nil - } - - h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) - - _, err := h.Handle(testContext(), vmSnapshot) - Expect(err).To(BeNil()) - Expect(vmSnapshot.Status.Phase).To(Equal(v1alpha2.VirtualMachineSnapshotPhaseFailed)) - ready, _ := conditions.GetCondition(vmscondition.VirtualMachineSnapshotReadyType, vmSnapshot.Status.Conditions) - Expect(ready.Status).To(Equal(metav1.ConditionFalse)) - Expect(ready.Reason).To(Equal(vmscondition.PotentiallyInconsistent.String())) - Expect(ready.Message).ToNot(BeEmpty()) - }) - - It("The virtual machine has frozen", func() { - snapshotter.IsFrozenFunc = func(_ *virtv1.VirtualMachineInstance) (bool, error) { - return false, nil - } - snapshotter.CanFreezeFunc = func(_ context.Context, _ *virtv1.VirtualMachineInstance) (bool, error) { - return true, nil - } - snapshotter.FreezeFunc = func(_ context.Context, _ *virtv1.VirtualMachineInstance) error { - return nil - } - - h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) - - _, err := h.Handle(testContext(), vmSnapshot) - Expect(err).To(BeNil()) - Expect(vmSnapshot.Status.Phase).To(Equal(v1alpha2.VirtualMachineSnapshotPhaseInProgress)) - ready, _ := conditions.GetCondition(vmscondition.VirtualMachineSnapshotReadyType, vmSnapshot.Status.Conditions) - Expect(ready.Status).To(Equal(metav1.ConditionFalse)) - Expect(ready.Reason).To(Equal(vmscondition.FileSystemFreezing.String())) - Expect(ready.Message).ToNot(BeEmpty()) - }) }) Context("The virtual machine snapshot is Ready", func() { diff --git a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/mock.go b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/mock.go index 67e5c82199..6dd0424961 100644 --- a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/mock.go +++ b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/mock.go @@ -7,7 +7,6 @@ import ( "context" "github.com/deckhouse/virtualization/api/core/v1alpha2" corev1 "k8s.io/api/core/v1" - virtv1 "kubevirt.io/api/core/v1" "sync" ) @@ -99,18 +98,9 @@ var _ Snapshotter = &SnapshotterMock{} // // // make and configure a mocked Snapshotter // mockedSnapshotter := &SnapshotterMock{ -// CanFreezeFunc: func(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) (bool, error) { -// panic("mock out the CanFreeze method") -// }, -// CanUnfreezeWithVirtualMachineSnapshotFunc: func(ctx context.Context, vmSnapshotName string, vm *v1alpha2.VirtualMachine, kvvmi *virtv1.VirtualMachineInstance) (bool, error) { -// panic("mock out the CanUnfreezeWithVirtualMachineSnapshot method") -// }, // CreateVirtualDiskSnapshotFunc: func(ctx context.Context, vdSnapshot *v1alpha2.VirtualDiskSnapshot) (*v1alpha2.VirtualDiskSnapshot, error) { // panic("mock out the CreateVirtualDiskSnapshot method") // }, -// FreezeFunc: func(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error { -// panic("mock out the Freeze method") -// }, // GetPersistentVolumeClaimFunc: func(ctx context.Context, name string, namespace string) (*corev1.PersistentVolumeClaim, error) { // panic("mock out the GetPersistentVolumeClaim method") // }, @@ -126,18 +116,6 @@ var _ Snapshotter = &SnapshotterMock{} // GetVirtualMachineFunc: func(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualMachine, error) { // panic("mock out the GetVirtualMachine method") // }, -// GetVirtualMachineInstanceFunc: func(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachineInstance, error) { -// panic("mock out the GetVirtualMachineInstance method") -// }, -// IsFrozenFunc: func(kvvmi *virtv1.VirtualMachineInstance) (bool, error) { -// panic("mock out the IsFrozen method") -// }, -// SyncFSFreezeRequestFunc: func(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error { -// panic("mock out the SyncFSFreezeRequest method") -// }, -// UnfreezeFunc: func(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error { -// panic("mock out the Unfreeze method") -// }, // } // // // use mockedSnapshotter in code that requires Snapshotter @@ -145,18 +123,9 @@ var _ Snapshotter = &SnapshotterMock{} // // } type SnapshotterMock struct { - // CanFreezeFunc mocks the CanFreeze method. - CanFreezeFunc func(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) (bool, error) - - // CanUnfreezeWithVirtualMachineSnapshotFunc mocks the CanUnfreezeWithVirtualMachineSnapshot method. - CanUnfreezeWithVirtualMachineSnapshotFunc func(ctx context.Context, vmSnapshotName string, vm *v1alpha2.VirtualMachine, kvvmi *virtv1.VirtualMachineInstance) (bool, error) - // CreateVirtualDiskSnapshotFunc mocks the CreateVirtualDiskSnapshot method. CreateVirtualDiskSnapshotFunc func(ctx context.Context, vdSnapshot *v1alpha2.VirtualDiskSnapshot) (*v1alpha2.VirtualDiskSnapshot, error) - // FreezeFunc mocks the Freeze method. - FreezeFunc func(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error - // GetPersistentVolumeClaimFunc mocks the GetPersistentVolumeClaim method. GetPersistentVolumeClaimFunc func(ctx context.Context, name string, namespace string) (*corev1.PersistentVolumeClaim, error) @@ -172,38 +141,8 @@ type SnapshotterMock struct { // GetVirtualMachineFunc mocks the GetVirtualMachine method. GetVirtualMachineFunc func(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualMachine, error) - // GetVirtualMachineInstanceFunc mocks the GetVirtualMachineInstance method. - GetVirtualMachineInstanceFunc func(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachineInstance, error) - - // IsFrozenFunc mocks the IsFrozen method. - IsFrozenFunc func(kvvmi *virtv1.VirtualMachineInstance) (bool, error) - - // SyncFSFreezeRequestFunc mocks the SyncFSFreezeRequest method. - SyncFSFreezeRequestFunc func(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error - - // UnfreezeFunc mocks the Unfreeze method. - UnfreezeFunc func(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error - // calls tracks calls to the methods. calls struct { - // CanFreeze holds details about calls to the CanFreeze method. - CanFreeze []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Kvvmi is the kvvmi argument value. - Kvvmi *virtv1.VirtualMachineInstance - } - // CanUnfreezeWithVirtualMachineSnapshot holds details about calls to the CanUnfreezeWithVirtualMachineSnapshot method. - CanUnfreezeWithVirtualMachineSnapshot []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // VmSnapshotName is the vmSnapshotName argument value. - VmSnapshotName string - // VM is the vm argument value. - VM *v1alpha2.VirtualMachine - // Kvvmi is the kvvmi argument value. - Kvvmi *virtv1.VirtualMachineInstance - } // CreateVirtualDiskSnapshot holds details about calls to the CreateVirtualDiskSnapshot method. CreateVirtualDiskSnapshot []struct { // Ctx is the ctx argument value. @@ -211,13 +150,6 @@ type SnapshotterMock struct { // VdSnapshot is the vdSnapshot argument value. VdSnapshot *v1alpha2.VirtualDiskSnapshot } - // Freeze holds details about calls to the Freeze method. - Freeze []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Kvvmi is the kvvmi argument value. - Kvvmi *virtv1.VirtualMachineInstance - } // GetPersistentVolumeClaim holds details about calls to the GetPersistentVolumeClaim method. GetPersistentVolumeClaim []struct { // Ctx is the ctx argument value. @@ -263,126 +195,13 @@ type SnapshotterMock struct { // Namespace is the namespace argument value. Namespace string } - // GetVirtualMachineInstance holds details about calls to the GetVirtualMachineInstance method. - GetVirtualMachineInstance []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // VM is the vm argument value. - VM *v1alpha2.VirtualMachine - } - // IsFrozen holds details about calls to the IsFrozen method. - IsFrozen []struct { - // Kvvmi is the kvvmi argument value. - Kvvmi *virtv1.VirtualMachineInstance - } - // SyncFSFreezeRequest holds details about calls to the SyncFSFreezeRequest method. - SyncFSFreezeRequest []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Kvvmi is the kvvmi argument value. - Kvvmi *virtv1.VirtualMachineInstance - } - // Unfreeze holds details about calls to the Unfreeze method. - Unfreeze []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Kvvmi is the kvvmi argument value. - Kvvmi *virtv1.VirtualMachineInstance - } - } - lockCanFreeze sync.RWMutex - lockCanUnfreezeWithVirtualMachineSnapshot sync.RWMutex - lockCreateVirtualDiskSnapshot sync.RWMutex - lockFreeze sync.RWMutex - lockGetPersistentVolumeClaim sync.RWMutex - lockGetSecret sync.RWMutex - lockGetVirtualDisk sync.RWMutex - lockGetVirtualDiskSnapshot sync.RWMutex - lockGetVirtualMachine sync.RWMutex - lockGetVirtualMachineInstance sync.RWMutex - lockIsFrozen sync.RWMutex - lockSyncFSFreezeRequest sync.RWMutex - lockUnfreeze sync.RWMutex -} - -// CanFreeze calls CanFreezeFunc. -func (mock *SnapshotterMock) CanFreeze(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) (bool, error) { - if mock.CanFreezeFunc == nil { - panic("SnapshotterMock.CanFreezeFunc: method is nil but Snapshotter.CanFreeze was just called") - } - callInfo := struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance - }{ - Ctx: ctx, - Kvvmi: kvvmi, - } - mock.lockCanFreeze.Lock() - mock.calls.CanFreeze = append(mock.calls.CanFreeze, callInfo) - mock.lockCanFreeze.Unlock() - return mock.CanFreezeFunc(ctx, kvvmi) -} - -// CanFreezeCalls gets all the calls that were made to CanFreeze. -// Check the length with: -// -// len(mockedSnapshotter.CanFreezeCalls()) -func (mock *SnapshotterMock) CanFreezeCalls() []struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance -} { - var calls []struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance - } - mock.lockCanFreeze.RLock() - calls = mock.calls.CanFreeze - mock.lockCanFreeze.RUnlock() - return calls -} - -// CanUnfreezeWithVirtualMachineSnapshot calls CanUnfreezeWithVirtualMachineSnapshotFunc. -func (mock *SnapshotterMock) CanUnfreezeWithVirtualMachineSnapshot(ctx context.Context, vmSnapshotName string, vm *v1alpha2.VirtualMachine, kvvmi *virtv1.VirtualMachineInstance) (bool, error) { - if mock.CanUnfreezeWithVirtualMachineSnapshotFunc == nil { - panic("SnapshotterMock.CanUnfreezeWithVirtualMachineSnapshotFunc: method is nil but Snapshotter.CanUnfreezeWithVirtualMachineSnapshot was just called") } - callInfo := struct { - Ctx context.Context - VmSnapshotName string - VM *v1alpha2.VirtualMachine - Kvvmi *virtv1.VirtualMachineInstance - }{ - Ctx: ctx, - VmSnapshotName: vmSnapshotName, - VM: vm, - Kvvmi: kvvmi, - } - mock.lockCanUnfreezeWithVirtualMachineSnapshot.Lock() - mock.calls.CanUnfreezeWithVirtualMachineSnapshot = append(mock.calls.CanUnfreezeWithVirtualMachineSnapshot, callInfo) - mock.lockCanUnfreezeWithVirtualMachineSnapshot.Unlock() - return mock.CanUnfreezeWithVirtualMachineSnapshotFunc(ctx, vmSnapshotName, vm, kvvmi) -} - -// CanUnfreezeWithVirtualMachineSnapshotCalls gets all the calls that were made to CanUnfreezeWithVirtualMachineSnapshot. -// Check the length with: -// -// len(mockedSnapshotter.CanUnfreezeWithVirtualMachineSnapshotCalls()) -func (mock *SnapshotterMock) CanUnfreezeWithVirtualMachineSnapshotCalls() []struct { - Ctx context.Context - VmSnapshotName string - VM *v1alpha2.VirtualMachine - Kvvmi *virtv1.VirtualMachineInstance -} { - var calls []struct { - Ctx context.Context - VmSnapshotName string - VM *v1alpha2.VirtualMachine - Kvvmi *virtv1.VirtualMachineInstance - } - mock.lockCanUnfreezeWithVirtualMachineSnapshot.RLock() - calls = mock.calls.CanUnfreezeWithVirtualMachineSnapshot - mock.lockCanUnfreezeWithVirtualMachineSnapshot.RUnlock() - return calls + lockCreateVirtualDiskSnapshot sync.RWMutex + lockGetPersistentVolumeClaim sync.RWMutex + lockGetSecret sync.RWMutex + lockGetVirtualDisk sync.RWMutex + lockGetVirtualDiskSnapshot sync.RWMutex + lockGetVirtualMachine sync.RWMutex } // CreateVirtualDiskSnapshot calls CreateVirtualDiskSnapshotFunc. @@ -421,42 +240,6 @@ func (mock *SnapshotterMock) CreateVirtualDiskSnapshotCalls() []struct { return calls } -// Freeze calls FreezeFunc. -func (mock *SnapshotterMock) Freeze(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error { - if mock.FreezeFunc == nil { - panic("SnapshotterMock.FreezeFunc: method is nil but Snapshotter.Freeze was just called") - } - callInfo := struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance - }{ - Ctx: ctx, - Kvvmi: kvvmi, - } - mock.lockFreeze.Lock() - mock.calls.Freeze = append(mock.calls.Freeze, callInfo) - mock.lockFreeze.Unlock() - return mock.FreezeFunc(ctx, kvvmi) -} - -// FreezeCalls gets all the calls that were made to Freeze. -// Check the length with: -// -// len(mockedSnapshotter.FreezeCalls()) -func (mock *SnapshotterMock) FreezeCalls() []struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance -} { - var calls []struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance - } - mock.lockFreeze.RLock() - calls = mock.calls.Freeze - mock.lockFreeze.RUnlock() - return calls -} - // GetPersistentVolumeClaim calls GetPersistentVolumeClaimFunc. func (mock *SnapshotterMock) GetPersistentVolumeClaim(ctx context.Context, name string, namespace string) (*corev1.PersistentVolumeClaim, error) { if mock.GetPersistentVolumeClaimFunc == nil { @@ -656,143 +439,3 @@ func (mock *SnapshotterMock) GetVirtualMachineCalls() []struct { mock.lockGetVirtualMachine.RUnlock() return calls } - -// GetVirtualMachineInstance calls GetVirtualMachineInstanceFunc. -func (mock *SnapshotterMock) GetVirtualMachineInstance(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachineInstance, error) { - if mock.GetVirtualMachineInstanceFunc == nil { - panic("SnapshotterMock.GetVirtualMachineInstanceFunc: method is nil but Snapshotter.GetVirtualMachineInstance was just called") - } - callInfo := struct { - Ctx context.Context - VM *v1alpha2.VirtualMachine - }{ - Ctx: ctx, - VM: vm, - } - mock.lockGetVirtualMachineInstance.Lock() - mock.calls.GetVirtualMachineInstance = append(mock.calls.GetVirtualMachineInstance, callInfo) - mock.lockGetVirtualMachineInstance.Unlock() - return mock.GetVirtualMachineInstanceFunc(ctx, vm) -} - -// GetVirtualMachineInstanceCalls gets all the calls that were made to GetVirtualMachineInstance. -// Check the length with: -// -// len(mockedSnapshotter.GetVirtualMachineInstanceCalls()) -func (mock *SnapshotterMock) GetVirtualMachineInstanceCalls() []struct { - Ctx context.Context - VM *v1alpha2.VirtualMachine -} { - var calls []struct { - Ctx context.Context - VM *v1alpha2.VirtualMachine - } - mock.lockGetVirtualMachineInstance.RLock() - calls = mock.calls.GetVirtualMachineInstance - mock.lockGetVirtualMachineInstance.RUnlock() - return calls -} - -// IsFrozen calls IsFrozenFunc. -func (mock *SnapshotterMock) IsFrozen(kvvmi *virtv1.VirtualMachineInstance) (bool, error) { - if mock.IsFrozenFunc == nil { - panic("SnapshotterMock.IsFrozenFunc: method is nil but Snapshotter.IsFrozen was just called") - } - callInfo := struct { - Kvvmi *virtv1.VirtualMachineInstance - }{ - Kvvmi: kvvmi, - } - mock.lockIsFrozen.Lock() - mock.calls.IsFrozen = append(mock.calls.IsFrozen, callInfo) - mock.lockIsFrozen.Unlock() - return mock.IsFrozenFunc(kvvmi) -} - -// IsFrozenCalls gets all the calls that were made to IsFrozen. -// Check the length with: -// -// len(mockedSnapshotter.IsFrozenCalls()) -func (mock *SnapshotterMock) IsFrozenCalls() []struct { - Kvvmi *virtv1.VirtualMachineInstance -} { - var calls []struct { - Kvvmi *virtv1.VirtualMachineInstance - } - mock.lockIsFrozen.RLock() - calls = mock.calls.IsFrozen - mock.lockIsFrozen.RUnlock() - return calls -} - -// SyncFSFreezeRequest calls SyncFSFreezeRequestFunc. -func (mock *SnapshotterMock) SyncFSFreezeRequest(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error { - if mock.SyncFSFreezeRequestFunc == nil { - panic("SnapshotterMock.SyncFSFreezeRequestFunc: method is nil but Snapshotter.SyncFSFreezeRequest was just called") - } - callInfo := struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance - }{ - Ctx: ctx, - Kvvmi: kvvmi, - } - mock.lockSyncFSFreezeRequest.Lock() - mock.calls.SyncFSFreezeRequest = append(mock.calls.SyncFSFreezeRequest, callInfo) - mock.lockSyncFSFreezeRequest.Unlock() - return mock.SyncFSFreezeRequestFunc(ctx, kvvmi) -} - -// SyncFSFreezeRequestCalls gets all the calls that were made to SyncFSFreezeRequest. -// Check the length with: -// -// len(mockedSnapshotter.SyncFSFreezeRequestCalls()) -func (mock *SnapshotterMock) SyncFSFreezeRequestCalls() []struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance -} { - var calls []struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance - } - mock.lockSyncFSFreezeRequest.RLock() - calls = mock.calls.SyncFSFreezeRequest - mock.lockSyncFSFreezeRequest.RUnlock() - return calls -} - -// Unfreeze calls UnfreezeFunc. -func (mock *SnapshotterMock) Unfreeze(ctx context.Context, kvvmi *virtv1.VirtualMachineInstance) error { - if mock.UnfreezeFunc == nil { - panic("SnapshotterMock.UnfreezeFunc: method is nil but Snapshotter.Unfreeze was just called") - } - callInfo := struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance - }{ - Ctx: ctx, - Kvvmi: kvvmi, - } - mock.lockUnfreeze.Lock() - mock.calls.Unfreeze = append(mock.calls.Unfreeze, callInfo) - mock.lockUnfreeze.Unlock() - return mock.UnfreezeFunc(ctx, kvvmi) -} - -// UnfreezeCalls gets all the calls that were made to Unfreeze. -// Check the length with: -// -// len(mockedSnapshotter.UnfreezeCalls()) -func (mock *SnapshotterMock) UnfreezeCalls() []struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance -} { - var calls []struct { - Ctx context.Context - Kvvmi *virtv1.VirtualMachineInstance - } - mock.lockUnfreeze.RLock() - calls = mock.calls.Unfreeze - mock.lockUnfreeze.RUnlock() - return calls -}