diff --git a/images/virtualization-artifact/pkg/controller/vmop/migration/internal/handler/lifecycle_test.go b/images/virtualization-artifact/pkg/controller/vmop/migration/internal/handler/lifecycle_test.go index 4b0495882e..94d139f9a9 100644 --- a/images/virtualization-artifact/pkg/controller/vmop/migration/internal/handler/lifecycle_test.go +++ b/images/virtualization-artifact/pkg/controller/vmop/migration/internal/handler/lifecycle_test.go @@ -152,10 +152,10 @@ var _ = Describe("LifecycleHandler", func() { ), // AlwaysForced cases. - Entry("should become Failed for AlwaysForced and force=nil", + Entry("is ok for AlwaysForced and force=nil", newVMOPEvictPending(), v1alpha2.AlwaysForcedMigrationPolicy, - v1alpha2.VMOPPhaseFailed, + v1alpha2.VMOPPhasePending, ), Entry("should become Failed for AlwaysForced and force=false", newVMOPEvictPending(vmopbuilder.WithForce(ptr.To(false))), diff --git a/images/virtualization-artifact/pkg/livemigration/policy.go b/images/virtualization-artifact/pkg/livemigration/policy.go index 1dad3de38e..d5b8f60a73 100644 --- a/images/virtualization-artifact/pkg/livemigration/policy.go +++ b/images/virtualization-artifact/pkg/livemigration/policy.go @@ -49,11 +49,7 @@ func CalculateEffectivePolicy(vm v1alpha2.VirtualMachine, vmop *v1alpha2.Virtual // Override autoConverge value. if vmop != nil { switch effectivePolicy { - case v1alpha2.PreferSafeMigrationPolicy: - if vmop.Spec.Force != nil { - autoConvergePtr = vmop.Spec.Force - } - case v1alpha2.PreferForcedMigrationPolicy: + case v1alpha2.PreferSafeMigrationPolicy, v1alpha2.PreferForcedMigrationPolicy: if vmop.Spec.Force != nil { autoConvergePtr = vmop.Spec.Force } @@ -62,8 +58,8 @@ func CalculateEffectivePolicy(vm v1alpha2.VirtualMachine, vmop *v1alpha2.Virtual return effectivePolicy, *autoConvergePtr, fmt.Errorf("force=true is not applicable for VM liveMigrationPolicy %s", effectivePolicy) } case v1alpha2.AlwaysForcedMigrationPolicy: - if vmop.Spec.Force == nil || !*vmop.Spec.Force { - return effectivePolicy, *autoConvergePtr, fmt.Errorf("force=true is required for VM liveMigrationPolicy %s", effectivePolicy) + if vmop.Spec.Force != nil && !*vmop.Spec.Force { + return effectivePolicy, *autoConvergePtr, fmt.Errorf("force=false is not applicable for VM liveMigrationPolicy %s", effectivePolicy) } } } diff --git a/src/cli/internal/cmd/lifecycle/lifecycle.go b/src/cli/internal/cmd/lifecycle/lifecycle.go index 4074f93609..8735ca9afe 100644 --- a/src/cli/internal/cmd/lifecycle/lifecycle.go +++ b/src/cli/internal/cmd/lifecycle/lifecycle.go @@ -30,6 +30,7 @@ import ( k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" "github.com/deckhouse/virtualization/api/client/kubeclient" "github.com/deckhouse/virtualization/src/cli/internal/clientconfig" @@ -106,7 +107,8 @@ func (l *Lifecycle) Run(cmd *cobra.Command, args []string) error { if err != nil { return err } - mgr := l.getManager(client) + forceSet := cmd.Flags().Changed(forceFlag) + mgr := l.getManager(client, forceSet) ctx, cancel := context.WithTimeout(context.Background(), l.opts.Timeout) defer cancel() @@ -166,12 +168,17 @@ func (l *Lifecycle) getNameNamespace(defaultNamespace string, args []string) (st return name, namespace, nil } -func (l *Lifecycle) getManager(client kubeclient.Client) Manager { +func (l *Lifecycle) getManager(client kubeclient.Client, forceSet bool) Manager { + var forcePtr *bool + if forceSet { + forcePtr = ptr.To(l.opts.Force) + } + return vmop.New( client, vmop.WithCreateOnly(l.opts.CreateOnly), vmop.WithWaitComplete(l.opts.WaitComplete), - vmop.WithForce(l.opts.Force), + vmop.WithForce(forcePtr), ) } diff --git a/src/cli/internal/cmd/lifecycle/vmop/vmop.go b/src/cli/internal/cmd/lifecycle/vmop/vmop.go index cc3ebf8ca0..20f297c2c0 100644 --- a/src/cli/internal/cmd/lifecycle/vmop/vmop.go +++ b/src/cli/internal/cmd/lifecycle/vmop/vmop.go @@ -25,7 +25,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/types" - "k8s.io/utils/ptr" "github.com/deckhouse/virtualization/api/client/kubeclient" "github.com/deckhouse/virtualization/api/core/v1alpha2" @@ -38,7 +37,7 @@ type VirtualMachineOperation struct { } type options struct { - force bool + force *bool waitComplete bool createOnly bool } @@ -56,7 +55,7 @@ func New(client kubeclient.Client, opts ...func(*VirtualMachineOperation)) *Virt return vmop } -func WithForce(force bool) func(*VirtualMachineOperation) { +func WithForce(force *bool) func(*VirtualMachineOperation) { return func(o *VirtualMachineOperation) { o.options.force = force } @@ -80,7 +79,7 @@ func (v VirtualMachineOperation) Stop(ctx context.Context, vmName, vmNamespace s } func (v VirtualMachineOperation) Start(ctx context.Context, vmName, vmNamespace string) (msg string, err error) { - vmop := v.newVMOP(vmName, vmNamespace, v1alpha2.VMOPTypeStart, false) + vmop := v.newVMOP(vmName, vmNamespace, v1alpha2.VMOPTypeStart, nil) return v.do(ctx, vmop, v.options.createOnly, v.options.waitComplete) } @@ -237,7 +236,7 @@ func (v VirtualMachineOperation) isPhaseOrFailed(vmop *v1alpha2.VirtualMachineOp return vmop.Status.Phase == phase || vmop.Status.Phase == v1alpha2.VMOPPhaseFailed } -func (v VirtualMachineOperation) newVMOP(vmName, vmNamespace string, t v1alpha2.VMOPType, force bool) *v1alpha2.VirtualMachineOperation { +func (v VirtualMachineOperation) newVMOP(vmName, vmNamespace string, t v1alpha2.VMOPType, force *bool) *v1alpha2.VirtualMachineOperation { return &v1alpha2.VirtualMachineOperation{ TypeMeta: metav1.TypeMeta{ Kind: v1alpha2.VirtualMachineOperationKind, @@ -250,7 +249,7 @@ func (v VirtualMachineOperation) newVMOP(vmName, vmNamespace string, t v1alpha2. Spec: v1alpha2.VirtualMachineOperationSpec{ Type: t, VirtualMachine: vmName, - Force: ptr.To(force), + Force: force, }, } }