diff --git a/pkg/api/v1/schema.go b/pkg/api/v1/schema.go index b33f9b72fd5c..9dc8f65bafd9 100644 --- a/pkg/api/v1/schema.go +++ b/pkg/api/v1/schema.go @@ -70,7 +70,7 @@ type ResourceRequirements struct { // +optional Requests v1.ResourceList `json:"requests,omitempty"` // Limits describes the maximum amount of compute resources allowed. - // Valid resource keys are "cpu". + // Valid resource keys are "memory" and "cpu". // +optional Limits v1.ResourceList `json:"limits,omitempty"` } diff --git a/pkg/virt-controller/services/template.go b/pkg/virt-controller/services/template.go index 9327dfcaaf63..0305c0e4bb77 100644 --- a/pkg/virt-controller/services/template.go +++ b/pkg/virt-controller/services/template.go @@ -97,6 +97,12 @@ func (t *templateService) RenderLaunchManifest(vm *v1.VirtualMachine) (*kubev1.P gracePeriodSeconds = gracePeriodSeconds + int64(15) gracePeriodKillAfter := gracePeriodSeconds + int64(15) + // Consider CPU and memory requests and limits for pod scheduling + resources := kubev1.ResourceRequirements{} + vmResources := vm.Spec.Domain.Resources + resources.Requests = vmResources.Requests + resources.Limits = vmResources.Limits + // VM target container container := kubev1.Container{ Name: "compute", @@ -132,6 +138,7 @@ func (t *templateService) RenderLaunchManifest(vm *v1.VirtualMachine) (*kubev1.P SuccessThreshold: int32(successThreshold), FailureThreshold: int32(failureThreshold), }, + Resources: resources, } containers, err := registrydisk.GenerateContainers(vm, "libvirt-runtime", "/var/run/libvirt") diff --git a/pkg/virt-controller/services/template_test.go b/pkg/virt-controller/services/template_test.go index 453e62709ec9..77697e5200ea 100644 --- a/pkg/virt-controller/services/template_test.go +++ b/pkg/virt-controller/services/template_test.go @@ -25,6 +25,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" kubev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "kubevirt.io/kubevirt/pkg/api/v1" @@ -123,6 +124,68 @@ var _ = Describe("Template", func() { Expect(pod.Spec.Affinity).To(BeNil()) }) }) + Context("with cpu and memory constraints", func() { + It("should add cpu and memory constraints to a template", func() { + + vm := v1.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testvm", + Namespace: "default", + UID: "1234", + }, + Spec: v1.VirtualMachineSpec{ + Domain: v1.DomainSpec{ + Resources: v1.ResourceRequirements{ + Requests: kubev1.ResourceList{ + kubev1.ResourceCPU: resource.MustParse("1m"), + kubev1.ResourceMemory: resource.MustParse("1Gi"), + }, + Limits: kubev1.ResourceList{ + kubev1.ResourceCPU: resource.MustParse("2m"), + kubev1.ResourceMemory: resource.MustParse("2Gi"), + }, + }, + }, + }, + } + + pod, err := svc.RenderLaunchManifest(&vm) + + Expect(err).To(BeNil()) + Expect(pod.Spec.Containers[0].Resources.Requests.Cpu().String()).To(Equal("1m")) + Expect(pod.Spec.Containers[0].Resources.Limits.Cpu().String()).To(Equal("2m")) + Expect(pod.Spec.Containers[0].Resources.Requests.Memory().String()).To(Equal("1Gi")) + Expect(pod.Spec.Containers[0].Resources.Limits.Memory().String()).To(Equal("2Gi")) + }) + It("should not add unset resources", func() { + + vm := v1.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testvm", + Namespace: "default", + UID: "1234", + }, + Spec: v1.VirtualMachineSpec{ + Domain: v1.DomainSpec{ + Resources: v1.ResourceRequirements{ + Requests: kubev1.ResourceList{ + kubev1.ResourceCPU: resource.MustParse("1m"), + kubev1.ResourceMemory: resource.MustParse("1Gi"), + }, + }, + }, + }, + } + + pod, err := svc.RenderLaunchManifest(&vm) + + Expect(err).To(BeNil()) + Expect(pod.Spec.Containers[0].Resources.Requests.Cpu().String()).To(Equal("1m")) + Expect(pod.Spec.Containers[0].Resources.Requests.Memory().String()).To(Equal("1Gi")) + Expect(pod.Spec.Containers[0].Resources.Limits).To(BeNil()) + }) + }) + }) Context("with pvc source", func() { It("should add pvc to template", func() {