diff --git a/vertical-pod-autoscaler/e2e/integration/integration.go b/vertical-pod-autoscaler/e2e/integration/integration.go new file mode 100644 index 0000000000..c8e27d187e --- /dev/null +++ b/vertical-pod-autoscaler/e2e/integration/integration.go @@ -0,0 +1,47 @@ +/* +Copyright 2025 The Kubernetes Authors. + +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 integration + +import ( + "testing" + + ginkgo "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + + runtimeutils "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/component-base/logs" + "k8s.io/kubernetes/test/e2e/framework" +) + +// RunE2ETests checks configuration parameters (specified through flags) and then runs +// E2E tests using the Ginkgo runner. +// If a "report directory" is specified, one or more JUnit test reports will be +// generated in this directory, and cluster logs will also be saved. +// This function is called on each Ginkgo node in parallel mode. +func RunE2ETests(t *testing.T) { + runtimeutils.ReallyCrash = true + logs.InitLogs() + defer logs.FlushLogs() + + gomega.RegisterFailHandler(framework.Fail) + suiteConfig, _ := ginkgo.GinkgoConfiguration() + // Disable skipped tests unless they are explicitly requested. + if len(suiteConfig.FocusStrings) == 0 && len(suiteConfig.SkipStrings) == 0 { + suiteConfig.SkipStrings = []string{`\[Flaky\]|\[Feature:.+\]`} + } + ginkgo.RunSpecs(t, "Kubernetes e2e suite") +} diff --git a/vertical-pod-autoscaler/e2e/integration/integration_test.go b/vertical-pod-autoscaler/e2e/integration/integration_test.go new file mode 100644 index 0000000000..4cbdd44dba --- /dev/null +++ b/vertical-pod-autoscaler/e2e/integration/integration_test.go @@ -0,0 +1,47 @@ +/* +Copyright 2025 The Kubernetes Authors. + +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 integration + +import ( + "flag" + "os" + "testing" + + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/kubernetes/test/e2e/framework/config" +) + +// handleFlags sets up all flags and parses the command line. +func handleFlags() { + config.CopyFlags(config.Flags, flag.CommandLine) + framework.RegisterCommonFlags(flag.CommandLine) + framework.RegisterClusterFlags(flag.CommandLine) + flag.Parse() +} + +func TestMain(m *testing.M) { + // Register test flags, then parse flags. + handleFlags() + + framework.AfterReadingAllFlags(&framework.TestContext) + + os.Exit(m.Run()) +} + +func TestIntegration(t *testing.T) { + RunE2ETests(t) +} diff --git a/vertical-pod-autoscaler/e2e/integration/recommender.go b/vertical-pod-autoscaler/e2e/integration/recommender.go new file mode 100644 index 0000000000..4ccb1a685e --- /dev/null +++ b/vertical-pod-autoscaler/e2e/integration/recommender.go @@ -0,0 +1,138 @@ +/* +Copyright 2025 The Kubernetes Authors. + +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 integration + +import ( + "context" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/autoscaler/vertical-pod-autoscaler/e2e/utils" + + vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1" + vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned" + "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/test" + "k8s.io/kubernetes/test/e2e/framework" + podsecurity "k8s.io/pod-security-admission/api" + + ginkgo "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" +) + +var _ = utils.RecommenderE2eDescribe("Flags", func() { + f := framework.NewDefaultFramework("vertical-pod-autoscaling") + f.NamespacePodSecurityEnforceLevel = podsecurity.LevelBaseline + + var vpaClientSet vpa_clientset.Interface + var hamsterNamespace string + + ginkgo.BeforeEach(func() { + vpaClientSet = utils.GetVpaClientSet(f) + hamsterNamespace = f.Namespace.Name + }) + + ginkgo.AfterEach(func() { + f.ClientSet.AppsV1().Deployments(utils.RecommenderNamespace).Delete(context.TODO(), utils.RecommenderDeploymentName, metav1.DeleteOptions{}) + }) + + ginkgo.It("starts recommender with --vpa-object-namespace parameter", func() { + ginkgo.By("Setting up VPA deployment") + ignoredNamespace, err := f.CreateNamespace(context.TODO(), "ignored-namespace", nil) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + f.Namespace.Name = utils.RecommenderNamespace + vpaDeployment := utils.NewVPADeployment(f, []string{ + "--recommender-interval=10s", + fmt.Sprintf("--vpa-object-namespace=%s", hamsterNamespace), + }) + utils.StartDeploymentPods(f, vpaDeployment) + + testIncludedAndIgnoredNamespaces(f, vpaClientSet, hamsterNamespace, ignoredNamespace.Name) + }) + + ginkgo.It("starts recommender with --ignored-vpa-object-namespaces parameter", func() { + ginkgo.By("Setting up VPA deployment") + ignoredNamespace, err := f.CreateNamespace(context.TODO(), "ignored-namespace", nil) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + f.Namespace.Name = utils.RecommenderNamespace + vpaDeployment := utils.NewVPADeployment(f, []string{ + "--recommender-interval=10s", + fmt.Sprintf("--ignored-vpa-object-namespaces=%s", ignoredNamespace.Name), + }) + utils.StartDeploymentPods(f, vpaDeployment) + + testIncludedAndIgnoredNamespaces(f, vpaClientSet, hamsterNamespace, ignoredNamespace.Name) + }) +}) + +// Create VPA and deployment in 2 namespaces, 1 should be ignored +// Ignored namespace VPA and deployment are intentionally created first +// so that by the time included namespace has recommendation generated, +// we know that ignored namespace has been waiting long enough. +func testIncludedAndIgnoredNamespaces(f *framework.Framework, vpaClientSet vpa_clientset.Interface, includedNamespace, ignoredNamespace string) { + ginkgo.By("Setting up a hamster deployment in ignored namespace") + f.Namespace.Name = ignoredNamespace + d := utils.NewNHamstersDeployment(f, 2) + _ = utils.StartDeploymentPods(f, d) + + ginkgo.By("Setting up VPA for ignored namespace") + container1Name := utils.GetHamsterContainerNameByIndex(0) + container2Name := utils.GetHamsterContainerNameByIndex(1) + ignoredVpaCRD := test.VerticalPodAutoscaler(). + WithName("hamster-vpa"). + WithNamespace(ignoredNamespace). + WithTargetRef(utils.HamsterTargetRef). + WithContainer(container1Name). + WithScalingMode(container1Name, vpa_types.ContainerScalingModeOff). + WithContainer(container2Name). + Get() + f.Namespace.Name = ignoredNamespace + utils.InstallVPA(f, ignoredVpaCRD) + + ginkgo.By("Setting up a hamster deployment in included namespace") + f.Namespace.Name = includedNamespace + d = utils.NewNHamstersDeployment(f, 2) + _ = utils.StartDeploymentPods(f, d) + + ginkgo.By("Setting up VPA for included namespace") + vpaCRD := test.VerticalPodAutoscaler(). + WithName("hamster-vpa"). + WithNamespace(includedNamespace). + WithTargetRef(utils.HamsterTargetRef). + WithContainer(container1Name). + WithScalingMode(container1Name, vpa_types.ContainerScalingModeOff). + WithContainer(container2Name). + Get() + + f.Namespace.Name = includedNamespace + utils.InstallVPA(f, vpaCRD) + + ginkgo.By("Waiting for recommendation to be filled for just one container") + vpa, err := utils.WaitForRecommendationPresent(vpaClientSet, vpaCRD) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + errMsg := fmt.Sprintf("%s container has recommendations turned off. We expect expect only recommendations for %s", + utils.GetHamsterContainerNameByIndex(0), + utils.GetHamsterContainerNameByIndex(1)) + gomega.Expect(vpa.Status.Recommendation.ContainerRecommendations).Should(gomega.HaveLen(1), errMsg) + gomega.Expect(vpa.Status.Recommendation.ContainerRecommendations[0].ContainerName).To(gomega.Equal(utils.GetHamsterContainerNameByIndex(1)), errMsg) + + ginkgo.By("Ignored namespace should not be recommended") + ignoredVpa, err := vpaClientSet.AutoscalingV1().VerticalPodAutoscalers(ignoredNamespace).Get(context.TODO(), ignoredVpaCRD.Name, metav1.GetOptions{}) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + gomega.Expect(ignoredVpa.Status.Conditions).Should(gomega.HaveLen(0)) +} diff --git a/vertical-pod-autoscaler/e2e/utils/common.go b/vertical-pod-autoscaler/e2e/utils/common.go new file mode 100644 index 0000000000..b4fc8e12c3 --- /dev/null +++ b/vertical-pod-autoscaler/e2e/utils/common.go @@ -0,0 +1,325 @@ +/* +Copyright 2025 The Kubernetes Authors. + +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 utils + +import ( + "context" + "encoding/json" + "fmt" + "time" + + ginkgo "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + appsv1 "k8s.io/api/apps/v1" + autoscaling "k8s.io/api/autoscaling/v1" + apiv1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/test/e2e/framework" + framework_deployment "k8s.io/kubernetes/test/e2e/framework/deployment" + + vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1" + vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned" +) + +const ( + recommenderComponent = "recommender" + + // RecommenderDeploymentName is VPA recommender deployment name + RecommenderDeploymentName = "vpa-recommender" + // RecommenderNamespace is namespace to deploy VPA recommender + RecommenderNamespace = "kube-system" + // PollInterval is interval for polling + PollInterval = 10 * time.Second + // PollTimeout is timeout for polling + PollTimeout = 15 * time.Minute + + // DefaultHamsterReplicas is replicas of hamster deployment + DefaultHamsterReplicas = int32(3) + // DefaultHamsterBackoffLimit is BackoffLimit of hamster app + DefaultHamsterBackoffLimit = int32(10) +) + +// HamsterTargetRef is CrossVersionObjectReference of hamster app +var HamsterTargetRef = &autoscaling.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "hamster-deployment", +} + +// RecommenderLabels are labels of VPA recommender +var RecommenderLabels = map[string]string{"app": "vpa-recommender"} + +// HamsterLabels are labels of hamster app +var HamsterLabels = map[string]string{"app": "hamster"} + +// SIGDescribe adds sig-autoscaling tag to test description. +// Takes args that are passed to ginkgo.Describe. +func SIGDescribe(scenario, name string, args ...interface{}) bool { + full := fmt.Sprintf("[sig-autoscaling] [VPA] [%s] [v1] %s", scenario, name) + return ginkgo.Describe(full, args...) +} + +// RecommenderE2eDescribe describes a VPA recommender e2e test. +func RecommenderE2eDescribe(name string, args ...interface{}) bool { + return SIGDescribe(recommenderComponent, name, args...) +} + +// GetHamsterContainerNameByIndex returns name of i-th hamster container. +func GetHamsterContainerNameByIndex(i int) string { + switch { + case i < 0: + panic("negative index") + case i == 0: + return "hamster" + default: + return fmt.Sprintf("hamster%d", i+1) + } +} + +// GetVpaClientSet return a VpaClientSet +func GetVpaClientSet(f *framework.Framework) vpa_clientset.Interface { + config, err := framework.LoadConfig() + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error loading framework") + return vpa_clientset.NewForConfigOrDie(config) +} + +// InstallVPA installs a VPA object in the test cluster. +func InstallVPA(f *framework.Framework, vpa *vpa_types.VerticalPodAutoscaler) { + vpaClientSet := GetVpaClientSet(f) + _, err := vpaClientSet.AutoscalingV1().VerticalPodAutoscalers(f.Namespace.Name).Create(context.TODO(), vpa, metav1.CreateOptions{}) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error creating VPA") + // apiserver ignore status in vpa create, so need to update status + if !isStatusEmpty(&vpa.Status) { + if vpa.Status.Recommendation != nil { + PatchVpaRecommendation(f, vpa, vpa.Status.Recommendation) + } + } +} + +func isStatusEmpty(status *vpa_types.VerticalPodAutoscalerStatus) bool { + if status == nil { + return true + } + + if len(status.Conditions) == 0 && status.Recommendation == nil { + return true + } + return false +} + +// PatchRecord used for patch action +type PatchRecord struct { + Op string `json:"op,inline"` + Path string `json:"path,inline"` + Value interface{} `json:"value"` +} + +// PatchVpaRecommendation installs a new recommendation for VPA object. +func PatchVpaRecommendation(f *framework.Framework, vpa *vpa_types.VerticalPodAutoscaler, + recommendation *vpa_types.RecommendedPodResources) { + newStatus := vpa.Status.DeepCopy() + newStatus.Recommendation = recommendation + bytes, err := json.Marshal([]PatchRecord{{ + Op: "replace", + Path: "/status", + Value: *newStatus, + }}) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + _, err = GetVpaClientSet(f).AutoscalingV1().VerticalPodAutoscalers(f.Namespace.Name).Patch(context.TODO(), vpa.Name, types.JSONPatchType, bytes, metav1.PatchOptions{}, "status") + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "Failed to patch VPA.") +} + +// NewVPADeployment creates a VPA deployment with n containers +// for e2e test purposes. +func NewVPADeployment(f *framework.Framework, flags []string) *appsv1.Deployment { + d := framework_deployment.NewDeployment( + RecommenderDeploymentName, /*deploymentName*/ + 1, /*replicas*/ + RecommenderLabels, /*podLabels*/ + "recommender", /*imageName*/ + "localhost:5001/vpa-recommender", /*image*/ + appsv1.RollingUpdateDeploymentStrategyType, /*strategyType*/ + ) + d.ObjectMeta.Namespace = f.Namespace.Name + d.Spec.Template.Spec.Containers[0].ImagePullPolicy = apiv1.PullNever // Image must be loaded first + d.Spec.Template.Spec.ServiceAccountName = "vpa-recommender" + d.Spec.Template.Spec.Containers[0].Command = []string{"/recommender"} + d.Spec.Template.Spec.Containers[0].Args = flags + + runAsNonRoot := true + var runAsUser int64 = 65534 // nobody + d.Spec.Template.Spec.SecurityContext = &apiv1.PodSecurityContext{ + RunAsNonRoot: &runAsNonRoot, + RunAsUser: &runAsUser, + } + + // Same as deploy/recommender-deployment.yaml + d.Spec.Template.Spec.Containers[0].Resources = apiv1.ResourceRequirements{ + Limits: apiv1.ResourceList{ + apiv1.ResourceCPU: resource.MustParse("200m"), + apiv1.ResourceMemory: resource.MustParse("1000Mi"), + }, + Requests: apiv1.ResourceList{ + apiv1.ResourceCPU: resource.MustParse("50m"), + apiv1.ResourceMemory: resource.MustParse("500Mi"), + }, + } + + d.Spec.Template.Spec.Containers[0].Ports = []apiv1.ContainerPort{{ + Name: "prometheus", + ContainerPort: 8942, + }} + + d.Spec.Template.Spec.Containers[0].LivenessProbe = &apiv1.Probe{ + ProbeHandler: apiv1.ProbeHandler{ + HTTPGet: &apiv1.HTTPGetAction{ + Path: "/health-check", + Port: intstr.FromString("prometheus"), + Scheme: apiv1.URISchemeHTTP, + }, + }, + InitialDelaySeconds: 5, + PeriodSeconds: 10, + FailureThreshold: 3, + } + d.Spec.Template.Spec.Containers[0].ReadinessProbe = &apiv1.Probe{ + ProbeHandler: apiv1.ProbeHandler{ + HTTPGet: &apiv1.HTTPGetAction{ + Path: "/health-check", + Port: intstr.FromString("prometheus"), + Scheme: apiv1.URISchemeHTTP, + }, + }, + PeriodSeconds: 10, + FailureThreshold: 3, + } + + return d +} + +// NewNHamstersDeployment creates a simple hamster deployment with n containers +// for e2e test purposes. +func NewNHamstersDeployment(f *framework.Framework, n int) *appsv1.Deployment { + if n < 1 { + panic("container count should be greater than 0") + } + d := framework_deployment.NewDeployment( + "hamster-deployment", /*deploymentName*/ + DefaultHamsterReplicas, /*replicas*/ + HamsterLabels, /*podLabels*/ + GetHamsterContainerNameByIndex(0), /*imageName*/ + "registry.k8s.io/ubuntu-slim:0.14", /*image*/ + appsv1.RollingUpdateDeploymentStrategyType, /*strategyType*/ + ) + 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"} + for i := 1; i < n; i++ { + d.Spec.Template.Spec.Containers = append(d.Spec.Template.Spec.Containers, d.Spec.Template.Spec.Containers[0]) + d.Spec.Template.Spec.Containers[i].Name = GetHamsterContainerNameByIndex(i) + } + return d +} + +// StartDeploymentPods start and wait for a deployment to complete +func StartDeploymentPods(f *framework.Framework, deployment *appsv1.Deployment) *apiv1.PodList { + // Apiserver watch can lag depending on cached object count and apiserver resource usage. + // We assume that watch can lag up to 5 seconds. + const apiserverWatchLag = 5 * time.Second + // In admission controller e2e tests a recommendation is created before deployment. + // Creating deployment with size greater than 0 would create a race between information + // about pods and information about deployment getting to the admission controller. + // Any pods that get processed by AC before it receives information about the deployment + // don't receive recommendation. + // To avoid this create deployment with size 0, then scale it up to the desired size. + desiredPodCount := *deployment.Spec.Replicas + zero := int32(0) + deployment.Spec.Replicas = &zero + c, ns := f.ClientSet, f.Namespace.Name + deployment, err := c.AppsV1().Deployments(ns).Create(context.TODO(), deployment, metav1.CreateOptions{}) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "when creating deployment with size 0") + + err = framework_deployment.WaitForDeploymentComplete(c, deployment) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "when waiting for empty deployment to create") + // If admission controller receives pod before controller it will not apply recommendation and test will fail. + // Wait after creating deployment to ensure VPA knows about it, then scale up. + // Normally watch lag is not a problem in terms of correctness: + // - Mode "Auto": created pod without assigned resources will be handled by the eviction loop. + // - Mode "Initial": calculating recommendations takes more than potential ectd lag. + // - Mode "Off": pods are not handled by the admission controller. + // In e2e admission controller tests we want to focus on scenarios without considering watch lag. + // TODO(#2631): Remove sleep when issue is fixed. + time.Sleep(apiserverWatchLag) + + scale := autoscaling.Scale{ + ObjectMeta: metav1.ObjectMeta{ + Name: deployment.ObjectMeta.Name, + Namespace: deployment.ObjectMeta.Namespace, + }, + Spec: autoscaling.ScaleSpec{ + Replicas: desiredPodCount, + }, + } + afterScale, err := c.AppsV1().Deployments(ns).UpdateScale(context.TODO(), deployment.Name, &scale, metav1.UpdateOptions{}) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + gomega.Expect(afterScale.Spec.Replicas).To(gomega.Equal(desiredPodCount), fmt.Sprintf("expected %d replicas after scaling", desiredPodCount)) + + // After scaling deployment we need to retrieve current version with updated replicas count. + deployment, err = c.AppsV1().Deployments(ns).Get(context.TODO(), deployment.Name, metav1.GetOptions{}) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "when getting scaled deployment") + err = framework_deployment.WaitForDeploymentComplete(c, deployment) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "when waiting for deployment to resize") + + podList, err := framework_deployment.GetPodsForDeployment(context.TODO(), c, deployment) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "when listing pods after deployment resize") + return podList +} + +// WaitForRecommendationPresent pools VPA object until recommendations are not empty. Returns +// polled vpa object. On timeout returns error. +func WaitForRecommendationPresent(c vpa_clientset.Interface, vpa *vpa_types.VerticalPodAutoscaler) (*vpa_types.VerticalPodAutoscaler, error) { + return WaitForVPAMatch(c, vpa, func(vpa *vpa_types.VerticalPodAutoscaler) bool { + return vpa.Status.Recommendation != nil && len(vpa.Status.Recommendation.ContainerRecommendations) != 0 + }) +} + +// WaitForVPAMatch pools VPA object until match function returns true. Returns +// polled vpa object. On timeout returns error. +func WaitForVPAMatch(c vpa_clientset.Interface, vpa *vpa_types.VerticalPodAutoscaler, match func(vpa *vpa_types.VerticalPodAutoscaler) bool) (*vpa_types.VerticalPodAutoscaler, error) { + var polledVpa *vpa_types.VerticalPodAutoscaler + err := wait.PollUntilContextTimeout(context.Background(), PollInterval, PollTimeout, true, func(ctx context.Context) (done bool, err error) { + polledVpa, err = c.AutoscalingV1().VerticalPodAutoscalers(vpa.Namespace).Get(context.TODO(), vpa.Name, metav1.GetOptions{}) + if err != nil { + return false, err + } + + if match(polledVpa) { + return true, nil + } + + return false, nil + }) + + if err != nil { + return nil, fmt.Errorf("error waiting for recommendation present in %v: %v", vpa.Name, err) + } + return polledVpa, nil +} diff --git a/vertical-pod-autoscaler/e2e/v1/actuation.go b/vertical-pod-autoscaler/e2e/v1/actuation.go index 60f4185b5d..71178315fc 100644 --- a/vertical-pod-autoscaler/e2e/v1/actuation.go +++ b/vertical-pod-autoscaler/e2e/v1/actuation.go @@ -58,17 +58,17 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { ginkgo.It("still applies recommendations on restart when update mode is InPlaceOrRecreate", func() { ginkgo.By("Setting up a hamster deployment") - SetupHamsterDeployment(f, "100m", "100Mi", defaultHamsterReplicas) + SetupHamsterDeployment(f, "100m", "100Mi", utils.DefaultHamsterReplicas) podList, err := GetHamsterPods(f) gomega.Expect(err).NotTo(gomega.HaveOccurred()) podSet := MakePodSet(podList) ginkgo.By("Setting up a VPA CRD in mode InPlaceOrRecreate") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithUpdateMode(vpa_types.UpdateModeInPlaceOrRecreate). WithContainer(containerName). AppendRecommendation( @@ -80,7 +80,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) updatedCPURequest := ParseQuantityOrDie("200m") ginkgo.By(fmt.Sprintf("Waiting for pods to be evicted, hoping it won't happen, sleep for %s", VpaEvictionTimeout.String())) @@ -98,13 +98,13 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { foundUpdated += 1 } } - gomega.Expect(foundUpdated).To(gomega.Equal(defaultHamsterReplicas)) + gomega.Expect(foundUpdated).To(gomega.Equal(utils.DefaultHamsterReplicas)) }) // TODO: add e2e test to verify metrics are getting updated ginkgo.It("applies in-place updates to all containers when update mode is InPlaceOrRecreate", func() { ginkgo.By("Setting up a hamster deployment") - d := NewNHamstersDeployment(f, 2 /*number of containers*/) + d := utils.NewNHamstersDeployment(f, 2 /*number of containers*/) d.Spec.Template.Spec.Containers[0].Resources.Requests = apiv1.ResourceList{ apiv1.ResourceCPU: ParseQuantityOrDie("100m"), apiv1.ResourceMemory: ParseQuantityOrDie("100Mi"), @@ -115,9 +115,9 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { } targetCPU := "200m" targetMemory := "200Mi" - _ = startDeploymentPods(f, d) // 3 replicas - container1Name := GetHamsterContainerNameByIndex(0) - container2Name := GetHamsterContainerNameByIndex(1) + _ = utils.StartDeploymentPods(f, d) // 3 replicas + container1Name := utils.GetHamsterContainerNameByIndex(0) + container2Name := utils.GetHamsterContainerNameByIndex(1) podList, err := GetHamsterPods(f) gomega.Expect(err).NotTo(gomega.HaveOccurred()) @@ -125,7 +125,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(container1Name). WithContainer(container2Name). WithUpdateMode(vpa_types.UpdateModeInPlaceOrRecreate). @@ -145,7 +145,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Checking that resources were modified due to in-place update, not due to evictions") err = WaitForPodsUpdatedWithoutEviction(f, podList) @@ -183,12 +183,12 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { gomega.Expect(err).NotTo(gomega.HaveOccurred()) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) updatedCPU := "999" // infeasible target vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). WithUpdateMode(vpa_types.UpdateModeInPlaceOrRecreate). AppendRecommendation( @@ -200,7 +200,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Waiting for pods to be evicted") err = WaitForPodsEvicted(f, podList) @@ -215,7 +215,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { gomega.Expect(err).NotTo(gomega.HaveOccurred()) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) // we can force deferred resize by setting the target CPU to the allocatable CPU of the node // it will be close enough to the node capacity, such that the kubelet defers instead of marking it infeasible @@ -228,7 +228,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). WithUpdateMode(vpa_types.UpdateModeInPlaceOrRecreate). AppendRecommendation( @@ -240,7 +240,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Waiting for status to be Deferred") gomega.Eventually(func() error { @@ -283,14 +283,14 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { ginkgo.It("stops when pods get pending", func() { ginkgo.By("Setting up a hamster deployment") - d := SetupHamsterDeployment(f, "100m", "100Mi", defaultHamsterReplicas) + d := SetupHamsterDeployment(f, "100m", "100Mi", utils.DefaultHamsterReplicas) ginkgo.By("Setting up a VPA CRD with ridiculous request") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -301,7 +301,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Waiting for pods to be restarted and stuck pending") err := assertPodsPendingForDuration(f.ClientSet, d, 1, 2*time.Minute) @@ -311,18 +311,18 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { ginkgo.It("never applies recommendations when update mode is Off", func() { ginkgo.By("Setting up a hamster deployment") - d := SetupHamsterDeployment(f, "100m", "100Mi", defaultHamsterReplicas) + d := SetupHamsterDeployment(f, "100m", "100Mi", utils.DefaultHamsterReplicas) cpuRequest := getCPURequest(d.Spec.Template.Spec) podList, err := GetHamsterPods(f) gomega.Expect(err).NotTo(gomega.HaveOccurred()) podSet := MakePodSet(podList) ginkgo.By("Setting up a VPA CRD in mode Off") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithUpdateMode(vpa_types.UpdateModeOff). WithContainer(containerName). AppendRecommendation( @@ -334,7 +334,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By(fmt.Sprintf("Waiting for pods to be evicted, hoping it won't happen, sleep for %s", VpaEvictionTimeout.String())) CheckNoPodsEvicted(f, podSet) @@ -350,17 +350,17 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { ginkgo.It("applies recommendations only on restart when update mode is Initial", func() { ginkgo.By("Setting up a hamster deployment") - SetupHamsterDeployment(f, "100m", "100Mi", defaultHamsterReplicas) + SetupHamsterDeployment(f, "100m", "100Mi", utils.DefaultHamsterReplicas) podList, err := GetHamsterPods(f) gomega.Expect(err).NotTo(gomega.HaveOccurred()) podSet := MakePodSet(podList) ginkgo.By("Setting up a VPA CRD in mode Initial") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithUpdateMode(vpa_types.UpdateModeInitial). WithContainer(containerName). AppendRecommendation( @@ -372,7 +372,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) updatedCPURequest := ParseQuantityOrDie("200m") ginkgo.By(fmt.Sprintf("Waiting for pods to be evicted, hoping it won't happen, sleep for %s", VpaEvictionTimeout.String())) @@ -468,11 +468,11 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { pdb := setupPDB(f, "hamster-pdb", 0 /* maxUnavailable */) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -483,7 +483,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By(fmt.Sprintf("Waiting for pods to be evicted, hoping it won't happen, sleep for %s", VpaEvictionTimeout.String())) CheckNoPodsEvicted(f, podSet) @@ -513,14 +513,14 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { d := NewHamsterDeploymentWithResourcesAndLimits(f, ParseQuantityOrDie("100m") /*cpu request*/, ParseQuantityOrDie("200Mi"), /*memory request*/ ParseQuantityOrDie("300m") /*cpu limit*/, ParseQuantityOrDie("400Mi") /*memory limit*/) - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -531,7 +531,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) // Max CPU limit is 300m and ratio is 3., so max request is 100m, while // recommendation is 200m @@ -547,14 +547,14 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { d := NewHamsterDeploymentWithResourcesAndLimits(f, ParseQuantityOrDie("100m") /*cpu request*/, ParseQuantityOrDie("200Mi"), /*memory request*/ ParseQuantityOrDie("300m") /*cpu limit*/, ParseQuantityOrDie("400Mi") /*memory limit*/) - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -565,7 +565,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) // Min CPU from limit range is 100m and ratio is 3. Min applies both to limit and request so min // request is 100m request and 300m limit @@ -583,15 +583,15 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { ParseQuantityOrDie("300m") /*cpu limit*/, ParseQuantityOrDie("400Mi") /*memory limit*/) d.Spec.Template.Spec.Containers = append(d.Spec.Template.Spec.Containers, d.Spec.Template.Spec.Containers[0]) d.Spec.Template.Spec.Containers[1].Name = "hamster2" - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) ginkgo.By("Setting up a VPA CRD") - container1Name := GetHamsterContainerNameByIndex(0) - container2Name := GetHamsterContainerNameByIndex(1) + container1Name := utils.GetHamsterContainerNameByIndex(0) + container2Name := utils.GetHamsterContainerNameByIndex(1) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(container1Name). AppendRecommendation( test.Recommendation(). @@ -610,7 +610,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) // Max CPU limit is 600m per pod, 300m per container and ratio is 3., so max request is 100m, // while recommendation is 200m @@ -629,14 +629,14 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { d.Spec.Template.Spec.Containers = append(d.Spec.Template.Spec.Containers, d.Spec.Template.Spec.Containers[0]) container2Name := "hamster2" d.Spec.Template.Spec.Containers[1].Name = container2Name - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) ginkgo.By("Setting up a VPA CRD") - container1Name := GetHamsterContainerNameByIndex(0) + container1Name := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(container1Name). AppendRecommendation( test.Recommendation(). @@ -655,7 +655,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) // Min CPU from limit range is 200m per pod, 100m per container and ratio is 3. Min applies both // to limit and request so min request is 100m request and 300m limit @@ -696,12 +696,12 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { defer webhookCleanup() ginkgo.By("Setting up a hamster vpa") - container1Name := GetHamsterContainerNameByIndex(0) - container2Name := GetHamsterContainerNameByIndex(1) + container1Name := utils.GetHamsterContainerNameByIndex(0) + container2Name := utils.GetHamsterContainerNameByIndex(1) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(container1Name). AppendRecommendation( test.Recommendation(). @@ -720,12 +720,12 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m"), ParseQuantityOrDie("100Mi")) - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) for _, pod := range podList.Items { observedContainers, ok := pod.GetAnnotations()[annotations.VpaObservedContainersLabel] gomega.Expect(ok).To(gomega.Equal(true)) @@ -760,7 +760,7 @@ func assertPodsPendingForDuration(c clientset.Interface, deployment *appsv1.Depl pendingPods := make(map[string]time.Time) - err := wait.PollUntilContextTimeout(context.Background(), pollInterval, pollTimeout, true, func(ctx context.Context) (done bool, err error) { + err := wait.PollUntilContextTimeout(context.Background(), utils.PollInterval, utils.PollTimeout, true, func(ctx context.Context) (done bool, err error) { currentPodList, err := framework_deployment.GetPodsForDeployment(ctx, c, deployment) if err != nil { return false, err @@ -815,12 +815,12 @@ func assertPodsPendingForDuration(c clientset.Interface, deployment *appsv1.Depl func testEvictsReplicatedPods(f *framework.Framework, controller *autoscaling.CrossVersionObjectReference) { ginkgo.By(fmt.Sprintf("Setting up a hamster %v", controller.Kind)) - setupHamsterController(f, controller.Kind, "100m", "100Mi", defaultHamsterReplicas) + setupHamsterController(f, controller.Kind, "100m", "100Mi", utils.DefaultHamsterReplicas) podList, err := GetHamsterPods(f) gomega.Expect(err).NotTo(gomega.HaveOccurred()) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). @@ -835,7 +835,7 @@ func testEvictsReplicatedPods(f *framework.Framework, controller *autoscaling.Cr GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Waiting for pods to be evicted") err = WaitForPodsEvicted(f, podList) @@ -849,7 +849,7 @@ func testDoesNotEvictSingletonPodByDefault(f *framework.Framework, controller *a gomega.Expect(err).NotTo(gomega.HaveOccurred()) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). @@ -864,7 +864,7 @@ func testDoesNotEvictSingletonPodByDefault(f *framework.Framework, controller *a GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) // No eviction is expected with the default settings of VPA object ginkgo.By(fmt.Sprintf("Waiting for pods to be evicted, hoping it won't happen, sleep for %s", VpaEvictionTimeout.String())) @@ -879,7 +879,7 @@ func testEvictsSingletonPodWhenConfigured(f *framework.Framework, controller *au // Prepare the VPA to allow single-Pod eviction. ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). @@ -895,7 +895,7 @@ func testEvictsSingletonPodWhenConfigured(f *framework.Framework, controller *au GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Waiting for pods to be evicted") err = WaitForPodsEvicted(f, podList) @@ -927,7 +927,7 @@ func setupHamsterController(f *framework.Framework, controllerKind, cpu, memory func setupHamsterReplicationController(f *framework.Framework, cpu, memory string, replicas int32) { hamsterContainer := SetupHamsterContainer(cpu, memory) - rc := framework_rc.ByNameContainer("hamster-rc", replicas, hamsterLabels, hamsterContainer, nil) + rc := framework_rc.ByNameContainer("hamster-rc", replicas, utils.HamsterLabels, hamsterContainer, nil) rc.Namespace = f.Namespace.Name err := testutils.CreateRCWithRetries(f.ClientSet, f.Namespace.Name, rc) @@ -937,7 +937,7 @@ func setupHamsterReplicationController(f *framework.Framework, cpu, memory strin } func waitForRCPodsRunning(f *framework.Framework, rc *apiv1.ReplicationController) error { - return wait.PollUntilContextTimeout(context.Background(), pollInterval, pollTimeout, true, func(ctx context.Context) (done bool, err error) { + return wait.PollUntilContextTimeout(context.Background(), utils.PollInterval, utils.PollTimeout, true, func(ctx context.Context) (done bool, err error) { podList, err := GetHamsterPods(f) if err != nil { framework.Logf("Error listing pods, retrying: %v", err) @@ -957,7 +957,7 @@ func setupHamsterJob(f *framework.Framework, cpu, memory string, replicas int32) job := framework_job.NewTestJob("notTerminate", "hamster-job", apiv1.RestartPolicyOnFailure, replicas, replicas, nil, 10) job.Spec.Template.Spec.Containers[0] = SetupHamsterContainer(cpu, memory) - for label, value := range hamsterLabels { + for label, value := range utils.HamsterLabels { job.Spec.Template.Labels[label] = value } _, err := framework_job.CreateJob(context.TODO(), f.ClientSet, f.Namespace.Name, job) @@ -967,7 +967,7 @@ func setupHamsterJob(f *framework.Framework, cpu, memory string, replicas int32) } func setupHamsterRS(f *framework.Framework, cpu, memory string, replicas int32) { - rs := newReplicaSet("hamster-rs", f.Namespace.Name, replicas, hamsterLabels, "", "") + rs := newReplicaSet("hamster-rs", f.Namespace.Name, replicas, utils.HamsterLabels, "", "") rs.Spec.Template.Spec.Containers[0] = SetupHamsterContainer(cpu, memory) err := createReplicaSetWithRetries(f.ClientSet, f.Namespace.Name, rs) gomega.Expect(err).NotTo(gomega.HaveOccurred()) @@ -977,7 +977,7 @@ func setupHamsterRS(f *framework.Framework, cpu, memory string, replicas int32) func setupHamsterStateful(f *framework.Framework, cpu, memory string, replicas int32) { stateful := framework_ss.NewStatefulSet("hamster-stateful", f.Namespace.Name, - "hamster-service", replicas, nil, nil, hamsterLabels) + "hamster-service", replicas, nil, nil, utils.HamsterLabels) stateful.Spec.Template.Spec.Containers[0] = SetupHamsterContainer(cpu, memory) err := createStatefulSetSetWithRetries(f.ClientSet, f.Namespace.Name, stateful) @@ -994,7 +994,7 @@ func setupPDB(f *framework.Framework, name string, maxUnavailable int) *policyv1 Spec: policyv1.PodDisruptionBudgetSpec{ MaxUnavailable: &maxUnavailableIntstr, Selector: &metav1.LabelSelector{ - MatchLabels: hamsterLabels, + MatchLabels: utils.HamsterLabels, }, }, } diff --git a/vertical-pod-autoscaler/e2e/v1/admission_controller.go b/vertical-pod-autoscaler/e2e/v1/admission_controller.go index 7ace246b09..f6cb2360df 100644 --- a/vertical-pod-autoscaler/e2e/v1/admission_controller.go +++ b/vertical-pod-autoscaler/e2e/v1/admission_controller.go @@ -23,14 +23,12 @@ import ( "strings" "time" - appsv1 "k8s.io/api/apps/v1" - autoscalingv1 "k8s.io/api/autoscaling/v1" apiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/autoscaler/vertical-pod-autoscaler/e2e/utils" vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1" "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/test" "k8s.io/kubernetes/test/e2e/framework" - framework_deployment "k8s.io/kubernetes/test/e2e/framework/deployment" podsecurity "k8s.io/pod-security-admission/api" ginkgo "github.com/onsi/ginkgo/v2" @@ -54,11 +52,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). WithUpdateMode(vpa_types.UpdateModeInPlaceOrRecreate). AppendRecommendation( @@ -70,10 +68,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 100Mi of memory, but admission controller // should change it to recommended 250m CPU and 200Mi of memory. @@ -87,11 +85,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -102,10 +100,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 100Mi of memory, but admission controller // should change it to recommended 250m CPU and 200Mi of memory. @@ -120,11 +118,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: ginkgo.By("Setting up a VPA CRD") removedContainerName := "removed" - container1Name := GetHamsterContainerNameByIndex(0) + container1Name := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(removedContainerName). AppendRecommendation( test.Recommendation(). @@ -143,10 +141,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 100Mi of memory, but admission controller // should change it to recommended 250m CPU and 200Mi of memory. @@ -164,7 +162,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(removedContainerName). AppendRecommendation( test.Recommendation(). @@ -175,10 +173,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 100Mi of memory, but admission controller // should change it to recommended 250m CPU and 200Mi of memory. @@ -189,7 +187,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: }) ginkgo.It("starts pod with recommendation when one container has a recommendation and one other one doesn't", func() { - d := NewNHamstersDeployment(f, 2) + d := utils.NewNHamstersDeployment(f, 2) d.Spec.Template.Spec.Containers[0].Resources.Requests = apiv1.ResourceList{ apiv1.ResourceCPU: ParseQuantityOrDie("100m"), apiv1.ResourceMemory: ParseQuantityOrDie("100Mi"), @@ -200,11 +198,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: } framework.Logf("Created hamster deployment %v", d) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -215,10 +213,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 100Mi of memory, but admission controller // should change it to recommended 250m CPU and 200Mi of memory. @@ -235,12 +233,12 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: InstallLimitRangeWithMax(f, "300m", "1Gi", apiv1.LimitTypeContainer) ginkgo.By("Setting up a VPA CRD") - container1Name := GetHamsterContainerNameByIndex(0) - container2Name := GetHamsterContainerNameByIndex(1) + container1Name := utils.GetHamsterContainerNameByIndex(0) + container2Name := utils.GetHamsterContainerNameByIndex(1) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(container1Name). AppendRecommendation( test.Recommendation(). @@ -259,10 +257,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 100Mi of memory, but admission controller // should change it to recommended 250m CPU and 200Mi of memory. @@ -279,11 +277,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: InstallLimitRangeWithMax(f, "300m", "1Gi", apiv1.LimitTypeContainer) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -294,10 +292,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 100Mi of memory, but admission controller // should change it to recommended 250m CPU and 200Mi of memory. @@ -308,7 +306,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: }) ginkgo.It("starts pod with default request when one container has a recommendation and one other one doesn't when a limit range applies", func() { - d := NewNHamstersDeployment(f, 2) + d := utils.NewNHamstersDeployment(f, 2) InstallLimitRangeWithMax(f, "400m", "1Gi", apiv1.LimitTypePod) d.Spec.Template.Spec.Containers[0].Resources.Requests = apiv1.ResourceList{ @@ -329,11 +327,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: } framework.Logf("Created hamster deployment %v", d) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -344,10 +342,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally both containers in each Pod had 400m CPU (one from // recommendation the other one from request), 600Mi of memory (similarly), @@ -365,11 +363,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -380,10 +378,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) ginkgo.By("Verifying hamster deployment") for i, pod := range podList.Items { @@ -395,7 +393,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: } ginkgo.By("Modifying recommendation.") - PatchVpaRecommendation(f, vpaCRD, &vpa_types.RecommendedPodResources{ + utils.PatchVpaRecommendation(f, vpaCRD, &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{{ ContainerName: "hamster", Target: apiv1.ResourceList{ @@ -414,11 +412,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: d := NewHamsterDeploymentWithGuaranteedResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -429,10 +427,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 100Mi of memory, but admission controller // should change it to 250m CPU and 200Mi of memory. Limits and requests should stay equal. @@ -450,11 +448,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: ParseQuantityOrDie("150m") /*cpu limit*/, ParseQuantityOrDie("200Mi") /*memory limit*/) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -465,10 +463,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 100Mi of memory, but admission controller // should change it to 250m CPU and 200Mi of memory. Limits to request ratio should stay unchanged. @@ -486,11 +484,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: ParseQuantityOrDie("500m") /*cpu limit*/, ParseQuantityOrDie("500Mi") /*memory limit*/) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). WithControlledValues(containerName, vpa_types.ContainerControlledValuesRequestsOnly). AppendRecommendation( @@ -502,10 +500,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 100Mi of memory, but admission controller // should change it to 250m CPU and 200Mi of memory. Limits should stay unchanged. @@ -527,11 +525,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: d := NewHamsterDeploymentWithResourcesAndLimits(f, startCpuRequest, startMemRequest, startCpuLimit, startMemLimit) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -542,7 +540,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) // Max CPU limit is 300m and ratio is 1.5, so max request is 200m, while // recommendation is 250m @@ -551,7 +549,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: InstallLimitRangeWithMax(f, maxCpu.String(), "1Gi", apiv1.LimitTypeContainer) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) ginkgo.By("Verifying hamster deployment") for i, pod := range podList.Items { @@ -585,11 +583,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: ParseQuantityOrDie("150m") /*cpu limit*/, ParseQuantityOrDie("400Mi") /*memory limit*/) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -600,7 +598,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) // Min CPU from limit range is 50m and ratio is 1.5. Min applies to both limit and request so min // request is 50m and min limit is 75 @@ -609,7 +607,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: InstallLimitRangeWithMin(f, "50m", "250Mi", apiv1.LimitTypeContainer) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 200Mi of memory, but admission controller // should change it to 250m CPU and 125Mi of memory, since this is the lowest @@ -634,11 +632,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: d.Spec.Template.Spec.Containers[1].Name = container2Name ginkgo.By("Setting up a VPA CRD") - container1Name := GetHamsterContainerNameByIndex(0) + container1Name := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(container1Name). AppendRecommendation( test.Recommendation(). @@ -657,7 +655,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) // Max CPU limit is 600m for pod, 300 per container and ratio is 1.5, so max request is 200m, // while recommendation is 250m @@ -665,7 +663,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: InstallLimitRangeWithMax(f, "600m", "1Gi", apiv1.LimitTypePod) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 100Mi of memory, but admission controller // should change it to 200m CPU (as this is the recommendation @@ -690,11 +688,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: d.Spec.Template.Spec.Containers[1].Name = container2Name ginkgo.By("Setting up a VPA CRD") - container1Name := GetHamsterContainerNameByIndex(0) + container1Name := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(container1Name). AppendRecommendation( test.Recommendation(). @@ -713,7 +711,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) // Min CPU from limit range is 100m, 50m per pod and ratio is 1.5. Min applies to both limit and // request so min request is 50m and min limit is 75 @@ -722,7 +720,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: InstallLimitRangeWithMin(f, "100m", "500Mi", apiv1.LimitTypePod) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // Originally Pods had 100m CPU, 200Mi of memory, but admission controller // should change it to 250m CPU and 125Mi of memory, since this is the lowest @@ -742,11 +740,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -758,10 +756,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: WithMaxAllowed(containerName, "233m", "150Mi"). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.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 @@ -776,11 +774,11 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). AppendRecommendation( test.Recommendation(). @@ -792,10 +790,10 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: WithMinAllowed(containerName, "90m", "80Mi"). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.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 @@ -810,18 +808,18 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // VPA has no recommendation, so user's request is passed through for _, pod := range podList.Items { @@ -834,18 +832,18 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: d := NewHamsterDeployment(f) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") - podList := startDeploymentPods(f, d) + podList := utils.StartDeploymentPods(f, d) // VPA has no recommendation, deployment has no request specified for _, pod := range podList.Items { @@ -951,59 +949,6 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG: }) }) -func startDeploymentPods(f *framework.Framework, deployment *appsv1.Deployment) *apiv1.PodList { - // Apiserver watch can lag depending on cached object count and apiserver resource usage. - // We assume that watch can lag up to 5 seconds. - const apiserverWatchLag = 5 * time.Second - // In admission controller e2e tests a recommendation is created before deployment. - // Creating deployment with size greater than 0 would create a race between information - // about pods and information about deployment getting to the admission controller. - // Any pods that get processed by AC before it receives information about the deployment - // don't receive recommendation. - // To avoid this create deployment with size 0, then scale it up to the desired size. - desiredPodCount := *deployment.Spec.Replicas - zero := int32(0) - deployment.Spec.Replicas = &zero - c, ns := f.ClientSet, f.Namespace.Name - deployment, err := c.AppsV1().Deployments(ns).Create(context.TODO(), deployment, metav1.CreateOptions{}) - gomega.Expect(err).NotTo(gomega.HaveOccurred(), "when creating deployment with size 0") - - err = framework_deployment.WaitForDeploymentComplete(c, deployment) - gomega.Expect(err).NotTo(gomega.HaveOccurred(), "when waiting for empty deployment to create") - // If admission controller receives pod before controller it will not apply recommendation and test will fail. - // Wait after creating deployment to ensure VPA knows about it, then scale up. - // Normally watch lag is not a problem in terms of correctness: - // - Mode "Auto": created pod without assigned resources will be handled by the eviction loop. - // - Mode "Initial": calculating recommendations takes more than potential ectd lag. - // - Mode "Off": pods are not handled by the admission controller. - // In e2e admission controller tests we want to focus on scenarios without considering watch lag. - // TODO(#2631): Remove sleep when issue is fixed. - time.Sleep(apiserverWatchLag) - - scale := autoscalingv1.Scale{ - ObjectMeta: metav1.ObjectMeta{ - Name: deployment.ObjectMeta.Name, - Namespace: deployment.ObjectMeta.Namespace, - }, - Spec: autoscalingv1.ScaleSpec{ - Replicas: desiredPodCount, - }, - } - afterScale, err := c.AppsV1().Deployments(ns).UpdateScale(context.TODO(), deployment.Name, &scale, metav1.UpdateOptions{}) - gomega.Expect(err).NotTo(gomega.HaveOccurred()) - gomega.Expect(afterScale.Spec.Replicas).To(gomega.Equal(desiredPodCount), fmt.Sprintf("expected %d replicas after scaling", desiredPodCount)) - - // After scaling deployment we need to retrieve current version with updated replicas count. - deployment, err = c.AppsV1().Deployments(ns).Get(context.TODO(), deployment.Name, metav1.GetOptions{}) - gomega.Expect(err).NotTo(gomega.HaveOccurred(), "when getting scaled deployment") - err = framework_deployment.WaitForDeploymentComplete(c, deployment) - gomega.Expect(err).NotTo(gomega.HaveOccurred(), "when waiting for deployment to resize") - - podList, err := framework_deployment.GetPodsForDeployment(context.TODO(), c, deployment) - gomega.Expect(err).NotTo(gomega.HaveOccurred(), "when listing pods after deployment resize") - return podList -} - func waitForVpaWebhookRegistration(f *framework.Framework) { ginkgo.By("Waiting for VPA webhook registration") gomega.Eventually(func() bool { diff --git a/vertical-pod-autoscaler/e2e/v1/common.go b/vertical-pod-autoscaler/e2e/v1/common.go index 7d54a0ffa4..7bc8157f7f 100644 --- a/vertical-pod-autoscaler/e2e/v1/common.go +++ b/vertical-pod-autoscaler/e2e/v1/common.go @@ -26,7 +26,6 @@ import ( ginkgo "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" - autoscaling "k8s.io/api/autoscaling/v1" batchv1 "k8s.io/api/batch/v1" apiv1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -35,6 +34,7 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/autoscaler/vertical-pod-autoscaler/e2e/utils" vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1" vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned" clientset "k8s.io/client-go/kubernetes" @@ -43,13 +43,10 @@ import ( ) const ( - recommenderComponent = "recommender" updateComponent = "updater" admissionControllerComponent = "admission-controller" fullVpaSuite = "full-vpa" actuationSuite = "actuation" - pollInterval = 10 * time.Second - pollTimeout = 15 * time.Minute cronJobsWaitTimeout = 15 * time.Minute // VpaEvictionTimeout is a timeout for VPA to restart a pod if there are no // mechanisms blocking it (for example PDB). @@ -58,63 +55,28 @@ const ( // pod, if there are no mechanisms blocking it. VpaInPlaceTimeout = 2 * time.Minute - defaultHamsterReplicas = int32(3) - defaultHamsterBackoffLimit = int32(10) - // VpaNamespace is the default namespace that holds the all the VPA components. VpaNamespace = "kube-system" ) -var hamsterTargetRef = &autoscaling.CrossVersionObjectReference{ - APIVersion: "apps/v1", - Kind: "Deployment", - Name: "hamster-deployment", -} - -var hamsterLabels = map[string]string{"app": "hamster"} - -// SIGDescribe adds sig-autoscaling tag to test description. -// Takes args that are passed to ginkgo.Describe. -func SIGDescribe(scenario, name string, args ...interface{}) bool { - full := fmt.Sprintf("[sig-autoscaling] [VPA] [%s] [v1] %s", scenario, name) - return ginkgo.Describe(full, args...) -} - -// RecommenderE2eDescribe describes a VPA recommender e2e test. -func RecommenderE2eDescribe(name string, args ...interface{}) bool { - return SIGDescribe(recommenderComponent, name, args...) -} - // UpdaterE2eDescribe describes a VPA updater e2e test. func UpdaterE2eDescribe(name string, args ...interface{}) bool { - return SIGDescribe(updateComponent, name, args...) + return utils.SIGDescribe(updateComponent, name, args...) } // AdmissionControllerE2eDescribe describes a VPA admission controller e2e test. func AdmissionControllerE2eDescribe(name string, args ...interface{}) bool { - return SIGDescribe(admissionControllerComponent, name, args...) + return utils.SIGDescribe(admissionControllerComponent, name, args...) } // FullVpaE2eDescribe describes a VPA full stack e2e test. func FullVpaE2eDescribe(name string, args ...interface{}) bool { - return SIGDescribe(fullVpaSuite, name, args...) + return utils.SIGDescribe(fullVpaSuite, name, args...) } // ActuationSuiteE2eDescribe describes a VPA actuation e2e test. func ActuationSuiteE2eDescribe(name string, args ...interface{}) bool { - return SIGDescribe(actuationSuite, name, args...) -} - -// GetHamsterContainerNameByIndex returns name of i-th hamster container. -func GetHamsterContainerNameByIndex(i int) string { - switch { - case i < 0: - panic("negative index") - case i == 0: - return "hamster" - default: - return fmt.Sprintf("hamster%d", i+1) - } + return utils.SIGDescribe(actuationSuite, name, args...) } // SetupHamsterDeployment creates and installs a simple hamster deployment @@ -134,31 +96,7 @@ func SetupHamsterDeployment(f *framework.Framework, cpu, memory string, replicas // NewHamsterDeployment creates a simple hamster deployment for e2e test purposes. func NewHamsterDeployment(f *framework.Framework) *appsv1.Deployment { - return NewNHamstersDeployment(f, 1) -} - -// NewNHamstersDeployment creates a simple hamster deployment with n containers -// for e2e test purposes. -func NewNHamstersDeployment(f *framework.Framework, n int) *appsv1.Deployment { - if n < 1 { - panic("container count should be greater than 0") - } - d := framework_deployment.NewDeployment( - "hamster-deployment", /*deploymentName*/ - defaultHamsterReplicas, /*replicas*/ - hamsterLabels, /*podLabels*/ - GetHamsterContainerNameByIndex(0), /*imageName*/ - "registry.k8s.io/ubuntu-slim:0.14", /*image*/ - appsv1.RollingUpdateDeploymentStrategyType, /*strategyType*/ - ) - 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"} - for i := 1; i < n; i++ { - d.Spec.Template.Spec.Containers = append(d.Spec.Template.Spec.Containers, d.Spec.Template.Spec.Containers[0]) - d.Spec.Template.Spec.Containers[i].Name = GetHamsterContainerNameByIndex(i) - } - return d + return utils.NewNHamstersDeployment(f, 1) } // NewHamsterDeploymentWithResources creates a simple hamster deployment with specific @@ -203,16 +141,16 @@ func getPodSelectorExcludingDonePodsOrDie() string { return selector.String() } -// GetHamsterPods returns running hamster pods (matched by hamsterLabels) +// GetHamsterPods returns running hamster pods (matched by utils.HamsterLabels) func GetHamsterPods(f *framework.Framework) (*apiv1.PodList, error) { - label := labels.SelectorFromSet(labels.Set(hamsterLabels)) + label := labels.SelectorFromSet(labels.Set(utils.HamsterLabels)) options := metav1.ListOptions{LabelSelector: label.String(), FieldSelector: getPodSelectorExcludingDonePodsOrDie()} return f.ClientSet.CoreV1().Pods(f.Namespace.Name).List(context.TODO(), options) } // NewTestCronJob returns a CronJob for test purposes. func NewTestCronJob(name, schedule string, replicas int32) *batchv1.CronJob { - backoffLimit := defaultHamsterBackoffLimit + backoffLimit := utils.DefaultHamsterBackoffLimit sj := &batchv1.CronJob{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -266,7 +204,7 @@ func getCronJob(c clientset.Interface, ns, name string) (*batchv1.CronJob, error func SetupHamsterCronJob(f *framework.Framework, schedule, cpu, memory string, replicas int32) { cronJob := NewTestCronJob("hamster-cronjob", schedule, replicas) cronJob.Spec.JobTemplate.Spec.Template.Spec.Containers = []apiv1.Container{SetupHamsterContainer(cpu, memory)} - for label, value := range hamsterLabels { + for label, value := range utils.HamsterLabels { cronJob.Spec.JobTemplate.Spec.Template.Labels[label] = value } cronJob, err := createCronJob(f.ClientSet, f.Namespace.Name, cronJob) @@ -294,45 +232,9 @@ func SetupHamsterContainer(cpu, memory string) apiv1.Container { } } -type patchRecord struct { - Op string `json:"op,inline"` - Path string `json:"path,inline"` - Value interface{} `json:"value"` -} - -func getVpaClientSet(f *framework.Framework) vpa_clientset.Interface { - config, err := framework.LoadConfig() - gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error loading framework") - return vpa_clientset.NewForConfigOrDie(config) -} - -// InstallVPA installs a VPA object in the test cluster. -func InstallVPA(f *framework.Framework, vpa *vpa_types.VerticalPodAutoscaler) { - vpaClientSet := getVpaClientSet(f) - _, err := vpaClientSet.AutoscalingV1().VerticalPodAutoscalers(f.Namespace.Name).Create(context.TODO(), vpa, metav1.CreateOptions{}) - gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error creating VPA") - // apiserver ignore status in vpa create, so need to update status - if !isStatusEmpty(&vpa.Status) { - if vpa.Status.Recommendation != nil { - PatchVpaRecommendation(f, vpa, vpa.Status.Recommendation) - } - } -} - -func isStatusEmpty(status *vpa_types.VerticalPodAutoscalerStatus) bool { - if status == nil { - return true - } - - if len(status.Conditions) == 0 && status.Recommendation == nil { - return true - } - return false -} - // InstallRawVPA installs a VPA object passed in as raw json in the test cluster. func InstallRawVPA(f *framework.Framework, obj interface{}) error { - vpaClientSet := getVpaClientSet(f) + vpaClientSet := utils.GetVpaClientSet(f) err := vpaClientSet.AutoscalingV1().RESTClient().Post(). Namespace(f.Namespace.Name). Resource("verticalpodautoscalers"). @@ -341,24 +243,9 @@ func InstallRawVPA(f *framework.Framework, obj interface{}) error { return err.Error() } -// PatchVpaRecommendation installs a new recommendation for VPA object. -func PatchVpaRecommendation(f *framework.Framework, vpa *vpa_types.VerticalPodAutoscaler, - recommendation *vpa_types.RecommendedPodResources) { - newStatus := vpa.Status.DeepCopy() - newStatus.Recommendation = recommendation - bytes, err := json.Marshal([]patchRecord{{ - Op: "replace", - Path: "/status", - Value: *newStatus, - }}) - gomega.Expect(err).NotTo(gomega.HaveOccurred()) - _, err = getVpaClientSet(f).AutoscalingV1().VerticalPodAutoscalers(f.Namespace.Name).Patch(context.TODO(), vpa.Name, types.JSONPatchType, bytes, metav1.PatchOptions{}, "status") - gomega.Expect(err).NotTo(gomega.HaveOccurred(), "Failed to patch VPA.") -} - // AnnotatePod adds annotation for an existing pod. func AnnotatePod(f *framework.Framework, podName, annotationName, annotationValue string) { - bytes, err := json.Marshal([]patchRecord{{ + bytes, err := json.Marshal([]utils.PatchRecord{{ Op: "add", Path: fmt.Sprintf("/metadata/annotations/%v", annotationName), Value: annotationValue, @@ -395,7 +282,7 @@ func MakePodSet(pods *apiv1.PodList) PodSet { func WaitForPodsRestarted(f *framework.Framework, podList *apiv1.PodList) error { initialPodSet := MakePodSet(podList) - return wait.PollUntilContextTimeout(context.Background(), pollInterval, pollTimeout, true, func(ctx context.Context) (done bool, err error) { + return wait.PollUntilContextTimeout(context.Background(), utils.PollInterval, utils.PollTimeout, true, func(ctx context.Context) (done bool, err error) { currentPodList, err := GetHamsterPods(f) if err != nil { return false, err @@ -409,7 +296,7 @@ func WaitForPodsRestarted(f *framework.Framework, podList *apiv1.PodList) error func WaitForPodsEvicted(f *framework.Framework, podList *apiv1.PodList) error { initialPodSet := MakePodSet(podList) - return wait.PollUntilContextTimeout(context.Background(), pollInterval, pollTimeout, true, func(ctx context.Context) (done bool, err error) { + return wait.PollUntilContextTimeout(context.Background(), utils.PollInterval, utils.PollTimeout, true, func(ctx context.Context) (done bool, err error) { currentPodList, err := GetHamsterPods(f) if err != nil { return false, err @@ -459,41 +346,10 @@ func CheckNoPodsEvicted(f *framework.Framework, initialPodSet PodSet) { gomega.Expect(restarted).To(gomega.Equal(0), "there should be no pod evictions") } -// WaitForVPAMatch pools VPA object until match function returns true. Returns -// polled vpa object. On timeout returns error. -func WaitForVPAMatch(c vpa_clientset.Interface, vpa *vpa_types.VerticalPodAutoscaler, match func(vpa *vpa_types.VerticalPodAutoscaler) bool) (*vpa_types.VerticalPodAutoscaler, error) { - var polledVpa *vpa_types.VerticalPodAutoscaler - err := wait.PollUntilContextTimeout(context.Background(), pollInterval, pollTimeout, true, func(ctx context.Context) (done bool, err error) { - polledVpa, err = c.AutoscalingV1().VerticalPodAutoscalers(vpa.Namespace).Get(context.TODO(), vpa.Name, metav1.GetOptions{}) - if err != nil { - return false, err - } - - if match(polledVpa) { - return true, nil - } - - return false, nil - }) - - if err != nil { - return nil, fmt.Errorf("error waiting for recommendation present in %v: %v", vpa.Name, err) - } - return polledVpa, nil -} - -// WaitForRecommendationPresent pools VPA object until recommendations are not empty. Returns -// polled vpa object. On timeout returns error. -func WaitForRecommendationPresent(c vpa_clientset.Interface, vpa *vpa_types.VerticalPodAutoscaler) (*vpa_types.VerticalPodAutoscaler, error) { - return WaitForVPAMatch(c, vpa, func(vpa *vpa_types.VerticalPodAutoscaler) bool { - return vpa.Status.Recommendation != nil && len(vpa.Status.Recommendation.ContainerRecommendations) != 0 - }) -} - // WaitForUncappedCPURecommendationAbove pools VPA object until uncapped recommendation is above specified value. // Returns polled VPA object. On timeout returns error. func WaitForUncappedCPURecommendationAbove(c vpa_clientset.Interface, vpa *vpa_types.VerticalPodAutoscaler, minMilliCPU int64) (*vpa_types.VerticalPodAutoscaler, error) { - return WaitForVPAMatch(c, vpa, func(vpa *vpa_types.VerticalPodAutoscaler) bool { + return utils.WaitForVPAMatch(c, vpa, func(vpa *vpa_types.VerticalPodAutoscaler) bool { if vpa.Status.Recommendation == nil || len(vpa.Status.Recommendation.ContainerRecommendations) == 0 { return false } @@ -565,7 +421,7 @@ func InstallLimitRangeWithMin(f *framework.Framework, minCpuLimit, minMemoryLimi // TODO: Use events to track in-place resizes instead of polling when ready: https://github.com/kubernetes/kubernetes/issues/127172 func WaitForPodsUpdatedWithoutEviction(f *framework.Framework, initialPods *apiv1.PodList) error { framework.Logf("waiting for at least one pod to be updated without eviction") - err := wait.PollUntilContextTimeout(context.TODO(), pollInterval, VpaInPlaceTimeout, false, func(context.Context) (bool, error) { + err := wait.PollUntilContextTimeout(context.TODO(), utils.PollInterval, VpaInPlaceTimeout, false, func(context.Context) (bool, error) { podList, err := GetHamsterPods(f) if err != nil { return false, err diff --git a/vertical-pod-autoscaler/e2e/v1/full_vpa.go b/vertical-pod-autoscaler/e2e/v1/full_vpa.go index d03f95779a..1d4e26a2e4 100644 --- a/vertical-pod-autoscaler/e2e/v1/full_vpa.go +++ b/vertical-pod-autoscaler/e2e/v1/full_vpa.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/autoscaler/vertical-pod-autoscaler/e2e/utils" vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1" "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/test" "k8s.io/kubernetes/test/e2e/framework" @@ -82,7 +83,7 @@ var _ = FullVpaE2eDescribe("Pods under VPA", func() { Name: "hamster", } - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). @@ -98,20 +99,20 @@ var _ = FullVpaE2eDescribe("Pods under VPA", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) }) ginkgo.It("have cpu requests growing with usage", func() { // initial CPU usage is low so a minimal recommendation is expected err := waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, ParseQuantityOrDie(minimalCPULowerBound), ParseQuantityOrDie(minimalCPUUpperBound)) gomega.Expect(err).NotTo(gomega.HaveOccurred()) // consume more CPU to get a higher recommendation rc.ConsumeCPU(600 * replicas) err = waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, ParseQuantityOrDie("500m"), ParseQuantityOrDie("1300m")) gomega.Expect(err).NotTo(gomega.HaveOccurred()) }) @@ -119,7 +120,7 @@ var _ = FullVpaE2eDescribe("Pods under VPA", func() { ginkgo.It("have memory requests growing with usage", func() { // initial memory usage is low so a minimal recommendation is expected err := waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceMemory, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceMemory, ParseQuantityOrDie(minimalMemoryLowerBound), ParseQuantityOrDie(minimalMemoryUpperBound)) gomega.Expect(err).NotTo(gomega.HaveOccurred()) @@ -127,7 +128,7 @@ var _ = FullVpaE2eDescribe("Pods under VPA", func() { // NOTE: large range given due to unpredictability of actual memory usage rc.ConsumeMem(1024 * replicas) err = waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceMemory, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceMemory, ParseQuantityOrDie("900Mi"), ParseQuantityOrDie("4000Mi")) gomega.Expect(err).NotTo(gomega.HaveOccurred()) }) @@ -154,7 +155,7 @@ var _ = FullVpaE2eDescribe("Pods under VPA", func() { Name: "hamster", } - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). @@ -169,20 +170,20 @@ var _ = FullVpaE2eDescribe("Pods under VPA", func() { GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) }) ginkgo.It("have cpu requests growing with usage", func() { // initial CPU usage is low so a minimal recommendation is expected err := waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, ParseQuantityOrDie(minimalCPULowerBound), ParseQuantityOrDie(minimalCPUUpperBound)) gomega.Expect(err).NotTo(gomega.HaveOccurred()) // consume more CPU to get a higher recommendation rc.ConsumeCPU(600 * replicas) err = waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, ParseQuantityOrDie("500m"), ParseQuantityOrDie("1300m")) gomega.Expect(err).NotTo(gomega.HaveOccurred()) }) @@ -190,7 +191,7 @@ var _ = FullVpaE2eDescribe("Pods under VPA", func() { ginkgo.It("have memory requests growing with usage", func() { // initial memory usage is low so a minimal recommendation is expected err := waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceMemory, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceMemory, ParseQuantityOrDie(minimalMemoryLowerBound), ParseQuantityOrDie(minimalMemoryUpperBound)) gomega.Expect(err).NotTo(gomega.HaveOccurred()) @@ -198,7 +199,7 @@ var _ = FullVpaE2eDescribe("Pods under VPA", func() { // NOTE: large range given due to unpredictability of actual memory usage rc.ConsumeMem(1024 * replicas) err = waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceMemory, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceMemory, ParseQuantityOrDie("900Mi"), ParseQuantityOrDie("4000Mi")) gomega.Expect(err).NotTo(gomega.HaveOccurred()) }) @@ -240,7 +241,7 @@ var _ = FullVpaE2eDescribe("Pods under VPA with default recommender explicitly c Name: "hamster", } - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). @@ -255,21 +256,21 @@ var _ = FullVpaE2eDescribe("Pods under VPA with default recommender explicitly c GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) }) ginkgo.It("have cpu requests growing with usage", func() { // initial CPU usage is low so a minimal recommendation is expected err := waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, ParseQuantityOrDie(minimalCPULowerBound), ParseQuantityOrDie(minimalCPUUpperBound)) gomega.Expect(err).NotTo(gomega.HaveOccurred()) // consume more CPU to get a higher recommendation rc.ConsumeCPU(600 * replicas) err = waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, ParseQuantityOrDie("500m"), ParseQuantityOrDie("1300m")) gomega.Expect(err).NotTo(gomega.HaveOccurred()) }) @@ -310,7 +311,7 @@ var _ = FullVpaE2eDescribe("Pods under VPA with non-recognized recommender expli Name: "hamster", } - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithRecommender("non-recognized"). @@ -326,20 +327,20 @@ var _ = FullVpaE2eDescribe("Pods under VPA with non-recognized recommender expli GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) }) ginkgo.It("deployment not updated by non-recognized recommender", func() { err := waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, ParseQuantityOrDie(minimalCPULowerBound), ParseQuantityOrDie(minimalCPUUpperBound)) gomega.Expect(err).NotTo(gomega.HaveOccurred()) // consume more CPU to get a higher recommendation rc.ConsumeCPU(600 * replicas) err = waitForResourceRequestInRangeInPods( - f, pollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, + f, utils.PollTimeout, metav1.ListOptions{LabelSelector: "name=hamster"}, apiv1.ResourceCPU, ParseQuantityOrDie("500m"), ParseQuantityOrDie("1000m")) gomega.Expect(err).To(gomega.HaveOccurred()) }) @@ -367,7 +368,7 @@ var _ = FullVpaE2eDescribe("OOMing pods under VPA", func() { Name: "hamster", } - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). @@ -375,7 +376,7 @@ var _ = FullVpaE2eDescribe("OOMing pods under VPA", func() { WithContainer(containerName). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) }) ginkgo.It("have memory requests growing with OOMs", func() { @@ -391,7 +392,7 @@ var _ = FullVpaE2eDescribe("OOMing pods under VPA", func() { }) func waitForPodsMatch(f *framework.Framework, timeout time.Duration, listOptions metav1.ListOptions, matcher func(pod apiv1.Pod) bool) error { - return wait.PollUntilContextTimeout(context.Background(), pollInterval, timeout, true, func(ctx context.Context) (done bool, err error) { + return wait.PollUntilContextTimeout(context.Background(), utils.PollInterval, timeout, true, func(ctx context.Context) (done bool, err error) { ns := f.Namespace.Name c := f.ClientSet diff --git a/vertical-pod-autoscaler/e2e/v1/recommender.go b/vertical-pod-autoscaler/e2e/v1/recommender.go index 694f257b3c..d97689fa81 100644 --- a/vertical-pod-autoscaler/e2e/v1/recommender.go +++ b/vertical-pod-autoscaler/e2e/v1/recommender.go @@ -26,6 +26,7 @@ import ( apiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" + "k8s.io/autoscaler/vertical-pod-autoscaler/e2e/utils" vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1" vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned" "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/test" @@ -119,13 +120,13 @@ func getVpaObserver(vpaClientSet vpa_clientset.Interface, namespace string) *obs return &vpaObserver } -var _ = RecommenderE2eDescribe("Checkpoints", func() { +var _ = utils.RecommenderE2eDescribe("Checkpoints", func() { f := framework.NewDefaultFramework("vertical-pod-autoscaling") f.NamespacePodSecurityEnforceLevel = podsecurity.LevelBaseline ginkgo.It("with missing VPA objects are garbage collected", func() { ns := f.Namespace.Name - vpaClientSet := getVpaClientSet(f) + vpaClientSet := utils.GetVpaClientSet(f) checkpoint := vpa_types.VerticalPodAutoscalerCheckpoint{ ObjectMeta: metav1.ObjectMeta{ @@ -159,15 +160,15 @@ var _ = RecommenderE2eDescribe("Checkpoints", func() { }) }) -var _ = RecommenderE2eDescribe("VPA CRD object", func() { +var _ = utils.RecommenderE2eDescribe("VPA CRD object", func() { f := framework.NewDefaultFramework("vertical-pod-autoscaling") f.NamespacePodSecurityEnforceLevel = podsecurity.LevelBaseline ginkgo.It("serves recommendation for CronJob", func() { ginkgo.By("Setting up hamster CronJob") - SetupHamsterCronJob(f, "*/5 * * * *", "100m", "100Mi", defaultHamsterReplicas) + SetupHamsterCronJob(f, "*/5 * * * *", "100m", "100Mi", utils.DefaultHamsterReplicas) - vpaClientSet := getVpaClientSet(f) + vpaClientSet := utils.GetVpaClientSet(f) ginkgo.By("Setting up VPA") targetRef := &autoscaling.CrossVersionObjectReference{ @@ -176,7 +177,7 @@ var _ = RecommenderE2eDescribe("VPA CRD object", func() { Name: "hamster-cronjob", } - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). @@ -184,15 +185,15 @@ var _ = RecommenderE2eDescribe("VPA CRD object", func() { WithContainer(containerName). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Waiting for recommendation to be filled") - _, err := WaitForRecommendationPresent(vpaClientSet, vpaCRD) + _, err := utils.WaitForRecommendationPresent(vpaClientSet, vpaCRD) gomega.Expect(err).NotTo(gomega.HaveOccurred()) }) }) -var _ = RecommenderE2eDescribe("VPA CRD object", func() { +var _ = utils.RecommenderE2eDescribe("VPA CRD object", func() { f := framework.NewDefaultFramework("vertical-pod-autoscaling") f.NamespacePodSecurityEnforceLevel = podsecurity.LevelBaseline @@ -211,22 +212,22 @@ var _ = RecommenderE2eDescribe("VPA CRD object", func() { ) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD = test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) - vpaClientSet = getVpaClientSet(f) + vpaClientSet = utils.GetVpaClientSet(f) }) ginkgo.It("serves recommendation", func() { ginkgo.By("Waiting for recommendation to be filled") - _, err := WaitForRecommendationPresent(vpaClientSet, vpaCRD) + _, err := utils.WaitForRecommendationPresent(vpaClientSet, vpaCRD) gomega.Expect(err).NotTo(gomega.HaveOccurred()) }) @@ -235,7 +236,7 @@ var _ = RecommenderE2eDescribe("VPA CRD object", func() { o := getVpaObserver(vpaClientSet, f.Namespace.Name) ginkgo.By("Waiting for recommendation to be filled") - _, err := WaitForRecommendationPresent(vpaClientSet, vpaCRD) + _, err := utils.WaitForRecommendationPresent(vpaClientSet, vpaCRD) gomega.Expect(err).NotTo(gomega.HaveOccurred()) ginkgo.By("Drain diffs") out: @@ -270,7 +271,7 @@ var _ = RecommenderE2eDescribe("VPA CRD object", func() { }) }) -var _ = RecommenderE2eDescribe("VPA CRD object", func() { +var _ = utils.RecommenderE2eDescribe("VPA CRD object", func() { f := framework.NewDefaultFramework("vertical-pod-autoscaling") f.NamespacePodSecurityEnforceLevel = podsecurity.LevelBaseline @@ -287,26 +288,26 @@ var _ = RecommenderE2eDescribe("VPA CRD object", func() { 1, /* number of replicas */ ) - vpaClientSet = getVpaClientSet(f) + vpaClientSet = utils.GetVpaClientSet(f) }) ginkgo.It("respects min allowed recommendation", func() { const minMilliCpu = 10000 ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD2 := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). WithMinAllowed(containerName, "10000", ""). Get() - InstallVPA(f, vpaCRD2) + utils.InstallVPA(f, vpaCRD2) vpaCRD := vpaCRD2 ginkgo.By("Waiting for recommendation to be filled") - vpa, err := WaitForRecommendationPresent(vpaClientSet, vpaCRD) + vpa, err := utils.WaitForRecommendationPresent(vpaClientSet, vpaCRD) gomega.Expect(err).NotTo(gomega.HaveOccurred()) gomega.Expect(vpa.Status.Recommendation.ContainerRecommendations).Should(gomega.HaveLen(1)) cpu := getMilliCpu(vpa.Status.Recommendation.ContainerRecommendations[0].Target) @@ -320,16 +321,16 @@ var _ = RecommenderE2eDescribe("VPA CRD object", func() { ginkgo.It("respects max allowed recommendation", func() { const maxMilliCpu = 1 ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(containerName). WithMaxAllowed(containerName, "1m", ""). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Waiting for recommendation to be filled") vpa, err := WaitForUncappedCPURecommendationAbove(vpaClientSet, vpaCRD, maxMilliCpu) @@ -347,67 +348,67 @@ func getMilliCpu(resources apiv1.ResourceList) int64 { return cpu.MilliValue() } -var _ = RecommenderE2eDescribe("VPA CRD object", func() { +var _ = utils.RecommenderE2eDescribe("VPA CRD object", func() { f := framework.NewDefaultFramework("vertical-pod-autoscaling") f.NamespacePodSecurityEnforceLevel = podsecurity.LevelBaseline var vpaClientSet vpa_clientset.Interface ginkgo.BeforeEach(func() { - vpaClientSet = getVpaClientSet(f) + vpaClientSet = utils.GetVpaClientSet(f) }) ginkgo.It("with no containers opted out all containers get recommendations", func() { ginkgo.By("Setting up a hamster deployment") - d := NewNHamstersDeployment(f, 2 /*number of containers*/) - _ = startDeploymentPods(f, d) + d := utils.NewNHamstersDeployment(f, 2 /*number of containers*/) + _ = utils.StartDeploymentPods(f, d) ginkgo.By("Setting up VPA CRD") - container1Name := GetHamsterContainerNameByIndex(0) - container2Name := GetHamsterContainerNameByIndex(1) + container1Name := utils.GetHamsterContainerNameByIndex(0) + container2Name := utils.GetHamsterContainerNameByIndex(1) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(container1Name). WithContainer(container2Name). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Waiting for recommendation to be filled for both containers") - vpa, err := WaitForRecommendationPresent(vpaClientSet, vpaCRD) + vpa, err := utils.WaitForRecommendationPresent(vpaClientSet, vpaCRD) gomega.Expect(err).NotTo(gomega.HaveOccurred()) gomega.Expect(vpa.Status.Recommendation.ContainerRecommendations).Should(gomega.HaveLen(2)) }) ginkgo.It("only containers not-opted-out get recommendations", func() { ginkgo.By("Setting up a hamster deployment") - d := NewNHamstersDeployment(f, 2 /*number of containers*/) - _ = startDeploymentPods(f, d) + d := utils.NewNHamstersDeployment(f, 2 /*number of containers*/) + _ = utils.StartDeploymentPods(f, d) ginkgo.By("Setting up VPA CRD") - container1Name := GetHamsterContainerNameByIndex(0) - container2Name := GetHamsterContainerNameByIndex(1) + container1Name := utils.GetHamsterContainerNameByIndex(0) + container2Name := utils.GetHamsterContainerNameByIndex(1) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). - WithTargetRef(hamsterTargetRef). + WithTargetRef(utils.HamsterTargetRef). WithContainer(container1Name). WithScalingMode(container1Name, vpa_types.ContainerScalingModeOff). WithContainer(container2Name). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) ginkgo.By("Waiting for recommendation to be filled for just one container") - vpa, err := WaitForRecommendationPresent(vpaClientSet, vpaCRD) + vpa, err := utils.WaitForRecommendationPresent(vpaClientSet, vpaCRD) gomega.Expect(err).NotTo(gomega.HaveOccurred()) errMsg := fmt.Sprintf("%s container has recommendations turned off. We expect expect only recommendations for %s", - GetHamsterContainerNameByIndex(0), - GetHamsterContainerNameByIndex(1)) + utils.GetHamsterContainerNameByIndex(0), + utils.GetHamsterContainerNameByIndex(1)) gomega.Expect(vpa.Status.Recommendation.ContainerRecommendations).Should(gomega.HaveLen(1), errMsg) - gomega.Expect(vpa.Status.Recommendation.ContainerRecommendations[0].ContainerName).To(gomega.Equal(GetHamsterContainerNameByIndex(1)), errMsg) + gomega.Expect(vpa.Status.Recommendation.ContainerRecommendations[0].ContainerName).To(gomega.Equal(utils.GetHamsterContainerNameByIndex(1)), errMsg) }) }) diff --git a/vertical-pod-autoscaler/e2e/v1/updater.go b/vertical-pod-autoscaler/e2e/v1/updater.go index 09ed0c0fb7..8274f48a7a 100644 --- a/vertical-pod-autoscaler/e2e/v1/updater.go +++ b/vertical-pod-autoscaler/e2e/v1/updater.go @@ -24,6 +24,7 @@ import ( autoscaling "k8s.io/api/autoscaling/v1" apiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/autoscaler/vertical-pod-autoscaler/e2e/utils" vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1" "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/status" "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/test" @@ -217,12 +218,12 @@ func setupPodsForEviction(f *framework.Framework, hamsterCPU, hamsterMemory stri Name: "hamster-deployment", } ginkgo.By(fmt.Sprintf("Setting up a hamster %v", controller.Kind)) - setupHamsterController(f, controller.Kind, hamsterCPU, hamsterMemory, defaultHamsterReplicas) + setupHamsterController(f, controller.Kind, hamsterCPU, hamsterMemory, utils.DefaultHamsterReplicas) podList, err := GetHamsterPods(f) gomega.Expect(err).NotTo(gomega.HaveOccurred()) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaCRD := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). @@ -239,7 +240,7 @@ func setupPodsForEviction(f *framework.Framework, hamsterCPU, hamsterMemory stri GetContainerResources()). Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) return podList } @@ -259,12 +260,12 @@ func setupPodsForInPlace(f *framework.Framework, hamsterCPU, hamsterMemory strin Name: "hamster-deployment", } ginkgo.By(fmt.Sprintf("Setting up a hamster %v", controller.Kind)) - setupHamsterController(f, controller.Kind, hamsterCPU, hamsterMemory, defaultHamsterReplicas) + setupHamsterController(f, controller.Kind, hamsterCPU, hamsterMemory, utils.DefaultHamsterReplicas) podList, err := GetHamsterPods(f) gomega.Expect(err).NotTo(gomega.HaveOccurred()) ginkgo.By("Setting up a VPA CRD") - containerName := GetHamsterContainerNameByIndex(0) + containerName := utils.GetHamsterContainerNameByIndex(0) vpaBuilder := test.VerticalPodAutoscaler(). WithName("hamster-vpa"). WithNamespace(f.Namespace.Name). @@ -284,7 +285,7 @@ func setupPodsForInPlace(f *framework.Framework, hamsterCPU, hamsterMemory strin } vpaCRD := vpaBuilder.Get() - InstallVPA(f, vpaCRD) + utils.InstallVPA(f, vpaCRD) return podList } diff --git a/vertical-pod-autoscaler/hack/local-cluster.md b/vertical-pod-autoscaler/hack/local-cluster.md index 5d03c38f61..6264e68c41 100644 --- a/vertical-pod-autoscaler/hack/local-cluster.md +++ b/vertical-pod-autoscaler/hack/local-cluster.md @@ -34,3 +34,7 @@ The local test cases support running the `recommender` with external metrics. T additional permissions we don't want to automatically enable for all customers via the configuration given in `deploy/vpa-rbac.yaml`. The scripts use a context diff `hack/e2e/vpa-rbac.diff` to enable those permission when running locally. + +# Quick Integration Tests + +`run-integration-locally.sh` is a quicker way to integration test compared to `run-e2e-locally.sh`. Only used for simple tests. diff --git a/vertical-pod-autoscaler/hack/run-integration-locally.sh b/vertical-pod-autoscaler/hack/run-integration-locally.sh new file mode 100755 index 0000000000..695d827112 --- /dev/null +++ b/vertical-pod-autoscaler/hack/run-integration-locally.sh @@ -0,0 +1,131 @@ +#!/bin/bash + +# Copyright 2025 The Kubernetes Authors. +# +# 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. + +set -o nounset +set -o pipefail + +BASE_NAME=$(basename $0) +SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/.. +source "${SCRIPT_ROOT}/hack/lib/util.sh" + +ARCH=$(kube::util::host_arch) + +function print_help { + echo "ERROR! Usage: $BASE_NAME " + echo " should be one of:" + echo " - recommender" +} + +if [ $# -eq 0 ]; then + print_help + exit 1 +fi + +if [ $# -gt 1 ]; then + print_help + exit 1 +fi + +SUITE=$1 +REQUIRED_COMMANDS=" +docker +go +kind +kubectl +make +" + +for i in $REQUIRED_COMMANDS; do + if ! command -v $i > /dev/null 2>&1 + then + echo "$i could not be found, please ensure it is installed" + echo + echo "The following commands are required to run these tests:" + echo $REQUIRED_COMMANDS + exit 1; + fi +done + +if ! docker ps >/dev/null 2>&1 +then + echo "docker isn't running" + echo + echo "Please ensure that docker is running" + exit 1 +fi + +case ${SUITE} in + recommender) + COMPONENTS="${SUITE}" + ;; + *) + print_help + exit 1 + ;; +esac + +echo "Deleting KIND cluster 'kind'." +kind delete cluster -n kind -q + +echo "Creating KIND cluster 'kind'" +KIND_VERSION="kindest/node:v1.33.0@sha256:02f73d6ae3f11ad5d543f16736a2cb2a63a300ad60e81dac22099b0b04784a4e" +if ! kind create cluster --image=${KIND_VERSION}; then + echo "Failed to create KIND cluster. Exiting. Make sure kind version is updated." + echo "Available versions: https://github.com/kubernetes-sigs/kind/releases" + exit 1 +fi + +# Local KIND images +export REGISTRY=${REGISTRY:-localhost:5001} +export TAG=${TAG:-latest} + +rm -f ${SCRIPT_ROOT}/hack/e2e/vpa-rbac.yaml +patch -c ${SCRIPT_ROOT}/deploy/vpa-rbac.yaml -i ${SCRIPT_ROOT}/hack/e2e/vpa-rbac.diff -o ${SCRIPT_ROOT}/hack/e2e/vpa-rbac.yaml +kubectl apply -f ${SCRIPT_ROOT}/hack/e2e/vpa-rbac.yaml +# Other-versioned CRDs are irrelevant as we're running a modern-ish cluster. +kubectl apply -f ${SCRIPT_ROOT}/deploy/vpa-v1-crd-gen.yaml +kubectl apply -f ${SCRIPT_ROOT}/hack/e2e/k8s-metrics-server.yaml + +for i in ${COMPONENTS}; do + ALL_ARCHITECTURES=${ARCH} make --directory ${SCRIPT_ROOT}/pkg/${i} docker-build REGISTRY=${REGISTRY} TAG=${TAG} + docker tag ${REGISTRY}/vpa-${i}-${ARCH}:${TAG} ${REGISTRY}/vpa-${i}:${TAG} + kind load docker-image ${REGISTRY}/vpa-${i}:${TAG} +done + +export GO111MODULE=on + +case ${SUITE} in + recommender) + + export KUBECONFIG=$HOME/.kube/config + pushd ${SCRIPT_ROOT}/e2e + go test ./integration/*go -v --test.timeout=10m --args --ginkgo.v=true --ginkgo.focus="\[VPA\] \[${SUITE}\]" --disable-log-dump --ginkgo.timeout=10m + INTEGRATION_RESULT=$? + popd + echo integration test result: ${INTEGRATION_RESULT} + if [ $INTEGRATION_RESULT -gt 0 ]; then + echo "Please check integration \"go test\" logs!" + fi + if [ $INTEGRATION_RESULT -gt 0 ]; then + echo "Tests failed" + exit 1 + fi + ;; + *) + print_help + exit 1 + ;; +esac