Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix power state handling from OpenStack #640

Merged
merged 2 commits into from
Nov 7, 2023
Merged
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
13 changes: 11 additions & 2 deletions pkg/apis/forklift/v1beta1/plan/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package plan

import (
"fmt"
"path"

"github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref"
libcnd "github.com/konveyor/forklift-controller/pkg/lib/condition"
core "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"path"
)

// Plan hook.
Expand Down Expand Up @@ -57,7 +58,7 @@ type VMStatus struct {
// Warm migration status
Warm *Warm `json:"warm,omitempty"`
// Source VM power state before migration.
RestorePowerState string `json:"restorePowerState,omitempty"`
RestorePowerState VMPowerState `json:"restorePowerState,omitempty"`

// Conditions.
libcnd.Conditions `json:",inline"`
Expand All @@ -72,6 +73,14 @@ type Warm struct {
Precopies []Precopy `json:"precopies,omitempty"`
}

type VMPowerState string

const (
VMPowerStateOn VMPowerState = "On"
VMPowerStateOff VMPowerState = "Off"
VMPowerStateUnknown VMPowerState = "Unknown"
)

// Precopy durations
type Precopy struct {
Start *meta.Time `json:"start,omitempty"`
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/plan/adapter/base/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type Client interface {
// Power off the source VM.
PowerOff(vmRef ref.Ref) error
// Return the source VM's power state.
PowerState(vmRef ref.Ref) (string, error)
PowerState(vmRef ref.Ref) (planapi.VMPowerState, error)
// Return whether the source VM is powered off.
PoweredOff(vmRef ref.Ref) (bool, error)
// Create a snapshot of the source VM.
Expand Down
8 changes: 4 additions & 4 deletions pkg/controller/plan/adapter/ocp/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,19 @@ func (r *Client) PowerOn(vmRef ref.Ref) error {
}

// PowerState implements base.Client
func (r *Client) PowerState(vmRef ref.Ref) (string, error) {
func (r *Client) PowerState(vmRef ref.Ref) (planapi.VMPowerState, error) {
vm := cnv.VirtualMachine{}
err := r.sourceClient.Get(context.TODO(), k8sclient.ObjectKey{Namespace: vmRef.Namespace, Name: vmRef.Name}, &vm)
if err != nil {
err = liberr.Wrap(err)
return "", err
return planapi.VMPowerStateUnknown, err
}

if vm.Spec.Running != nil && *vm.Spec.Running {
return "On", nil
return planapi.VMPowerStateOn, nil
}

return "Off", nil
return planapi.VMPowerStateOff, nil
}

// PoweredOff implements base.Client
Expand Down
16 changes: 13 additions & 3 deletions pkg/controller/plan/adapter/openstack/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,20 @@ func (r *Client) PowerOff(vmRef ref.Ref) (err error) {
}

// Return the source VM's power state.
func (r *Client) PowerState(vmRef ref.Ref) (state string, err error) {
state, err = r.VMStatus(vmRef.ID)
func (r *Client) PowerState(vmRef ref.Ref) (state planapi.VMPowerState, err error) {
status, err := r.VMStatus(vmRef.ID)
if err != nil {
err = liberr.Wrap(err)
state = planapi.VMPowerStateUnknown
return
}
switch status {
case libclient.VmStatusActive:
state = planapi.VMPowerStateOn
case libclient.VmStatusShutoff:
state = planapi.VMPowerStateOff
default:
state = planapi.VMPowerStateUnknown
}
return
}
Expand All @@ -91,7 +101,7 @@ func (r *Client) PoweredOff(vmRef ref.Ref) (off bool, err error) {
err = liberr.Wrap(err)
return
}
off = state == libclient.VmStatusShutoff
off = state == planapi.VMPowerStateOff
return
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/plan/adapter/ova/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, data
}

// Get the power state of the VM.
func (r *Client) PowerState(vmRef ref.Ref) (state string, err error) {
func (r *Client) PowerState(vmRef ref.Ref) (state planapi.VMPowerState, err error) {
return
}

Expand Down
17 changes: 5 additions & 12 deletions pkg/controller/plan/adapter/ovirt/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,6 @@ const (
snapshotDesc = "Forklift Operator warm migration precopy"
)

// VM power states
const (
powerOn = "On"
powerOff = "Off"
powerUnknown = "Unknown"
)

// Snapshot event codes
const (
SNAPSHOT_FINISHED_SUCCESS int64 = 68
Expand Down Expand Up @@ -148,19 +141,19 @@ func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, data
}

// Get the power state of the VM.
func (r *Client) PowerState(vmRef ref.Ref) (state string, err error) {
func (r *Client) PowerState(vmRef ref.Ref) (state planapi.VMPowerState, err error) {
vm, _, err := r.getVM(vmRef)
if err != nil {
return
}
status, _ := vm.Status()
switch status {
case ovirtsdk.VMSTATUS_DOWN:
state = powerOff
state = planapi.VMPowerStateOff
case ovirtsdk.VMSTATUS_UP, ovirtsdk.VMSTATUS_POWERING_UP:
state = powerOn
state = planapi.VMPowerStateOn
default:
state = powerUnknown
state = planapi.VMPowerStateUnknown
}
return
}
Expand Down Expand Up @@ -203,7 +196,7 @@ func (r *Client) PoweredOff(vmRef ref.Ref) (poweredOff bool, err error) {
if err != nil {
return
}
poweredOff = powerState == powerOff
poweredOff = powerState == planapi.VMPowerStateOff
return
}

Expand Down
15 changes: 4 additions & 11 deletions pkg/controller/plan/adapter/vsphere/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@ const (
snapshotDesc = "Forklift Operator warm migration precopy"
)

// VM power states
const (
powerOn = "On"
powerOff = "Off"
powerUnknown = "Unknown"
)

// vSphere VM Client
type Client struct {
*plancontext.Context
Expand Down Expand Up @@ -138,7 +131,7 @@ func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, data
}

// Get the power state of the VM.
func (r *Client) PowerState(vmRef ref.Ref) (state string, err error) {
func (r *Client) PowerState(vmRef ref.Ref) (state planapi.VMPowerState, err error) {
vm, err := r.getVM(vmRef)
if err != nil {
return
Expand All @@ -150,11 +143,11 @@ func (r *Client) PowerState(vmRef ref.Ref) (state string, err error) {
}
switch powerState {
case types.VirtualMachinePowerStatePoweredOn:
state = powerOn
state = planapi.VMPowerStateOn
case types.VirtualMachinePowerStatePoweredOff:
state = powerOff
state = planapi.VMPowerStateOff
default:
state = powerUnknown
state = planapi.VMPowerStateUnknown
}
return
}
Expand Down
15 changes: 2 additions & 13 deletions pkg/controller/plan/kubevirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,18 +427,6 @@ func (r *KubeVirt) DeleteVM(vm *plan.VMStatus) (err error) {
return
}

// Set the Running state on a Kubevirt VirtualMachine.
func (r *KubeVirt) SetRunning(vmCr *VirtualMachine, running bool) (err error) {
vmCopy := vmCr.VirtualMachine.DeepCopy()
vmCr.VirtualMachine.Spec.Running = &running
patch := client.MergeFrom(vmCopy)
err = r.Destination.Client.Patch(context.TODO(), vmCr.VirtualMachine, patch)
if err != nil {
err = liberr.Wrap(err)
}
return
}

func (r *KubeVirt) DataVolumes(vm *plan.VMStatus) (dataVolumes []cdi.DataVolume, err error) {
secret, err := r.ensureSecret(vm.Ref, r.secretDataSetterForCDI(vm.Ref))
if err != nil {
Expand Down Expand Up @@ -1006,7 +994,8 @@ func (r *KubeVirt) virtualMachine(vm *plan.VMStatus) (object *cnv.VirtualMachine
object.ObjectMeta.Annotations = annotations
}

running := false
// Power on the destination VM if the source VM was originally powered on.
running := vm.RestorePowerState == plan.VMPowerStateOn
object.Spec.Running = &running

err = r.Builder.VirtualMachine(vm.Ref, &object.Spec, pvcs)
Expand Down
50 changes: 2 additions & 48 deletions pkg/controller/plan/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,6 @@ const (
Unknown = "Unknown"
)

// Power states.
const (
On = "On"
)

const (
TransferCompleted = "Transfer completed."
)
Expand Down Expand Up @@ -401,7 +396,7 @@ func (r *Migration) Cancel() (err error) {
vm.String())
err = nil
}
if vm.RestorePowerState == On {
if vm.RestorePowerState == plan.VMPowerStateOn {
err = r.provider.PowerOn(vm.Ref)
if err != nil {
r.Log.Error(err,
Expand Down Expand Up @@ -905,7 +900,7 @@ func (r *Migration) execute(vm *plan.VMStatus) (err error) {
vm.AddError(fmt.Sprintf("Step '%s' not found", r.step(vm)))
break
}
var state string
var state plan.VMPowerState
state, err = r.provider.PowerState(vm.Ref)
if err != nil {
if !errors.As(err, &web.ProviderNotReadyError{}) {
Expand Down Expand Up @@ -1052,15 +1047,6 @@ func (r *Migration) execute(vm *plan.VMStatus) (err error) {
Durable: true,
})

// Power on the destination VM if the source VM was originally powered on.
err = r.setRunning(vm, vm.RestorePowerState == On)
if err != nil {
r.Log.Error(err,
"Could not power on destination VM.",
"vm",
vm.String())
err = nil
}
} else if vm.Error != nil {
vm.Phase = Completed
vm.SetCondition(
Expand Down Expand Up @@ -1317,38 +1303,6 @@ func (r *Migration) ensureGuestConversionPod(vm *plan.VMStatus) (err error) {
return
}

// Set the running state of the kubevirt VM.
func (r *Migration) setRunning(vm *plan.VMStatus, running bool) (err error) {
if r.vmMap == nil {
r.vmMap, err = r.kubevirt.VirtualMachineMap()
if err != nil {
return
}
}
var vmCr VirtualMachine
found := false
if vmCr, found = r.vmMap[vm.ID]; !found {
// Recreate the map and check again, the map may be stale
r.vmMap, err = r.kubevirt.VirtualMachineMap()
if err != nil {
return
}

if vmCr, found = r.vmMap[vm.ID]; !found {
msg := "VirtualMachine CR not found."
vm.AddError(msg)
return
}
}

if vmCr.Spec.Running != nil && *vmCr.Spec.Running == running {
return
}

err = r.kubevirt.SetRunning(&vmCr, running)
return
}

// Update the progress of the appropriate disk copy step. (DiskTransfer, Cutover)
func (r *Migration) updateCopyProgress(vm *plan.VMStatus, step *plan.Step) (err error) {
var pendingReason string
Expand Down