From b326836308b53f62270181de020b9e72bece002a Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Thu, 22 Jan 2026 19:38:35 +0300 Subject: [PATCH 1/2] wip Signed-off-by: Daniil Loktev --- .../pkg/controller/kvbuilder/kvvm_utils.go | 19 +++++++++++++++++++ .../pkg/controller/vm/internal/sync_kvvm.go | 9 ++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go index 284c21eaa1..730db78006 100644 --- a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go +++ b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go @@ -20,6 +20,7 @@ import ( "crypto/md5" "encoding/hex" "fmt" + "sort" "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -97,6 +98,7 @@ func ApplyVirtualMachineSpec( class *v1alpha2.VirtualMachineClass, ipAddress string, networkSpec network.InterfaceSpecList, + existingTargets map[string]string, ) error { if err := kvvm.SetRunPolicy(vm.Spec.RunPolicy); err != nil { return err @@ -234,6 +236,23 @@ func ApplyVirtualMachineSpec( return err } + sort.SliceStable(hotpluggedDevices, func(i, j int) bool { + nameI, _ := GetOriginalDiskName(hotpluggedDevices[i].VolumeName) + nameJ, _ := GetOriginalDiskName(hotpluggedDevices[j].VolumeName) + ti := existingTargets[nameI] + tj := existingTargets[nameJ] + if ti == "" && tj == "" { + return false + } + if ti == "" { + return false + } + if tj == "" { + return true + } + return ti < tj + }) + for _, device := range hotpluggedDevices { name, kind := GetOriginalDiskName(device.VolumeName) diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go b/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go index 9c9a840920..8a23bd7139 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go @@ -437,8 +437,15 @@ func MakeKVVMFromVMSpec(ctx context.Context, s state.VirtualMachineState) (*virt return nil, fmt.Errorf("get vmbdas: %w", err) } + existingTargets := make(map[string]string) + for _, bd := range current.Status.BlockDeviceRefs { + if bd.Target != "" { + existingTargets[bd.Name] = bd.Target + } + } + // Create kubevirt VirtualMachine resource from d8 VirtualMachine spec. - err = kvbuilder.ApplyVirtualMachineSpec(kvvmBuilder, current, bdState.VDByName, bdState.VIByName, bdState.CVIByName, vmbdas, class, ipAddress, networkSpec) + err = kvbuilder.ApplyVirtualMachineSpec(kvvmBuilder, current, bdState.VDByName, bdState.VIByName, bdState.CVIByName, vmbdas, class, ipAddress, networkSpec, existingTargets) if err != nil { return nil, err } From 9d09d60d87fee6c4fd7d6c7b71d288bd3c5601fa Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 23 Jan 2026 16:34:38 +0300 Subject: [PATCH 2/2] wip Signed-off-by: Daniil Loktev --- .../pkg/controller/kvbuilder/kvvm_utils.go | 21 +++++++++++-------- .../service/restorer/restorers/vm_restorer.go | 9 ++++++++ .../pkg/controller/vm/internal/sync_kvvm.go | 9 +------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go index 730db78006..1763656846 100644 --- a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go +++ b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go @@ -98,7 +98,6 @@ func ApplyVirtualMachineSpec( class *v1alpha2.VirtualMachineClass, ipAddress string, networkSpec network.InterfaceSpecList, - existingTargets map[string]string, ) error { if err := kvvm.SetRunPolicy(vm.Spec.RunPolicy); err != nil { return err @@ -236,21 +235,25 @@ func ApplyVirtualMachineSpec( return err } - sort.SliceStable(hotpluggedDevices, func(i, j int) bool { + diskOrder := make(map[string]int) + for i, bd := range vm.Status.BlockDeviceRefs { + diskOrder[bd.Name] = i + } + sort.Slice(hotpluggedDevices, func(i, j int) bool { nameI, _ := GetOriginalDiskName(hotpluggedDevices[i].VolumeName) nameJ, _ := GetOriginalDiskName(hotpluggedDevices[j].VolumeName) - ti := existingTargets[nameI] - tj := existingTargets[nameJ] - if ti == "" && tj == "" { - return false + orderI, okI := diskOrder[nameI] + orderJ, okJ := diskOrder[nameJ] + if !okI && !okJ { + return hotpluggedDevices[i].VolumeName < hotpluggedDevices[j].VolumeName } - if ti == "" { + if !okI { return false } - if tj == "" { + if !okJ { return true } - return ti < tj + return orderI < orderJ }) for _, device := range hotpluggedDevices { diff --git a/images/virtualization-artifact/pkg/controller/service/restorer/restorers/vm_restorer.go b/images/virtualization-artifact/pkg/controller/service/restorer/restorers/vm_restorer.go index 937fec7c08..0e92ae6f55 100644 --- a/images/virtualization-artifact/pkg/controller/service/restorer/restorers/vm_restorer.go +++ b/images/virtualization-artifact/pkg/controller/service/restorer/restorers/vm_restorer.go @@ -213,6 +213,15 @@ func (v *VirtualMachineHandler) ProcessRestore(ctx context.Context) error { return fmt.Errorf("failed to update the `VirtualMachine`: %w", updErr) } + vm.Status.BlockDeviceRefs = v.vm.Status.BlockDeviceRefs + updErr = v.client.Status().Update(ctx, vm) + if updErr != nil { + if apierrors.IsConflict(updErr) { + return fmt.Errorf("waiting for the `VirtualMachine` status %w", common.ErrUpdating) + } + return fmt.Errorf("failed to update the `VirtualMachine` status: %w", updErr) + } + // Always clean up VMBDAs first, regardless of VM state err = v.deleteCurrentVirtualMachineBlockDeviceAttachments(ctx) if err != nil { diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go b/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go index 8a23bd7139..9c9a840920 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go @@ -437,15 +437,8 @@ func MakeKVVMFromVMSpec(ctx context.Context, s state.VirtualMachineState) (*virt return nil, fmt.Errorf("get vmbdas: %w", err) } - existingTargets := make(map[string]string) - for _, bd := range current.Status.BlockDeviceRefs { - if bd.Target != "" { - existingTargets[bd.Name] = bd.Target - } - } - // Create kubevirt VirtualMachine resource from d8 VirtualMachine spec. - err = kvbuilder.ApplyVirtualMachineSpec(kvvmBuilder, current, bdState.VDByName, bdState.VIByName, bdState.CVIByName, vmbdas, class, ipAddress, networkSpec, existingTargets) + err = kvbuilder.ApplyVirtualMachineSpec(kvvmBuilder, current, bdState.VDByName, bdState.VIByName, bdState.CVIByName, vmbdas, class, ipAddress, networkSpec) if err != nil { return nil, err }