VPA Admission controller e2e tests for boundary cases.

This commit is contained in:
Slawomir Chylek 2018-02-26 11:14:53 +01:00
parent a68c20ee49
commit 4e7f5612e3
5 changed files with 210 additions and 38 deletions

View File

@ -45,7 +45,7 @@ var _ = actuationSuiteE2eDescribe("Actuation", func() {
cpuQuantity := parseQuantityOrDie("100m") cpuQuantity := parseQuantityOrDie("100m")
memoryQuantity := parseQuantityOrDie("100Mi") memoryQuantity := parseQuantityOrDie("100Mi")
d := hamsterDeployment(f, cpuQuantity, memoryQuantity) d := newHamsterDeploymentWithResources(f, cpuQuantity, memoryQuantity)
d, err := c.ExtensionsV1beta1().Deployments(ns).Create(d) d, err := c.ExtensionsV1beta1().Deployments(ns).Create(d)
gomega.Expect(err).NotTo(gomega.HaveOccurred()) gomega.Expect(err).NotTo(gomega.HaveOccurred())
err = framework.WaitForDeploymentComplete(c, d) err = framework.WaitForDeploymentComplete(c, d)

View File

@ -18,9 +18,9 @@ package autoscaling
import ( import (
apiv1 "k8s.io/api/core/v1" apiv1 "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/poc.autoscaling.k8s.io/v1alpha1" vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/poc.autoscaling.k8s.io/v1alpha1"
vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
"k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/framework"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo"
@ -30,49 +30,26 @@ import (
var _ = admissionControllerE2eDescribe("Admission-controller", func() { var _ = admissionControllerE2eDescribe("Admission-controller", func() {
f := framework.NewDefaultFramework("vertical-pod-autoscaling") f := framework.NewDefaultFramework("vertical-pod-autoscaling")
ginkgo.It("starts pods with new request", func() { ginkgo.It("starts pods with new recommended request", func() {
c := f.ClientSet d := newHamsterDeploymentWithResources(f, parseQuantityOrDie("100m") /*cpu*/, parseQuantityOrDie("100Mi") /*memory*/)
ns := f.Namespace.Name
ginkgo.By("Setting up a VPA CRD") ginkgo.By("Setting up a VPA CRD")
config, err := framework.LoadConfig()
gomega.Expect(err).NotTo(gomega.HaveOccurred())
vpaCRD := newVPA(f, "hamster-vpa", &metav1.LabelSelector{ vpaCRD := newVPA(f, "hamster-vpa", &metav1.LabelSelector{
MatchLabels: map[string]string{ MatchLabels: d.Spec.Template.Labels,
"app": "hamster",
},
}) })
newCPUQuantity := parseQuantityOrDie("250m")
newMemoryQuantity := parseQuantityOrDie("200Mi")
vpaCRD.Status.Recommendation.ContainerRecommendations = []vpa_types.RecommendedContainerResources{ vpaCRD.Status.Recommendation.ContainerRecommendations = []vpa_types.RecommendedContainerResources{
{ {
Name: "hamster", Name: "hamster",
Target: apiv1.ResourceList{ Target: apiv1.ResourceList{
apiv1.ResourceCPU: newCPUQuantity, apiv1.ResourceCPU: parseQuantityOrDie("250m"),
apiv1.ResourceMemory: newMemoryQuantity, apiv1.ResourceMemory: parseQuantityOrDie("200Mi"),
}, },
}, },
} }
installVPA(f, vpaCRD)
vpaClientSet := vpa_clientset.NewForConfigOrDie(config)
vpaClient := vpaClientSet.PocV1alpha1()
_, err = vpaClient.VerticalPodAutoscalers(ns).Create(vpaCRD)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
ginkgo.By("Setting up a hamster deployment") ginkgo.By("Setting up a hamster deployment")
podList := startDeploymentPods(f, d)
cpuQuantity := parseQuantityOrDie("100m")
memoryQuantity := parseQuantityOrDie("100Mi")
d := hamsterDeployment(f, cpuQuantity, memoryQuantity)
d, err = c.ExtensionsV1beta1().Deployments(ns).Create(d)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
err = framework.WaitForDeploymentComplete(c, d)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
podList, err := framework.GetPodsForDeployment(c, d)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
// Originally Pods had 100m CPU, 100Mi of memory, but admission controller // Originally Pods had 100m CPU, 100Mi of memory, but admission controller
// should change it to recommended 250m CPU and 200Mi of memory. // should change it to recommended 250m CPU and 200Mi of memory.
@ -80,6 +57,185 @@ var _ = admissionControllerE2eDescribe("Admission-controller", func() {
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceCPU]).To(gomega.Equal(parseQuantityOrDie("250m"))) gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceCPU]).To(gomega.Equal(parseQuantityOrDie("250m")))
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceMemory]).To(gomega.Equal(parseQuantityOrDie("200Mi"))) gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceMemory]).To(gomega.Equal(parseQuantityOrDie("200Mi")))
} }
})
ginkgo.It("caps request to limit set by the user", func() {
d := newHamsterDeploymentWithResources(f, parseQuantityOrDie("100m") /*cpu*/, parseQuantityOrDie("100Mi") /*memory*/)
d.Spec.Template.Spec.Containers[0].Resources.Limits = apiv1.ResourceList{
apiv1.ResourceCPU: parseQuantityOrDie("222m"),
apiv1.ResourceMemory: parseQuantityOrDie("123Mi"),
}
ginkgo.By("Setting up a VPA CRD")
vpaCRD := newVPA(f, "hamster-vpa", &metav1.LabelSelector{
MatchLabels: d.Spec.Template.Labels,
})
vpaCRD.Status.Recommendation.ContainerRecommendations = []vpa_types.RecommendedContainerResources{
{
Name: "hamster",
Target: apiv1.ResourceList{
apiv1.ResourceCPU: parseQuantityOrDie("250m"),
apiv1.ResourceMemory: parseQuantityOrDie("200Mi"),
},
},
}
installVPA(f, vpaCRD)
ginkgo.By("Setting up a hamster deployment")
podList := startDeploymentPods(f, d)
// Originally Pods had 100m CPU, 100Mi of memory, but admission controller
// should change it to 222m CPU and 123Mi of memory (as this is the recommendation
// capped to the limit set by the user)
for _, pod := range podList.Items {
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceCPU]).To(gomega.Equal(parseQuantityOrDie("222m")))
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceMemory]).To(gomega.Equal(parseQuantityOrDie("123Mi")))
}
})
ginkgo.It("caps request to max set in VPA", func() {
d := newHamsterDeploymentWithResources(f, parseQuantityOrDie("100m") /*cpu*/, parseQuantityOrDie("100Mi") /*memory*/)
ginkgo.By("Setting up a VPA CRD")
vpaCRD := newVPA(f, "hamster-vpa", &metav1.LabelSelector{
MatchLabels: d.Spec.Template.Labels,
})
vpaCRD.Status.Recommendation.ContainerRecommendations = []vpa_types.RecommendedContainerResources{
{
Name: "hamster",
Target: apiv1.ResourceList{
apiv1.ResourceCPU: parseQuantityOrDie("250m"),
apiv1.ResourceMemory: parseQuantityOrDie("200Mi"),
},
MaxRecommended: apiv1.ResourceList{
apiv1.ResourceCPU: parseQuantityOrDie("233m"),
apiv1.ResourceMemory: parseQuantityOrDie("150Mi"),
},
},
}
installVPA(f, vpaCRD)
ginkgo.By("Setting up a hamster deployment")
podList := startDeploymentPods(f, d)
// Originally Pods had 100m CPU, 100Mi of memory, but admission controller
// should change it to 233m CPU and 150Mi of memory (as this is the recommendation
// capped to max specified in VPA)
for _, pod := range podList.Items {
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceCPU]).To(gomega.Equal(parseQuantityOrDie("233m")))
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceMemory]).To(gomega.Equal(parseQuantityOrDie("150Mi")))
}
})
ginkgo.It("raises request to min set in VPA", func() {
d := newHamsterDeploymentWithResources(f, parseQuantityOrDie("100m") /*cpu*/, parseQuantityOrDie("100Mi") /*memory*/)
ginkgo.By("Setting up a VPA CRD")
vpaCRD := newVPA(f, "hamster-vpa", &metav1.LabelSelector{
MatchLabels: d.Spec.Template.Labels,
})
vpaCRD.Status.Recommendation.ContainerRecommendations = []vpa_types.RecommendedContainerResources{
{
Name: "hamster",
Target: apiv1.ResourceList{
apiv1.ResourceCPU: parseQuantityOrDie("50m"),
apiv1.ResourceMemory: parseQuantityOrDie("60Mi"),
},
MinRecommended: apiv1.ResourceList{
apiv1.ResourceCPU: parseQuantityOrDie("90m"),
apiv1.ResourceMemory: parseQuantityOrDie("80Mi"),
},
},
}
installVPA(f, vpaCRD)
ginkgo.By("Setting up a hamster deployment")
podList := startDeploymentPods(f, d)
// Originally Pods had 100m CPU, 100Mi of memory, but admission controller
// should change it to recommended 90m CPU and 800Mi of memory (as this the
// recommendation raised to min specified in VPA)
for _, pod := range podList.Items {
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceCPU]).To(gomega.Equal(parseQuantityOrDie("90m")))
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceMemory]).To(gomega.Equal(parseQuantityOrDie("80Mi")))
}
})
ginkgo.It("leaves users request when no recommendation", func() {
d := newHamsterDeploymentWithResources(f, parseQuantityOrDie("100m") /*cpu*/, parseQuantityOrDie("100Mi") /*memory*/)
ginkgo.By("Setting up a VPA CRD")
vpaCRD := newVPA(f, "hamster-vpa", &metav1.LabelSelector{
MatchLabels: d.Spec.Template.Labels,
})
installVPA(f, vpaCRD)
ginkgo.By("Setting up a hamster deployment")
podList := startDeploymentPods(f, d)
// VPA has no recommendation, so user's request is passed through
for _, pod := range podList.Items {
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceCPU]).To(gomega.Equal(parseQuantityOrDie("100m")))
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceMemory]).To(gomega.Equal(parseQuantityOrDie("100Mi")))
}
})
ginkgo.It("leaves user's request when target recommendation is zero", func() {
d := newHamsterDeploymentWithResources(f, parseQuantityOrDie("100m") /*cpu*/, parseQuantityOrDie("100Mi") /*memory*/)
ginkgo.By("Setting up a VPA CRD")
vpaCRD := newVPA(f, "hamster-vpa", &metav1.LabelSelector{
MatchLabels: d.Spec.Template.Labels,
})
vpaCRD.Status.Recommendation.ContainerRecommendations = []vpa_types.RecommendedContainerResources{
{
Name: "hamster",
Target: apiv1.ResourceList{
apiv1.ResourceCPU: parseQuantityOrDie("0"),
apiv1.ResourceMemory: parseQuantityOrDie("0"),
},
},
}
installVPA(f, vpaCRD)
ginkgo.By("Setting up a hamster deployment")
podList := startDeploymentPods(f, d)
// VPA has no recommendation, so user's request is passed through
for _, pod := range podList.Items {
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceCPU]).To(gomega.Equal(parseQuantityOrDie("100m")))
gomega.Expect(pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceMemory]).To(gomega.Equal(parseQuantityOrDie("100Mi")))
}
})
ginkgo.It("passes empty request when no recommendation and no user-specified request", func() {
d := newHamsterDeployment(f)
ginkgo.By("Setting up a VPA CRD")
vpaCRD := newVPA(f, "hamster-vpa", &metav1.LabelSelector{
MatchLabels: d.Spec.Template.Labels,
})
installVPA(f, vpaCRD)
ginkgo.By("Setting up a hamster deployment")
podList := startDeploymentPods(f, d)
// VPA has no recommendation, deployment has no request specified
for _, pod := range podList.Items {
gomega.Expect(pod.Spec.Containers[0].Resources.Requests).To(gomega.BeEmpty())
}
})
}) })
})
func startDeploymentPods(f *framework.Framework, deployment *extensions.Deployment) *apiv1.PodList {
c, ns := f.ClientSet, f.Namespace.Name
deployment, err := c.ExtensionsV1beta1().Deployments(ns).Create(deployment)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
err = framework.WaitForDeploymentComplete(c, deployment)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
podList, err := framework.GetPodsForDeployment(c, deployment)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
return podList
}

View File

@ -27,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/poc.autoscaling.k8s.io/v1alpha1" vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/poc.autoscaling.k8s.io/v1alpha1"
vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
"k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/framework"
) )
@ -64,15 +65,20 @@ func actuationSuiteE2eDescribe(name string, body func()) bool {
return e2eDescribe(actuationSuite, name, body) return e2eDescribe(actuationSuite, name, body)
} }
func hamsterDeployment(f *framework.Framework, cpuQuantity, memoryQuantity resource.Quantity) *extensions.Deployment { func newHamsterDeployment(f *framework.Framework) *extensions.Deployment {
d := framework.NewDeployment("hamster-deployment", 3, map[string]string{"app": "hamster"}, "hamster", "gcr.io/google_containers/ubuntu-slim:0.1", extensions.RollingUpdateDeploymentStrategyType) d := framework.NewDeployment("hamster-deployment", 3, map[string]string{"app": "hamster"}, "hamster", "gcr.io/google_containers/ubuntu-slim:0.1", extensions.RollingUpdateDeploymentStrategyType)
d.ObjectMeta.Namespace = f.Namespace.Name d.ObjectMeta.Namespace = f.Namespace.Name
d.Spec.Template.Spec.Containers[0].Command = []string{"/bin/sh"}
d.Spec.Template.Spec.Containers[0].Args = []string{"-c", "/usr/bin/yes >/dev/null"}
return d
}
func newHamsterDeploymentWithResources(f *framework.Framework, cpuQuantity, memoryQuantity resource.Quantity) *extensions.Deployment {
d := newHamsterDeployment(f)
d.Spec.Template.Spec.Containers[0].Resources.Requests = v1.ResourceList{ d.Spec.Template.Spec.Containers[0].Resources.Requests = v1.ResourceList{
v1.ResourceCPU: cpuQuantity, v1.ResourceCPU: cpuQuantity,
v1.ResourceMemory: memoryQuantity, v1.ResourceMemory: memoryQuantity,
} }
d.Spec.Template.Spec.Containers[0].Command = []string{"/bin/sh"}
d.Spec.Template.Spec.Containers[0].Args = []string{"-c", "/usr/bin/yes >/dev/null"}
return d return d
} }
@ -95,6 +101,16 @@ func newVPA(f *framework.Framework, name string, selector *metav1.LabelSelector)
return &vpa return &vpa
} }
func installVPA(f *framework.Framework, vpa *vpa_types.VerticalPodAutoscaler) {
ns := f.Namespace.Name
config, err := framework.LoadConfig()
gomega.Expect(err).NotTo(gomega.HaveOccurred())
vpaClientSet := vpa_clientset.NewForConfigOrDie(config)
vpaClient := vpaClientSet.PocV1alpha1()
_, err = vpaClient.VerticalPodAutoscalers(ns).Create(vpa)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
}
func parseQuantityOrDie(text string) resource.Quantity { func parseQuantityOrDie(text string) resource.Quantity {
quantity, err := resource.ParseQuantity(text) quantity, err := resource.ParseQuantity(text)
gomega.Expect(err).NotTo(gomega.HaveOccurred()) gomega.Expect(err).NotTo(gomega.HaveOccurred())

View File

@ -41,7 +41,7 @@ var _ = recommenderE2eDescribe("VPA CRD object", func() {
cpuQuantity := parseQuantityOrDie("100m") cpuQuantity := parseQuantityOrDie("100m")
memoryQuantity := parseQuantityOrDie("100Mi") memoryQuantity := parseQuantityOrDie("100Mi")
d := hamsterDeployment(f, cpuQuantity, memoryQuantity) d := newHamsterDeploymentWithResources(f, cpuQuantity, memoryQuantity)
_, err := c.ExtensionsV1beta1().Deployments(ns).Create(d) _, err := c.ExtensionsV1beta1().Deployments(ns).Create(d)
gomega.Expect(err).NotTo(gomega.HaveOccurred()) gomega.Expect(err).NotTo(gomega.HaveOccurred())
err = framework.WaitForDeploymentComplete(c, d) err = framework.WaitForDeploymentComplete(c, d)

View File

@ -46,7 +46,7 @@ var _ = updaterE2eDescribe("Updater", func() {
cpuQuantity := parseQuantityOrDie("100m") cpuQuantity := parseQuantityOrDie("100m")
memoryQuantity := parseQuantityOrDie("100Mi") memoryQuantity := parseQuantityOrDie("100Mi")
d := hamsterDeployment(f, cpuQuantity, memoryQuantity) d := newHamsterDeploymentWithResources(f, cpuQuantity, memoryQuantity)
d, err := c.ExtensionsV1beta1().Deployments(ns).Create(d) d, err := c.ExtensionsV1beta1().Deployments(ns).Create(d)
gomega.Expect(err).NotTo(gomega.HaveOccurred()) gomega.Expect(err).NotTo(gomega.HaveOccurred())
err = framework.WaitForDeploymentComplete(c, d) err = framework.WaitForDeploymentComplete(c, d)