From 08a0123adec698e4753317b606f4471c55dedeb2 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Mon, 1 Jun 2026 07:48:18 +0300 Subject: [PATCH 1/7] add hotplug validators Signed-off-by: Valeriy Khorunzhin --- .../validators/hotplug_resources_validator.go | 157 ++++++++++++++++++ .../hotplug_resources_validator_test.go | 155 +++++++++++++++++ .../pkg/controller/vm/vm_webhook.go | 1 + 3 files changed, 313 insertions(+) create mode 100644 images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go create mode 100644 images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go new file mode 100644 index 0000000000..f853a7abfa --- /dev/null +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go @@ -0,0 +1,157 @@ +/* +Copyright 2026 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validators + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + "github.com/deckhouse/virtualization-controller/pkg/common" + "github.com/deckhouse/virtualization-controller/pkg/controller/kvbuilder" + "github.com/deckhouse/virtualization/api/core/v1alpha2" +) + +const maxHotplugCores = 128 + +var maxHotplugMemory = resource.MustParse("256Gi") + +type HotplugResourcesValidator struct { + client client.Client +} + +func NewHotplugResourcesValidator(client client.Client) *HotplugResourcesValidator { + return &HotplugResourcesValidator{ + client: client, + } +} + +func (v *HotplugResourcesValidator) ValidateCreate(_ context.Context, _ *v1alpha2.VirtualMachine) (admission.Warnings, error) { + return nil, nil +} + +func (v *HotplugResourcesValidator) ValidateUpdate(ctx context.Context, oldVM, newVM *v1alpha2.VirtualMachine) (admission.Warnings, error) { + if !isHotplugResourcesChanged(oldVM, newVM) { + return nil, nil + } + + if err := validateHotplugRanges(newVM); err != nil { + return nil, err + } + + if err := v.validateProjectQuota(ctx, oldVM, newVM); err != nil { + return nil, err + } + + return nil, nil +} + +func isHotplugResourcesChanged(oldVM, newVM *v1alpha2.VirtualMachine) bool { + if oldVM.Spec.CPU.Cores != newVM.Spec.CPU.Cores { + return true + } + if oldVM.Spec.CPU.CoreFraction != newVM.Spec.CPU.CoreFraction { + return true + } + return oldVM.Spec.Memory.Size.Cmp(newVM.Spec.Memory.Size) != common.CmpEqual +} + +func validateHotplugRanges(vm *v1alpha2.VirtualMachine) error { + if vm.Spec.CPU.Cores > maxHotplugCores { + return fmt.Errorf("hotplug CPU cores should not exceed %d", maxHotplugCores) + } + + if vm.Spec.Memory.Size.Cmp(maxHotplugMemory) == common.CmpGreater { + return fmt.Errorf("hotplug memory should not exceed %s", maxHotplugMemory.String()) + } + + return nil +} + +func (v *HotplugResourcesValidator) validateProjectQuota(ctx context.Context, oldVM, newVM *v1alpha2.VirtualMachine) error { + newCPU, newMemory, err := getHotplugRequests(oldVM, newVM) + if err != nil { + return err + } + + var quotaList corev1.ResourceQuotaList + if err = v.client.List(ctx, "aList, client.InNamespace(newVM.GetNamespace())); err != nil { + return fmt.Errorf("list project quotas: %w", err) + } + + for i := range quotaList.Items { + quota := "aList.Items[i] + if err = checkQuotaForResource(quota, corev1.ResourceRequestsCPU, newCPU); err != nil { + return err + } + if err = checkQuotaForResource(quota, corev1.ResourceRequestsMemory, newMemory); err != nil { + return err + } + } + + return nil +} + +func getHotplugRequests(_ *v1alpha2.VirtualMachine, newVM *v1alpha2.VirtualMachine) (newCPU, newMemory resource.Quantity, err error) { + var newCPUReq *resource.Quantity + + newCPUReq, err = kvbuilder.GetCPURequest(newVM.Spec.CPU.Cores, newVM.Spec.CPU.CoreFraction) + if err != nil { + return resource.Quantity{}, resource.Quantity{}, fmt.Errorf("calculate new CPU request: %w", err) + } + + return *newCPUReq, newVM.Spec.Memory.Size, nil +} + +func checkQuotaForResource(quota *corev1.ResourceQuota, resourceName corev1.ResourceName, newReq resource.Quantity) error { + hard, hasHard := quota.Status.Hard[resourceName] + if !hasHard { + hard, hasHard = quota.Spec.Hard[resourceName] + } + if !hasHard { + return nil + } + + used := quota.Status.Used[resourceName] + free := hard.DeepCopy() + free.Sub(used) + if free.Sign() < 0 { + free.Set(0) + } + + if newReq.Cmp(hard) == common.CmpGreater { + return fmt.Errorf("hotplug %s request %s exceeds project quota %q hard limit %s", resourceName, newReq.String(), quota.GetName(), hard.String()) + } + + duringMigration := used.DeepCopy() + duringMigration.Add(newReq) + if duringMigration.Cmp(hard) == common.CmpGreater { + return fmt.Errorf( + "insufficient project quota %q for hotplug migration %s: required additional %s, available %s", + quota.GetName(), + resourceName, + newReq.String(), + free.String(), + ) + } + + return nil +} diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go new file mode 100644 index 0000000000..6e7e024133 --- /dev/null +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go @@ -0,0 +1,155 @@ +/* +Copyright 2026 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validators_test + +import ( + "context" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/deckhouse/virtualization-controller/pkg/controller/vm/internal/validators" + "github.com/deckhouse/virtualization/api/core/v1alpha2" +) + +var _ = Describe("HotplugResourcesValidator", func() { + type testCase struct { + name string + oldVM *v1alpha2.VirtualMachine + newVM *v1alpha2.VirtualMachine + objects []client.Object + wantError string + } + + DescribeTable("ValidateUpdate", + func(tc testCase) { + validator := validators.NewHotplugResourcesValidator(newFakeClientForHotplugValidator(tc.objects...)) + _, err := validator.ValidateUpdate(context.Background(), tc.oldVM, tc.newVM) + + if tc.wantError == "" { + Expect(err).NotTo(HaveOccurred()) + return + } + + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring(tc.wantError)) + }, + Entry("should skip validation when cpu and memory are unchanged", testCase{ + oldVM: newVMForHotplugValidation("vm", "default", 4, "50%", "8Gi"), + newVM: newVMForHotplugValidation("vm", "default", 4, "50%", "8Gi"), + wantError: "", + }), + Entry("should fail when hotplug cores exceed allowed maximum", testCase{ + oldVM: newVMForHotplugValidation("vm", "default", 64, "100%", "64Gi"), + newVM: newVMForHotplugValidation("vm", "default", 129, "100%", "64Gi"), + wantError: "hotplug CPU cores should not exceed 128", + }), + Entry("should fail when hotplug memory exceeds allowed maximum", testCase{ + oldVM: newVMForHotplugValidation("vm", "default", 16, "100%", "128Gi"), + newVM: newVMForHotplugValidation("vm", "default", 16, "100%", "257Gi"), + wantError: "hotplug memory should not exceed 256Gi", + }), + Entry("should fail when quota is insufficient during migration", testCase{ + oldVM: newVMForHotplugValidation("vm", "default", 2, "100%", "8Gi"), + newVM: newVMForHotplugValidation("vm", "default", 4, "100%", "8Gi"), + objects: []client.Object{ + newResourceQuota( + "default", + resource.MustParse("6"), + resource.MustParse("8Gi"), + resource.MustParse("3"), + resource.MustParse("4Gi"), + ), + }, + wantError: "insufficient project quota", + }), + Entry("should pass when quota is sufficient", testCase{ + oldVM: newVMForHotplugValidation("vm", "default", 2, "100%", "8Gi"), + newVM: newVMForHotplugValidation("vm", "default", 4, "100%", "8Gi"), + objects: []client.Object{ + newResourceQuota( + "default", + resource.MustParse("10"), + resource.MustParse("32Gi"), + resource.MustParse("2"), + resource.MustParse("8Gi"), + ), + }, + wantError: "", + }), + ) +}) + +func newVMForHotplugValidation(name, namespace string, cores int, coreFraction, memory string) *v1alpha2.VirtualMachine { + return &v1alpha2.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: v1alpha2.VirtualMachineSpec{ + CPU: v1alpha2.CPUSpec{ + Cores: cores, + CoreFraction: coreFraction, + }, + Memory: v1alpha2.MemorySpec{ + Size: resource.MustParse(memory), + }, + }, + } +} + +func newResourceQuota(namespace string, cpuHard, memoryHard, cpuUsed, memoryUsed resource.Quantity) *corev1.ResourceQuota { + return &corev1.ResourceQuota{ + ObjectMeta: metav1.ObjectMeta{ + Name: "project-quota", + Namespace: namespace, + }, + Spec: corev1.ResourceQuotaSpec{ + Hard: corev1.ResourceList{ + corev1.ResourceRequestsCPU: cpuHard, + corev1.ResourceRequestsMemory: memoryHard, + }, + }, + Status: corev1.ResourceQuotaStatus{ + Hard: corev1.ResourceList{ + corev1.ResourceRequestsCPU: cpuHard, + corev1.ResourceRequestsMemory: memoryHard, + }, + Used: corev1.ResourceList{ + corev1.ResourceRequestsCPU: cpuUsed, + corev1.ResourceRequestsMemory: memoryUsed, + }, + }, + } +} + +func newFakeClientForHotplugValidator(objects ...client.Object) client.Client { + scheme := runtime.NewScheme() + Expect(v1alpha2.AddToScheme(scheme)).To(Succeed()) + Expect(corev1.AddToScheme(scheme)).To(Succeed()) + + return fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(objects...). + Build() +} diff --git a/images/virtualization-artifact/pkg/controller/vm/vm_webhook.go b/images/virtualization-artifact/pkg/controller/vm/vm_webhook.go index ac4ab38cd5..d8a400d316 100644 --- a/images/virtualization-artifact/pkg/controller/vm/vm_webhook.go +++ b/images/virtualization-artifact/pkg/controller/vm/vm_webhook.go @@ -49,6 +49,7 @@ func NewValidator(client client.Client, blockDeviceService *service.BlockDeviceS validators.NewIPAMValidator(client), validators.NewBlockDeviceSpecRefsValidator(), validators.NewSizingPolicyValidator(client), + validators.NewHotplugResourcesValidator(client), validators.NewBlockDeviceLimiterValidator(blockDeviceService, log), validators.NewAffinityValidator(), validators.NewTopologySpreadConstraintValidator(), From ee6764b094e59c80d0dc13b2e0284346eae103f7 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 2 Jun 2026 10:01:31 +0300 Subject: [PATCH 2/7] fix linter Signed-off-by: Valeriy Khorunzhin --- .../vm/internal/validators/hotplug_resources_validator_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go index 6e7e024133..7e85b87e2e 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go @@ -18,6 +18,7 @@ package validators_test import ( "context" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -34,7 +35,6 @@ import ( var _ = Describe("HotplugResourcesValidator", func() { type testCase struct { - name string oldVM *v1alpha2.VirtualMachine newVM *v1alpha2.VirtualMachine objects []client.Object From 041b28950c777389bbf7dd9b6a0bb89bfb26be2e Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 2 Jun 2026 11:46:26 +0300 Subject: [PATCH 3/7] fix linter Signed-off-by: Valeriy Khorunzhin --- .../validators/hotplug_resources_validator.go | 8 ++--- .../hotplug_resources_validator_test.go | 31 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go index f853a7abfa..379e191874 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go @@ -57,7 +57,7 @@ func (v *HotplugResourcesValidator) ValidateUpdate(ctx context.Context, oldVM, n return nil, err } - if err := v.validateProjectQuota(ctx, oldVM, newVM); err != nil { + if err := v.validateProjectQuota(ctx, newVM); err != nil { return nil, err } @@ -86,8 +86,8 @@ func validateHotplugRanges(vm *v1alpha2.VirtualMachine) error { return nil } -func (v *HotplugResourcesValidator) validateProjectQuota(ctx context.Context, oldVM, newVM *v1alpha2.VirtualMachine) error { - newCPU, newMemory, err := getHotplugRequests(oldVM, newVM) +func (v *HotplugResourcesValidator) validateProjectQuota(ctx context.Context, newVM *v1alpha2.VirtualMachine) error { + newCPU, newMemory, err := getHotplugRequests(newVM) if err != nil { return err } @@ -110,7 +110,7 @@ func (v *HotplugResourcesValidator) validateProjectQuota(ctx context.Context, ol return nil } -func getHotplugRequests(_ *v1alpha2.VirtualMachine, newVM *v1alpha2.VirtualMachine) (newCPU, newMemory resource.Quantity, err error) { +func getHotplugRequests(newVM *v1alpha2.VirtualMachine) (newCPU, newMemory resource.Quantity, err error) { var newCPUReq *resource.Quantity newCPUReq, err = kvbuilder.GetCPURequest(newVM.Spec.CPU.Cores, newVM.Spec.CPU.CoreFraction) diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go index 7e85b87e2e..2bb918dcc2 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go @@ -19,6 +19,8 @@ package validators_test import ( "context" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -26,9 +28,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/deckhouse/virtualization-controller/pkg/controller/vm/internal/validators" "github.com/deckhouse/virtualization/api/core/v1alpha2" ) @@ -55,23 +54,23 @@ var _ = Describe("HotplugResourcesValidator", func() { Expect(err.Error()).To(ContainSubstring(tc.wantError)) }, Entry("should skip validation when cpu and memory are unchanged", testCase{ - oldVM: newVMForHotplugValidation("vm", "default", 4, "50%", "8Gi"), - newVM: newVMForHotplugValidation("vm", "default", 4, "50%", "8Gi"), + oldVM: newVMForHotplugValidation(4, "50%", "8Gi"), + newVM: newVMForHotplugValidation(4, "50%", "8Gi"), wantError: "", }), Entry("should fail when hotplug cores exceed allowed maximum", testCase{ - oldVM: newVMForHotplugValidation("vm", "default", 64, "100%", "64Gi"), - newVM: newVMForHotplugValidation("vm", "default", 129, "100%", "64Gi"), + oldVM: newVMForHotplugValidation(64, "100%", "64Gi"), + newVM: newVMForHotplugValidation(129, "100%", "64Gi"), wantError: "hotplug CPU cores should not exceed 128", }), Entry("should fail when hotplug memory exceeds allowed maximum", testCase{ - oldVM: newVMForHotplugValidation("vm", "default", 16, "100%", "128Gi"), - newVM: newVMForHotplugValidation("vm", "default", 16, "100%", "257Gi"), + oldVM: newVMForHotplugValidation(16, "100%", "128Gi"), + newVM: newVMForHotplugValidation(16, "100%", "257Gi"), wantError: "hotplug memory should not exceed 256Gi", }), Entry("should fail when quota is insufficient during migration", testCase{ - oldVM: newVMForHotplugValidation("vm", "default", 2, "100%", "8Gi"), - newVM: newVMForHotplugValidation("vm", "default", 4, "100%", "8Gi"), + oldVM: newVMForHotplugValidation(2, "100%", "8Gi"), + newVM: newVMForHotplugValidation(4, "100%", "8Gi"), objects: []client.Object{ newResourceQuota( "default", @@ -84,8 +83,8 @@ var _ = Describe("HotplugResourcesValidator", func() { wantError: "insufficient project quota", }), Entry("should pass when quota is sufficient", testCase{ - oldVM: newVMForHotplugValidation("vm", "default", 2, "100%", "8Gi"), - newVM: newVMForHotplugValidation("vm", "default", 4, "100%", "8Gi"), + oldVM: newVMForHotplugValidation(2, "100%", "8Gi"), + newVM: newVMForHotplugValidation(4, "100%", "8Gi"), objects: []client.Object{ newResourceQuota( "default", @@ -100,11 +99,11 @@ var _ = Describe("HotplugResourcesValidator", func() { ) }) -func newVMForHotplugValidation(name, namespace string, cores int, coreFraction, memory string) *v1alpha2.VirtualMachine { +func newVMForHotplugValidation(cores int, coreFraction, memory string) *v1alpha2.VirtualMachine { return &v1alpha2.VirtualMachine{ ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, + Name: "vm", + Namespace: "default", }, Spec: v1alpha2.VirtualMachineSpec{ CPU: v1alpha2.CPUSpec{ From bbdbe606b43588b9e18c04642931f5dc2e3f46ca Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 2 Jun 2026 16:57:45 +0300 Subject: [PATCH 4/7] Update images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go Co-authored-by: Ivan Mikheykin Signed-off-by: Valeriy Khorunzhin --- .../vm/internal/validators/hotplug_resources_validator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go index 379e191874..8b4c03d860 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go @@ -138,7 +138,7 @@ func checkQuotaForResource(quota *corev1.ResourceQuota, resourceName corev1.Reso } if newReq.Cmp(hard) == common.CmpGreater { - return fmt.Errorf("hotplug %s request %s exceeds project quota %q hard limit %s", resourceName, newReq.String(), quota.GetName(), hard.String()) + return fmt.Errorf("%s request %s exceeds project quota %q hard limit %s", resourceName, newReq.String(), quota.GetName(), hard.String()) } duringMigration := used.DeepCopy() From 68e877702e4b3475e7bd3a0c79118dbf40ff39df Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 2 Jun 2026 16:57:55 +0300 Subject: [PATCH 5/7] Update images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go Co-authored-by: Ivan Mikheykin Signed-off-by: Valeriy Khorunzhin --- .../vm/internal/validators/hotplug_resources_validator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go index 8b4c03d860..05ef35818f 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go @@ -80,7 +80,7 @@ func validateHotplugRanges(vm *v1alpha2.VirtualMachine) error { } if vm.Spec.Memory.Size.Cmp(maxHotplugMemory) == common.CmpGreater { - return fmt.Errorf("hotplug memory should not exceed %s", maxHotplugMemory.String()) + return fmt.Errorf("memory size should not exceed %s", maxHotplugMemory.String()) } return nil From e0a9d3a8b29ef0e55dc7e0fd0b3e16ffadafb972 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 2 Jun 2026 17:04:13 +0300 Subject: [PATCH 6/7] remove useless check Signed-off-by: Valeriy Khorunzhin --- .../validators/hotplug_resources_validator.go | 20 ------------------- .../hotplug_resources_validator_test.go | 10 ---------- 2 files changed, 30 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go index 05ef35818f..28124ff29b 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator.go @@ -30,10 +30,6 @@ import ( "github.com/deckhouse/virtualization/api/core/v1alpha2" ) -const maxHotplugCores = 128 - -var maxHotplugMemory = resource.MustParse("256Gi") - type HotplugResourcesValidator struct { client client.Client } @@ -53,10 +49,6 @@ func (v *HotplugResourcesValidator) ValidateUpdate(ctx context.Context, oldVM, n return nil, nil } - if err := validateHotplugRanges(newVM); err != nil { - return nil, err - } - if err := v.validateProjectQuota(ctx, newVM); err != nil { return nil, err } @@ -74,18 +66,6 @@ func isHotplugResourcesChanged(oldVM, newVM *v1alpha2.VirtualMachine) bool { return oldVM.Spec.Memory.Size.Cmp(newVM.Spec.Memory.Size) != common.CmpEqual } -func validateHotplugRanges(vm *v1alpha2.VirtualMachine) error { - if vm.Spec.CPU.Cores > maxHotplugCores { - return fmt.Errorf("hotplug CPU cores should not exceed %d", maxHotplugCores) - } - - if vm.Spec.Memory.Size.Cmp(maxHotplugMemory) == common.CmpGreater { - return fmt.Errorf("memory size should not exceed %s", maxHotplugMemory.String()) - } - - return nil -} - func (v *HotplugResourcesValidator) validateProjectQuota(ctx context.Context, newVM *v1alpha2.VirtualMachine) error { newCPU, newMemory, err := getHotplugRequests(newVM) if err != nil { diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go index 2bb918dcc2..f05092c9e1 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go @@ -58,16 +58,6 @@ var _ = Describe("HotplugResourcesValidator", func() { newVM: newVMForHotplugValidation(4, "50%", "8Gi"), wantError: "", }), - Entry("should fail when hotplug cores exceed allowed maximum", testCase{ - oldVM: newVMForHotplugValidation(64, "100%", "64Gi"), - newVM: newVMForHotplugValidation(129, "100%", "64Gi"), - wantError: "hotplug CPU cores should not exceed 128", - }), - Entry("should fail when hotplug memory exceeds allowed maximum", testCase{ - oldVM: newVMForHotplugValidation(16, "100%", "128Gi"), - newVM: newVMForHotplugValidation(16, "100%", "257Gi"), - wantError: "hotplug memory should not exceed 256Gi", - }), Entry("should fail when quota is insufficient during migration", testCase{ oldVM: newVMForHotplugValidation(2, "100%", "8Gi"), newVM: newVMForHotplugValidation(4, "100%", "8Gi"), From 1ceaa6e83de2d7b33195a1e17fc12ecff1f3983a Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 2 Jun 2026 17:15:07 +0300 Subject: [PATCH 7/7] fix linter Signed-off-by: Valeriy Khorunzhin --- .../vm/internal/validators/hotplug_resources_validator_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go index f05092c9e1..511122a4e7 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/hotplug_resources_validator_test.go @@ -89,6 +89,7 @@ var _ = Describe("HotplugResourcesValidator", func() { ) }) +//nolint:unparam // memory is always "8Gi" in tests, but kept for flexibility func newVMForHotplugValidation(cores int, coreFraction, memory string) *v1alpha2.VirtualMachine { return &v1alpha2.VirtualMachine{ ObjectMeta: metav1.ObjectMeta{