diff --git a/images/virtualization-artifact/pkg/controller/powerstate/kvvm_request.go b/images/virtualization-artifact/pkg/controller/powerstate/kvvm_request.go index 122f3ea547..3d5124efdc 100644 --- a/images/virtualization-artifact/pkg/controller/powerstate/kvvm_request.go +++ b/images/virtualization-artifact/pkg/controller/powerstate/kvvm_request.go @@ -17,6 +17,7 @@ limitations under the License. package powerstate import ( + "errors" "fmt" "k8s.io/apimachinery/pkg/api/equality" @@ -25,6 +26,8 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/common/patch" ) +var ErrChangesAlreadyExist = errors.New("changes already exist in the current status") + // BuildPatch creates a patch to request VM state changing via updating KVVM status. // // Some combinations lead to an error to not interfere with kvvm controller: @@ -49,6 +52,10 @@ func BuildPatch(vm *kvv1.VirtualMachine, changes ...kvv1.VirtualMachineStateChan failOnConflict = false } if len(vm.Status.StateChangeRequests) != 0 { + if equality.Semantic.DeepEqual(vm.Status.StateChangeRequests, changes) { + return nil, ErrChangesAlreadyExist + } + if failOnConflict { return nil, fmt.Errorf("unable to complete request: stop/start already underway") } else { diff --git a/images/virtualization-artifact/pkg/controller/powerstate/operations.go b/images/virtualization-artifact/pkg/controller/powerstate/operations.go index 37fbdda0f4..d15f3c6e8e 100644 --- a/images/virtualization-artifact/pkg/controller/powerstate/operations.go +++ b/images/virtualization-artifact/pkg/controller/powerstate/operations.go @@ -18,6 +18,7 @@ package powerstate import ( "context" + "errors" "fmt" "k8s.io/apimachinery/pkg/types" @@ -36,6 +37,9 @@ func StartVM(ctx context.Context, cl client.Client, kvvm *kvv1.VirtualMachine) e jp, err := BuildPatch(kvvm, kvv1.VirtualMachineStateChangeRequest{Action: kvv1.StartRequest}) if err != nil { + if errors.Is(err, ErrChangesAlreadyExist) { + return nil + } return err } return cl.Status().Patch(ctx, kvvm, client.RawPatch(types.JSONPatchType, jp), &client.SubResourcePatchOptions{}) @@ -70,6 +74,9 @@ func RestartVM(ctx context.Context, cl client.Client, kvvm *kvv1.VirtualMachine, kvv1.VirtualMachineStateChangeRequest{Action: kvv1.StopRequest, UID: &kvvmi.UID}, kvv1.VirtualMachineStateChangeRequest{Action: kvv1.StartRequest}) if err != nil { + if errors.Is(err, ErrChangesAlreadyExist) { + return nil + } return err } diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/sync_power_state.go b/images/virtualization-artifact/pkg/controller/vm/internal/sync_power_state.go index fefa4aaf9f..5c70e48a36 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/sync_power_state.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/sync_power_state.go @@ -70,6 +70,9 @@ func (h *SyncPowerStateHandler) Handle(ctx context.Context, s state.VirtualMachi } changed := s.VirtualMachine().Changed() + if isDeletion(changed) { + return reconcile.Result{}, nil + } kvvm, err := s.KVVM(ctx) if err != nil { @@ -209,6 +212,17 @@ func (h *SyncPowerStateHandler) handleManualPolicy( return Nothing } +func (h *SyncPowerStateHandler) isVMRestarting(kvvm *virtv1.VirtualMachine) bool { + if kvvm != nil && + len(kvvm.Status.StateChangeRequests) == 2 && + kvvm.Status.StateChangeRequests[0].Action == virtv1.StopRequest && + kvvm.Status.StateChangeRequests[1].Action == virtv1.StartRequest { + return true + } + + return false +} + func (h *SyncPowerStateHandler) handleAlwaysOnPolicy( ctx context.Context, s state.VirtualMachineState, @@ -218,6 +232,10 @@ func (h *SyncPowerStateHandler) handleAlwaysOnPolicy( shutdownInfo powerstate.ShutdownInfo, ) (VMAction, error) { if kvvmi == nil { + if h.isVMRestarting(kvvm) { + return Nothing, nil + } + if isConfigurationApplied { h.recordStartEventf(ctx, s.VirtualMachine().Current(), "Start initiated "+ "by controller for AlwaysOn policy")