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
2 changes: 1 addition & 1 deletion build/components/versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ firmware:
libvirt: v10.9.0
edk2: stable202411
core:
3p-kubevirt: v1.3.1-v12n.17
3p-kubevirt: v1.3.1-v12n.18
3p-containerized-data-importer: v1.60.3-v12n.12
distribution: 2.8.3
package:
Expand Down
4 changes: 3 additions & 1 deletion images/virtualization-artifact/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ replace (
k8s.io/client-go => k8s.io/client-go v0.33.3
k8s.io/component-base => k8s.io/component-base v0.33.3
k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911
kubevirt.io/api => github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.3.1-v12n.17
)

// CVE Replaces
Expand All @@ -164,3 +163,6 @@ replace (
golang.org/x/net => golang.org/x/net v0.40.0 // CVE-2025-22870, CVE-2025-22872
golang.org/x/oauth2 => golang.org/x/oauth2 v0.27.0 // CVE-2025-22868
)

// Kubevirt API replaces
replace kubevirt.io/api => github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.3.1-v12n.18
4 changes: 2 additions & 2 deletions images/virtualization-artifact/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.3.1-v12n.17 h1:IQPK5oGRSONOKPH8TIuDq7vCjbFTj0NEWQzo6ZBD7uY=
github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.3.1-v12n.17/go.mod h1:tCn7VAZktEvymk490iPSMPCmKM9UjbbfH2OsFR/IOLU=
github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.3.1-v12n.18 h1:9pstD3PiPmby/Chh24ickwUNbAcqbceOPp253/jSr8k=
github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.3.1-v12n.18/go.mod h1:tCn7VAZktEvymk490iPSMPCmKM9UjbbfH2OsFR/IOLU=
github.com/deckhouse/deckhouse/pkg/log v0.0.0-20250226105106-176cd3afcdd5 h1:PsN1E0oxC/+4zdA977txrqUCuObFL3HAuu5Xnud8m8c=
github.com/deckhouse/deckhouse/pkg/log v0.0.0-20250226105106-176cd3afcdd5/go.mod h1:Mk5HRzkc5pIcDIZ2JJ6DPuuqnwhXVkb3you8M8Mg+4w=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ func (h *MigratingHandler) syncMigrating(ctx context.Context, s state.VirtualMac
cb.Status(metav1.ConditionTrue).Reason(vmcondition.ReasonMigratingInProgress)

case vmopcondition.ReasonOperationFailed.String():
cb.Reason(vmcondition.ReasonLastMigrationFinishedWithError).Message("")
cb.Reason(vmcondition.ReasonLastMigrationFinishedWithError).Message(completed.Message)

case vmopcondition.ReasonNotApplicableForVMPhase.String():
cb.Reason(vmcondition.ReasonLastMigrationFinishedWithError).Message("Migration is not applicable for the current virtual machine phase")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,11 @@ func (h LifecycleHandler) syncOperationComplete(ctx context.Context, vmop *v1alp
if mig.Status.MigrationState != nil && mig.Status.MigrationState.FailureReason != "" {
msg += ": " + mig.Status.MigrationState.FailureReason
}
msgByFailedReason := getMessageByMigrationFailedReason(mig)
if msgByFailedReason != "" {
msg += ": " + msgByFailedReason
}

completedCond.
Status(metav1.ConditionFalse).
Reason(vmopcondition.ReasonOperationFailed).
Expand All @@ -292,10 +297,15 @@ func (h LifecycleHandler) syncOperationComplete(ctx context.Context, vmop *v1alp
vmop.Status.Phase = v1alpha2.VMOPPhasePending
}

msg, err := h.getConditionCompletedMessageByReason(ctx, reason, mig)
if err != nil {
return err
}

completedCond.
Status(metav1.ConditionFalse).
Reason(reason).
Message("Wait until operation is completed")
Message(msg)
conditions.SetCondition(completedCond, &vmop.Status.Conditions)

return nil
Expand Down Expand Up @@ -435,9 +445,11 @@ func (h LifecycleHandler) execute(ctx context.Context, vmop *v1alpha2.VirtualMac

// The Operation is successfully executed.
// Turn the phase to InProgress and set the send signal condition to true.
msg := fmt.Sprintf("Sent signal %q to VM without errors.", vmop.Spec.Type)
log.Debug(msg)
h.recorder.Event(vmop, corev1.EventTypeNormal, v1alpha2.ReasonVMOPInProgress, msg)
{
msg := fmt.Sprintf("Sent signal %q to VM without errors.", vmop.Spec.Type)
log.Debug(msg)
h.recorder.Event(vmop, corev1.EventTypeNormal, v1alpha2.ReasonVMOPInProgress, msg)
}

mig, err := h.migration.GetMigration(ctx, vmop)
if mig == nil || err != nil {
Expand All @@ -450,11 +462,16 @@ func (h LifecycleHandler) execute(ctx context.Context, vmop *v1alpha2.VirtualMac
vmop.Status.Phase = v1alpha2.VMOPPhasePending
}

msg, err := h.getConditionCompletedMessageByReason(ctx, reason, mig)
if err != nil {
return err
}

conditions.SetCondition(
conditions.NewConditionBuilder(vmopcondition.TypeCompleted).
Generation(vmop.GetGeneration()).
Reason(reason).
Message("Wait for operation to complete").
Message(msg).
Status(metav1.ConditionFalse),
&vmop.Status.Conditions)
conditions.SetCondition(
Expand Down Expand Up @@ -498,3 +515,74 @@ var mapMigrationPhaseToReason = map[virtv1.VirtualMachineInstanceMigrationPhase]
virtv1.MigrationSucceeded: vmopcondition.ReasonOperationCompleted,
virtv1.MigrationFailed: vmopcondition.ReasonOperationFailed,
}

func getMessageByMigrationFailedReason(mig *virtv1.VirtualMachineInstanceMigration) string {
cond, found := conditions.GetKVVMIMCondition(virtv1.VirtualMachineInstanceMigrationFailed, mig.Status.Conditions)

if cond.Status == corev1.ConditionTrue && found {
switch cond.Reason {
case virtv1.VirtualMachineInstanceMigrationFailedReasonVMIDoesNotExist, virtv1.VirtualMachineInstanceMigrationFailedReasonVMIIsShutdown:
return "VirtualMachine is stopped"
default:
return cond.Message
}
}

return ""
}

func (h LifecycleHandler) getTargetPod(ctx context.Context, mig *virtv1.VirtualMachineInstanceMigration) (*corev1.Pod, error) {
selector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{
MatchLabels: map[string]string{
virtv1.AppLabel: "virt-launcher",
virtv1.MigrationJobLabel: string(mig.UID),
},
})
if err != nil {
return nil, err
}

pods := &corev1.PodList{}
err = h.client.List(ctx, pods, client.InNamespace(mig.Namespace), client.MatchingLabelsSelector{Selector: selector})
if err != nil {
return nil, err
}

if len(pods.Items) > 0 {
return &pods.Items[0], nil
}

return nil, nil
}

func isPodPendingUnschedulable(pod *corev1.Pod) bool {
if pod == nil {
return false
}
if pod.Status.Phase != corev1.PodPending || pod.DeletionTimestamp != nil {
return false
}

for _, condition := range pod.Status.Conditions {
if condition.Type == corev1.PodScheduled &&
condition.Status == corev1.ConditionFalse &&
condition.Reason == corev1.PodReasonUnschedulable {
return true
}
}
return false
}

func (h LifecycleHandler) getConditionCompletedMessageByReason(ctx context.Context, reason vmopcondition.ReasonCompleted, mig *virtv1.VirtualMachineInstanceMigration) (string, error) {
msg := "Wait until operation is completed"
if reason == vmopcondition.ReasonMigrationPending || reason == vmopcondition.ReasonMigrationPrepareTarget {
pod, err := h.getTargetPod(ctx, mig)
if err != nil {
return "", err
}
if isPodPendingUnschedulable(pod) {
msg += fmt.Sprintf(" (target pod is unschedulable: %s/%s)", pod.Namespace, pod.Name)
}
}
return msg + ".", nil
}
Loading