diff --git a/api/core/v1alpha2/vmcondition/condition.go b/api/core/v1alpha2/vmcondition/condition.go index e99b6416a..025aa982a 100644 --- a/api/core/v1alpha2/vmcondition/condition.go +++ b/api/core/v1alpha2/vmcondition/condition.go @@ -23,17 +23,23 @@ func (t Type) String() string { } const ( - TypeIPAddressReady Type = "VirtualMachineIPAddressReady" - TypeClassReady Type = "VirtualMachineClassReady" - TypeBlockDevicesReady Type = "BlockDevicesReady" - TypeRunning Type = "Running" - TypeMigrating Type = "Migrating" - TypeMigratable Type = "Migratable" - TypePodStarted Type = "PodStarted" - TypeProvisioningReady Type = "ProvisioningReady" - TypeAgentReady Type = "AgentReady" - TypeAgentVersionNotSupported Type = "AgentVersionNotSupported" - TypeConfigurationApplied Type = "ConfigurationApplied" + TypeIPAddressReady Type = "VirtualMachineIPAddressReady" + TypeClassReady Type = "VirtualMachineClassReady" + TypeBlockDevicesReady Type = "BlockDevicesReady" + TypeRunning Type = "Running" + TypeMigrating Type = "Migrating" + TypeMigratable Type = "Migratable" + TypePodStarted Type = "PodStarted" + TypeProvisioningReady Type = "ProvisioningReady" + TypeAgentReady Type = "AgentReady" + TypeAgentVersionNotSupported Type = "AgentVersionNotSupported" + + // TypeConfigurationApplied indicates status to the synchronization of the KVVM configuration. + TypeConfigurationApplied Type = "ConfigurationApplied" + + // TypePowerConfigurationApplied indicates status to the synchronization of the power state. + TypePowerConfigurationApplied Type = "PowerConfigurationApplied" + TypeAwaitingRestartToApplyConfiguration Type = "AwaitingRestartToApplyConfiguration" TypeFilesystemReady Type = "FilesystemReady" TypeSizingPolicyMatched Type = "SizingPolicyMatched" diff --git a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm.go b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm.go index 3795ecf07..60a806cb5 100644 --- a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm.go +++ b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm.go @@ -126,25 +126,8 @@ func (b *KVVM) SetCPUModel(class *virtv2.VirtualMachineClass) error { return nil } -func (b *KVVM) SetRunPolicy(runPolicy virtv2.RunPolicy) error { - switch runPolicy { - case virtv2.AlwaysOnPolicy: - b.Resource.Spec.RunStrategy = pointer.GetPointer(virtv1.RunStrategyAlways) - case virtv2.AlwaysOffPolicy: - b.Resource.Spec.RunStrategy = pointer.GetPointer(virtv1.RunStrategyHalted) - case virtv2.ManualPolicy: - if !b.ResourceExists { - // initialize only - b.Resource.Spec.RunStrategy = pointer.GetPointer(virtv1.RunStrategyManual) - } - case virtv2.AlwaysOnUnlessStoppedManually: - if !b.ResourceExists { - // initialize only - b.Resource.Spec.RunStrategy = pointer.GetPointer(virtv1.RunStrategyAlways) - } - default: - return fmt.Errorf("unexpected runPolicy %s. %w", runPolicy, common.ErrUnknownValue) - } +func (b *KVVM) SetRunPolicy() error { + b.Resource.Spec.RunStrategy = pointer.GetPointer(virtv1.RunStrategyManual) return nil } diff --git a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go index 9b963dc8c..490e45ef4 100644 --- a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go +++ b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go @@ -71,7 +71,7 @@ func ApplyVirtualMachineSpec( class *virtv2.VirtualMachineClass, ipAddress string, ) error { - if err := kvvm.SetRunPolicy(vm.Spec.RunPolicy); err != nil { + if err := kvvm.SetRunPolicy(); err != nil { return err } if err := kvvm.SetOsType(vm.Spec.OsType); err != nil { 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 99d9fbacd..22ed9e8c6 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 @@ -28,7 +28,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" - kvvmutil "github.com/deckhouse/virtualization-controller/pkg/common/kvvm" "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" "github.com/deckhouse/virtualization-controller/pkg/controller/powerstate" "github.com/deckhouse/virtualization-controller/pkg/controller/service" @@ -60,43 +59,48 @@ func (h *SyncPowerStateHandler) Handle(ctx context.Context, s state.VirtualMachi current := s.VirtualMachine().Current() changed := s.VirtualMachine().Changed() - cbConfApplied := conditions.NewConditionBuilder(vmcondition.TypeConfigurationApplied). + cbPowerConfApplied := conditions.NewConditionBuilder(vmcondition.TypePowerConfigurationApplied). Generation(current.GetGeneration()). Status(metav1.ConditionUnknown). Reason(conditions.ReasonUnknown) defer func() { - conditions.SetCondition(cbConfApplied, &changed.Status.Conditions) + conditions.SetCondition(cbPowerConfApplied, &changed.Status.Conditions) }() kvvm, err := s.KVVM(ctx) if err != nil { - cbConfApplied. + cbPowerConfApplied. Status(metav1.ConditionFalse). Reason(vmcondition.ReasonConfigurationNotApplied). Message(service.CapitalizeFirstLetter(err.Error()) + ".") return reconcile.Result{}, err } - err = h.syncPowerState(ctx, s, kvvm, &changed.Spec) + err = h.syncPowerState(ctx, s, kvvm, changed.Spec.RunPolicy) if err != nil { err = fmt.Errorf("failed to sync powerstate: %w", err) h.recorder.Event(current, corev1.EventTypeWarning, virtv2.ReasonErrVmNotSynced, err.Error()) - cbConfApplied. + cbPowerConfApplied. Status(metav1.ConditionFalse). Reason(vmcondition.ReasonConfigurationNotApplied). Message(service.CapitalizeFirstLetter(err.Error()) + ".") + } else { + cbPowerConfApplied. + Status(metav1.ConditionTrue). + Reason(vmcondition.ReasonConfigurationApplied). + Message("") } return reconcile.Result{}, err } // syncPowerState enforces runPolicy on the underlying KVVM. -func (h *SyncPowerStateHandler) syncPowerState(ctx context.Context, s state.VirtualMachineState, kvvm *virtv1.VirtualMachine, effectiveSpec *virtv2.VirtualMachineSpec) error { +func (h *SyncPowerStateHandler) syncPowerState(ctx context.Context, s state.VirtualMachineState, kvvm *virtv1.VirtualMachine, vmRunPolicy virtv2.RunPolicy) error { log := logger.FromContext(ctx) if kvvm == nil { - return nil + return fmt.Errorf("kvvm is nil") } kvvmi, err := s.KVVMI(ctx) @@ -104,7 +108,6 @@ func (h *SyncPowerStateHandler) syncPowerState(ctx context.Context, s state.Virt return fmt.Errorf("find the internal virtual machine instance: %w", err) } - vmRunPolicy := effectiveSpec.RunPolicy var shutdownInfo powerstate.ShutdownInfo s.Shared(func(s *state.Shared) { shutdownInfo = s.ShutdownInfo @@ -119,10 +122,8 @@ func (h *SyncPowerStateHandler) syncPowerState(ctx context.Context, s state.Virt return fmt.Errorf("force AlwaysOff: delete KVVMI: %w", err) } } - err = h.ensureRunStrategy(ctx, kvvm, virtv1.RunStrategyHalted) case virtv2.AlwaysOnPolicy: - strategy, _ := kvvm.RunStrategy() - if strategy == virtv1.RunStrategyAlways && kvvmi == nil { + if kvvmi == nil { if err = powerstate.StartVM(ctx, h.client, kvvm); err != nil { return fmt.Errorf("failed to start VM: %w", err) } @@ -145,13 +146,13 @@ func (h *SyncPowerStateHandler) syncPowerState(ctx context.Context, s state.Virt } } } - - err = h.ensureRunStrategy(ctx, kvvm, virtv1.RunStrategyManual) case virtv2.AlwaysOnUnlessStoppedManually: - strategy, _ := kvvm.RunStrategy() - if strategy == virtv1.RunStrategyAlways && kvvmi == nil { - if err = powerstate.StartVM(ctx, h.client, kvvm); err != nil { - return fmt.Errorf("failed to start VM: %w", err) + if kvvmi == nil { + cond, ok := conditions.GetCondition(vmcondition.TypePowerConfigurationApplied, s.VirtualMachine().Changed().Status.Conditions) + if !ok || cond.Status != metav1.ConditionTrue { + if err = powerstate.StartVM(ctx, h.client, kvvm); err != nil { + return fmt.Errorf("failed to start VM: %w", err) + } } } if kvvmi != nil && kvvmi.DeletionTimestamp == nil { @@ -183,8 +184,6 @@ func (h *SyncPowerStateHandler) syncPowerState(ctx context.Context, s state.Virt } } } - - err = h.ensureRunStrategy(ctx, kvvm, virtv1.RunStrategyManual) case virtv2.ManualPolicy: // Manual policy requires to handle only guest-reset event. // All types of shutdown are a final state. @@ -207,30 +206,6 @@ func (h *SyncPowerStateHandler) syncPowerState(ctx context.Context, s state.Virt } } } - - err = h.ensureRunStrategy(ctx, kvvm, virtv1.RunStrategyManual) - } - - if err != nil { - return fmt.Errorf("enforce runPolicy %s: %w", vmRunPolicy, err) - } - - return nil -} - -func (h *SyncPowerStateHandler) ensureRunStrategy(ctx context.Context, kvvm *virtv1.VirtualMachine, desiredRunStrategy virtv1.VirtualMachineRunStrategy) error { - if kvvm == nil { - return nil - } - kvvmRunStrategy := kvvmutil.GetRunStrategy(kvvm) - - if kvvmRunStrategy == desiredRunStrategy { - return nil - } - patch := kvvmutil.PatchRunStrategy(desiredRunStrategy) - err := h.client.Patch(ctx, kvvm, patch) - if err != nil { - return fmt.Errorf("patch KVVM with runStrategy %s: %w", desiredRunStrategy, err) } return nil