Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,11 @@ In case multi-cluster support is enabled (default) and you have access to multip
- `action` (`string`) **(required)** - The lifecycle action to perform: 'start' (changes runStrategy to Always), 'stop' (changes runStrategy to Halted), or 'restart' (stops then starts the VM)
- `name` (`string`) **(required)** - The name of the virtual machine
- `namespace` (`string`) **(required)** - The namespace of the virtual machine
- `run_policy` (`string`) - The run policy to use when starting or restarting a VM (applies to 'start' and 'restart' actions; ignored for 'stop'). Options:
- 'HighAvailability': VM runs continuously (sets runStrategy to Always)
- 'RestartOnFailure': VM restarts on failure (sets runStrategy to RerunOnFailure)
- 'Once': VM runs once and stops after completion (sets runStrategy to Once)
Defaults to 'HighAvailability' if not specified.

</details>

Expand Down
78 changes: 65 additions & 13 deletions pkg/kubevirt/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,29 @@ import (

// RunStrategy represents the run strategy for a VirtualMachine
type RunStrategy string
type RunPolicy string

const (
RunStrategyAlways RunStrategy = "Always"
RunStrategyHalted RunStrategy = "Halted"
RunStrategyAlways RunStrategy = "Always"
RunStrategyHalted RunStrategy = "Halted"
RunStrategyManual RunStrategy = "Manual"
RunStrategyRerunOnFailure RunStrategy = "RerunOnFailure"
RunStrategyOnce RunStrategy = "Once"
RunStrategyWaitAsReceiver RunStrategy = "WaitAsReceiver"

RunPolicyHighAvailability RunPolicy = "HighAvailability"
RunPolicyRestartOnFailure RunPolicy = "RestartOnFailure"
RunPolicyOnce RunPolicy = "Once"
)

func IsValidRunPolicy(runPolicy RunPolicy) bool {
switch runPolicy {
case RunPolicyHighAvailability, RunPolicyRestartOnFailure, RunPolicyOnce:
return true
}
return false
}

// GetVirtualMachine retrieves a VirtualMachine by namespace and name
func GetVirtualMachine(ctx context.Context, client dynamic.Interface, namespace, name string) (*unstructured.Unstructured, error) {
return client.Resource(VirtualMachineGVR).Namespace(namespace).Get(ctx, name, metav1.GetOptions{})
Expand Down Expand Up @@ -45,9 +62,22 @@ func UpdateVirtualMachine(ctx context.Context, client dynamic.Interface, vm *uns
Update(ctx, vm, metav1.UpdateOptions{})
}

// StartVM starts a VirtualMachine by updating its runStrategy to Always
// Returns the updated VM and true if the VM was started, false if it was already running
func StartVM(ctx context.Context, dynamicClient dynamic.Interface, namespace, name string) (*unstructured.Unstructured, bool, error) {
// StartVM starts a VirtualMachine by updating its runStrategy based on the runPolicy
// runPolicy can be one of: HighAvailability, RestartOnFailure, Once
// - HighAvailability: The VM will be started if it is not already running, if it is already running the runStrategy
// will be set to Always.
// - RestartOnFailure: The VM will be started if it is not already running and will be restarted if it fails, if it
// is already running the runStrategy will be set to RerunOnFailure.
// - Once: The VM will be started if it is not already running and will be stopped after it completes, if it is already
// running the runStrategy will be set to Once.
// Returns the updated VM and true if the VM was started, or if it was already running and the runStrategy changed.
// Returns false if it was already running and the runStrategy did not change.
func StartVM(ctx context.Context, dynamicClient dynamic.Interface, namespace, name string, runPolicy RunPolicy) (*unstructured.Unstructured, bool, error) {
// Validate run policy
if !IsValidRunPolicy(runPolicy) {
return nil, false, fmt.Errorf("invalid run policy '%s': must be one of 'HighAvailability', 'RestartOnFailure', 'Once'", runPolicy)
}

// Get the current VirtualMachine
vm, err := GetVirtualMachine(ctx, dynamicClient, namespace, name)
if err != nil {
Expand All @@ -60,12 +90,12 @@ func StartVM(ctx context.Context, dynamicClient dynamic.Interface, namespace, na
}

// Check if already running
if found && currentStrategy == RunStrategyAlways {
if found && currentStrategy == getRunStrategyFromRunPolicy(runPolicy) {
return vm, false, nil
}

// Update runStrategy to Always
if err := SetVMRunStrategy(vm, RunStrategyAlways); err != nil {
// Update runStrategy to the appropriate value
if err := SetVMRunStrategy(vm, getRunStrategyFromRunPolicy(runPolicy)); err != nil {
return nil, false, fmt.Errorf("failed to set runStrategy: %w", err)
}

Expand All @@ -78,6 +108,23 @@ func StartVM(ctx context.Context, dynamicClient dynamic.Interface, namespace, na
return updatedVM, true, nil
}

// getRunStrategyFromRunPolicy returns the RunStrategy for a given RunPolicy
// - HighAvailability: Always
// - RestartOnFailure: RerunOnFailure
// - Once: Once
// Returns the RunStrategy
func getRunStrategyFromRunPolicy(runPolicy RunPolicy) RunStrategy {
switch runPolicy {
case RunPolicyHighAvailability:
return RunStrategyAlways
case RunPolicyRestartOnFailure:
return RunStrategyRerunOnFailure
case RunPolicyOnce:
return RunStrategyOnce
}
return RunStrategyAlways
Comment thread
awels marked this conversation as resolved.
}

// StopVM stops a VirtualMachine by updating its runStrategy to Halted
// Returns the updated VM and true if the VM was stopped, false if it was already stopped
func StopVM(ctx context.Context, dynamicClient dynamic.Interface, namespace, name string) (*unstructured.Unstructured, bool, error) {
Expand Down Expand Up @@ -144,8 +191,13 @@ func CloneVM(ctx context.Context, dynamicClient dynamic.Interface, namespace, so
return result, nil
}

// RestartVM restarts a VirtualMachine by temporarily setting runStrategy to Halted then back to Always
func RestartVM(ctx context.Context, dynamicClient dynamic.Interface, namespace, name string) (*unstructured.Unstructured, error) {
// RestartVM restarts a VirtualMachine by temporarily setting runStrategy to Halted then back to the specified run policy
func RestartVM(ctx context.Context, dynamicClient dynamic.Interface, namespace, name string, runPolicy RunPolicy) (*unstructured.Unstructured, error) {
// Validate run policy
if !IsValidRunPolicy(runPolicy) {
return nil, fmt.Errorf("invalid run policy '%s': must be one of 'HighAvailability', 'RestartOnFailure', 'Once'", runPolicy)
}

// Get the current VirtualMachine
vm, err := GetVirtualMachine(ctx, dynamicClient, namespace, name)
if err != nil {
Expand All @@ -162,9 +214,9 @@ func RestartVM(ctx context.Context, dynamicClient dynamic.Interface, namespace,
return nil, fmt.Errorf("failed to stop VirtualMachine: %w", err)
}

// Start the VM again
if err := SetVMRunStrategy(vm, RunStrategyAlways); err != nil {
return nil, fmt.Errorf("failed to set runStrategy to Always: %w", err)
// Start the VM again with the specified run policy
if err := SetVMRunStrategy(vm, getRunStrategyFromRunPolicy(runPolicy)); err != nil {
return nil, fmt.Errorf("failed to set runStrategy: %w", err)
}

updatedVM, err := UpdateVirtualMachine(ctx, dynamicClient, vm)
Expand Down
Loading