From 3a192d2abb8402224a4b6d8935a625f4302575da Mon Sep 17 00:00:00 2001 From: Ivan Mikheykin Date: Fri, 15 May 2026 15:55:16 +0300 Subject: [PATCH 1/3] fix(vm): cleanup cpu.features on KVVM after vmclass change The problem occurs when VM started with Discovery type vmclass and then vmclass is changed to a non-Discovery type. - cpu.features are kept and they are passed to a nodeSelector for VM Pod. User may encounter unexpected Pod scheduling problems after vmclass change. Signed-off-by: Ivan Mikheykin --- .../pkg/controller/vm/internal/sync_kvvm.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 688b0f556d..3dc89bee3e 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go @@ -410,13 +410,22 @@ func (h *SyncKvvmHandler) updateKVVM(ctx context.Context, s state.VirtualMachine log.Info("Update internal virtual machine done", "name", newKVVM.Name) log.Debug("Update internal virtual machine done", "name", newKVVM.Name, "kvvm", newKVVM) + // Add patches to remove fields with "omitempty" annotation. + jsonPatch := patch.JSONPatch{} if domainMemory != nil { - jsonPatch := patch.JSONPatch{} // Removing memory.maxGuest is not enough, replace memory.guest is needed to pass the vm-validator webhook. jsonPatch.Append( patch.WithRemove("/spec/template/spec/domain/memory/maxGuest"), patch.WithReplace("/spec/template/spec/domain/memory/guest", domainMemory.Guest.String()), ) + } + newCPU := newKVVM.Spec.Template.Spec.Domain.CPU + if newCPU != nil && len(newCPU.Features) == 0 { + jsonPatch.Append( + patch.WithRemove("/spec/template/spec/domain/cpu/features"), + ) + } + if jsonPatch.Len() > 0 { patchBytes, err := jsonPatch.Bytes() if err != nil { return fmt.Errorf("prepare json patch for internal virtual machine: %w", err) From b31e5d7db7a9921265cf01811175ac3f65abd8f6 Mon Sep 17 00:00:00 2001 From: Ivan Mikheykin Date: Mon, 18 May 2026 19:29:28 +0300 Subject: [PATCH 2/3] ++ try with features=nil Signed-off-by: Ivan Mikheykin --- .../pkg/controller/kvbuilder/kvvm.go | 2 ++ .../pkg/controller/vm/internal/sync_kvvm.go | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm.go b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm.go index cb33c9891b..68cb1793a6 100644 --- a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm.go +++ b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm.go @@ -152,6 +152,8 @@ func (b *KVVM) SetCPUModel(class *v1alpha2.VirtualMachineClass) error { b.Resource.Spec.Template.Spec.Domain.CPU = &virtv1.CPU{} } cpu := b.Resource.Spec.Template.Spec.Domain.CPU + // Reset features to handle vmclass changes: only discovery type sets features. + cpu.Features = nil switch class.Spec.CPU.Type { case v1alpha2.CPUTypeHost: 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 3dc89bee3e..2a7068f39d 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go @@ -419,12 +419,12 @@ func (h *SyncKvvmHandler) updateKVVM(ctx context.Context, s state.VirtualMachine patch.WithReplace("/spec/template/spec/domain/memory/guest", domainMemory.Guest.String()), ) } - newCPU := newKVVM.Spec.Template.Spec.Domain.CPU - if newCPU != nil && len(newCPU.Features) == 0 { - jsonPatch.Append( - patch.WithRemove("/spec/template/spec/domain/cpu/features"), - ) - } + //newCPU := newKVVM.Spec.Template.Spec.Domain.CPU + //if newCPU != nil && len(newCPU.Features) == 0 { + // jsonPatch.Append( + // patch.WithRemove("/spec/template/spec/domain/cpu/features"), + // ) + //} if jsonPatch.Len() > 0 { patchBytes, err := jsonPatch.Bytes() if err != nil { From d3afcabf12f23655d7435631117b2188b07e90ec Mon Sep 17 00:00:00 2001 From: Ivan Mikheykin Date: Mon, 18 May 2026 20:20:49 +0300 Subject: [PATCH 3/3] ++ try with features=nil Signed-off-by: Ivan Mikheykin --- .../pkg/controller/vm/internal/sync_kvvm.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) 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 2a7068f39d..688b0f556d 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go @@ -410,22 +410,13 @@ func (h *SyncKvvmHandler) updateKVVM(ctx context.Context, s state.VirtualMachine log.Info("Update internal virtual machine done", "name", newKVVM.Name) log.Debug("Update internal virtual machine done", "name", newKVVM.Name, "kvvm", newKVVM) - // Add patches to remove fields with "omitempty" annotation. - jsonPatch := patch.JSONPatch{} if domainMemory != nil { + jsonPatch := patch.JSONPatch{} // Removing memory.maxGuest is not enough, replace memory.guest is needed to pass the vm-validator webhook. jsonPatch.Append( patch.WithRemove("/spec/template/spec/domain/memory/maxGuest"), patch.WithReplace("/spec/template/spec/domain/memory/guest", domainMemory.Guest.String()), ) - } - //newCPU := newKVVM.Spec.Template.Spec.Domain.CPU - //if newCPU != nil && len(newCPU.Features) == 0 { - // jsonPatch.Append( - // patch.WithRemove("/spec/template/spec/domain/cpu/features"), - // ) - //} - if jsonPatch.Len() > 0 { patchBytes, err := jsonPatch.Bytes() if err != nil { return fmt.Errorf("prepare json patch for internal virtual machine: %w", err)