From 9a0521a856d082d6d56a798285f2cbd2b4798273 Mon Sep 17 00:00:00 2001 From: xiaoqing Date: Wed, 17 May 2023 22:45:16 +0800 Subject: [PATCH] Add subresource status for vpa Add status field in subresource on crd yaml and add new ClusterRole system:vpa-actor to patch /status subresource. The `metadata.generation` only increase on vpa spec update. Fix e2e test for patch and create vpa --- vertical-pod-autoscaler/deploy/vpa-rbac.yaml | 26 ++++++++++++- .../deploy/vpa-v1-crd-gen.yaml | 3 +- vertical-pod-autoscaler/e2e/v1/actuation.go | 2 +- .../e2e/v1/admission_controller.go | 38 +++++++++---------- vertical-pod-autoscaler/e2e/v1/common.go | 26 +++++++++++-- vertical-pod-autoscaler/e2e/v1beta2/common.go | 22 ++++++++++- .../pkg/apis/autoscaling.k8s.io/v1/types.go | 1 + vertical-pod-autoscaler/pkg/utils/vpa/api.go | 6 +-- 8 files changed, 94 insertions(+), 30 deletions(-) diff --git a/vertical-pod-autoscaler/deploy/vpa-rbac.yaml b/vertical-pod-autoscaler/deploy/vpa-rbac.yaml index 8c81b9a3c72a..45147c36b7ef 100644 --- a/vertical-pod-autoscaler/deploy/vpa-rbac.yaml +++ b/vertical-pod-autoscaler/deploy/vpa-rbac.yaml @@ -44,7 +44,6 @@ rules: - get - list - watch - - patch - apiGroups: - "autoscaling.k8s.io" resources: @@ -53,6 +52,18 @@ rules: - get - list - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: system:vpa-status-actor +rules: + - apiGroups: + - "autoscaling.k8s.io" + resources: + - verticalpodautoscalers/status + verbs: + - get - patch --- apiVersion: rbac.authorization.k8s.io/v1 @@ -140,6 +151,19 @@ subjects: --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding +metadata: + name: system:vpa-status-actor +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:vpa-status-actor +subjects: + - kind: ServiceAccount + name: vpa-recommender + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding metadata: name: system:vpa-checkpoint-actor roleRef: diff --git a/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml b/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml index 42a89bfb0090..7756dfe8d56a 100644 --- a/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml +++ b/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml @@ -513,7 +513,8 @@ spec: type: object served: true storage: true - subresources: {} + subresources: + status: {} - deprecated: true deprecationWarning: autoscaling.k8s.io/v1beta2 API is deprecated name: v1beta2 diff --git a/vertical-pod-autoscaler/e2e/v1/actuation.go b/vertical-pod-autoscaler/e2e/v1/actuation.go index 596fe0acd2a1..d9c6fc85f3bb 100644 --- a/vertical-pod-autoscaler/e2e/v1/actuation.go +++ b/vertical-pod-autoscaler/e2e/v1/actuation.go @@ -335,7 +335,7 @@ var _ = ActuationSuiteE2eDescribe("Actuation", func() { hamsterResourceList := apiv1.ResourceList{apiv1.ResourceCPU: ParseQuantityOrDie("100m")} sidecarResourceList := apiv1.ResourceList{apiv1.ResourceCPU: ParseQuantityOrDie("5000m")} - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Spec.UpdatePolicy.UpdateMode = &mode vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ diff --git a/vertical-pod-autoscaler/e2e/v1/admission_controller.go b/vertical-pod-autoscaler/e2e/v1/admission_controller.go index 9c8d927df85d..54056f957ead 100644 --- a/vertical-pod-autoscaler/e2e/v1/admission_controller.go +++ b/vertical-pod-autoscaler/e2e/v1/admission_controller.go @@ -43,7 +43,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{{ ContainerName: "hamster", @@ -70,7 +70,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{ { @@ -106,7 +106,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{ { @@ -143,7 +143,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { } klog.Infof("d: %+v", d) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{ { @@ -175,7 +175,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { InstallLimitRangeWithMax(f, "300m", "1Gi", apiv1.LimitTypeContainer) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{ { @@ -214,7 +214,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { InstallLimitRangeWithMax(f, "300m", "1Gi", apiv1.LimitTypeContainer) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{ { @@ -261,7 +261,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { } klog.Infof("d: %+v", d) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{ { @@ -301,7 +301,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{{ ContainerName: "hamster", @@ -345,7 +345,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { d := NewHamsterDeploymentWithGuaranteedResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{{ ContainerName: "hamster", @@ -376,7 +376,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { ParseQuantityOrDie("150m") /*cpu limit*/, ParseQuantityOrDie("200Mi") /*memory limit*/) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{{ ContainerName: "hamster", @@ -407,7 +407,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { ParseQuantityOrDie("500m") /*cpu limit*/, ParseQuantityOrDie("500Mi") /*memory limit*/) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{{ ContainerName: "hamster", @@ -450,7 +450,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { d := NewHamsterDeploymentWithResourcesAndLimits(f, startCpuRequest, startMemRequest, startCpuLimit, startMemLimit) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{{ ContainerName: "hamster", @@ -503,7 +503,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { ParseQuantityOrDie("150m") /*cpu limit*/, ParseQuantityOrDie("400Mi") /*memory limit*/) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{{ ContainerName: "hamster", @@ -545,7 +545,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { 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" ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{ { @@ -595,7 +595,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { 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" ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{ { @@ -643,7 +643,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{{ ContainerName: "hamster", @@ -680,7 +680,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Status.Recommendation = &vpa_types.RecommendedPodResources{ ContainerRecommendations: []vpa_types.RecommendedContainerResources{{ ContainerName: "hamster", @@ -717,7 +717,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { d := NewHamsterDeploymentWithResources(f, ParseQuantityOrDie("100m") /*cpu*/, ParseQuantityOrDie("100Mi") /*memory*/) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") @@ -734,7 +734,7 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", func() { d := NewHamsterDeployment(f) ginkgo.By("Setting up a VPA CRD") - vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", hamsterTargetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) InstallVPA(f, vpaCRD) ginkgo.By("Setting up a hamster deployment") diff --git a/vertical-pod-autoscaler/e2e/v1/common.go b/vertical-pod-autoscaler/e2e/v1/common.go index c90ec6fc8b2d..1b5c1c9f0e77 100644 --- a/vertical-pod-autoscaler/e2e/v1/common.go +++ b/vertical-pod-autoscaler/e2e/v1/common.go @@ -56,6 +56,8 @@ const ( defaultHamsterReplicas = int32(3) defaultHamsterBackoffLimit = int32(10) + // dummyRecommender for self update vpa status, avoid being modified by the default recommender + dummyRecommender = "notExistRecommender" ) var hamsterTargetRef = &autoscaling.CrossVersionObjectReference{ @@ -302,7 +304,7 @@ func SetupVPAForNHamsters(f *framework.Framework, n int, cpu string, mode vpa_ty // SetupVPAForNHamstersWithMinReplicas creates and installs a simple hamster VPA for a pod with n containers, setting MinReplicas. To be used for e2e test purposes. func SetupVPAForNHamstersWithMinReplicas(f *framework.Framework, n int, cpu string, mode vpa_types.UpdateMode, targetRef *autoscaling.CrossVersionObjectReference, minReplicas *int32) *vpa_types.VerticalPodAutoscaler { - vpaCRD := NewVPA(f, "hamster-vpa", targetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{}) + vpaCRD := NewVPA(f, "hamster-vpa", targetRef, []*vpa_types.VerticalPodAutoscalerRecommenderSelector{{Name: dummyRecommender}}) vpaCRD.Spec.UpdatePolicy.UpdateMode = &mode vpaCRD.Spec.UpdatePolicy.MinReplicas = minReplicas @@ -369,9 +371,27 @@ func getVpaClientSet(f *framework.Framework) vpa_clientset.Interface { // InstallVPA installs a VPA object in the test cluster. func InstallVPA(f *framework.Framework, vpa *vpa_types.VerticalPodAutoscaler) { + status := vpa.Status vpaClientSet := getVpaClientSet(f) - _, err := vpaClientSet.AutoscalingV1().VerticalPodAutoscalers(f.Namespace.Name).Create(context.TODO(), vpa, metav1.CreateOptions{}) + vpa, 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(&status) { + vpa.Status = status + _, err := vpaClientSet.AutoscalingV1().VerticalPodAutoscalers(f.Namespace.Name).UpdateStatus(context.TODO(), vpa, metav1.UpdateOptions{}) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error update VPA status") + } +} + +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. @@ -396,7 +416,7 @@ func PatchVpaRecommendation(f *framework.Framework, vpa *vpa_types.VerticalPodAu 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{}) + _, 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.") } diff --git a/vertical-pod-autoscaler/e2e/v1beta2/common.go b/vertical-pod-autoscaler/e2e/v1beta2/common.go index b4e31bd8a1af..53de4f890ba0 100644 --- a/vertical-pod-autoscaler/e2e/v1beta2/common.go +++ b/vertical-pod-autoscaler/e2e/v1beta2/common.go @@ -357,9 +357,27 @@ func getVpaClientSet(f *framework.Framework) vpa_clientset.Interface { // InstallVPA installs a VPA object in the test cluster. func InstallVPA(f *framework.Framework, vpa *vpa_types.VerticalPodAutoscaler) { + status := vpa.Status vpaClientSet := getVpaClientSet(f) - _, err := vpaClientSet.AutoscalingV1beta2().VerticalPodAutoscalers(f.Namespace.Name).Create(context.TODO(), vpa, metav1.CreateOptions{}) + vpa, err := vpaClientSet.AutoscalingV1beta2().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(&status) { + vpa.Status = status + _, err := vpaClientSet.AutoscalingV1beta2().VerticalPodAutoscalers(f.Namespace.Name).UpdateStatus(context.TODO(), vpa, metav1.UpdateOptions{}) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error update VPA status") + } +} + +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. @@ -384,7 +402,7 @@ func PatchVpaRecommendation(f *framework.Framework, vpa *vpa_types.VerticalPodAu Value: *newStatus, }}) gomega.Expect(err).NotTo(gomega.HaveOccurred()) - _, err = getVpaClientSet(f).AutoscalingV1beta2().VerticalPodAutoscalers(f.Namespace.Name).Patch(context.TODO(), vpa.Name, types.JSONPatchType, bytes, metav1.PatchOptions{}) + _, err = getVpaClientSet(f).AutoscalingV1beta2().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.") } diff --git a/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go b/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go index aff68d6fe406..0bc2e60f8806 100644 --- a/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go +++ b/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go @@ -40,6 +40,7 @@ type VerticalPodAutoscalerList struct { // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +kubebuilder:storageversion // +kubebuilder:resource:shortName=vpa +// +kubebuilder:subresource:status // +kubebuilder:printcolumn:name="Mode",type="string",JSONPath=".spec.updatePolicy.updateMode" // +kubebuilder:printcolumn:name="CPU",type="string",JSONPath=".status.recommendation.containerRecommendations[0].target.cpu" // +kubebuilder:printcolumn:name="Mem",type="string",JSONPath=".status.recommendation.containerRecommendations[0].target.memory" diff --git a/vertical-pod-autoscaler/pkg/utils/vpa/api.go b/vertical-pod-autoscaler/pkg/utils/vpa/api.go index 7fa869390be4..891c0e0bb3de 100644 --- a/vertical-pod-autoscaler/pkg/utils/vpa/api.go +++ b/vertical-pod-autoscaler/pkg/utils/vpa/api.go @@ -49,14 +49,14 @@ type patchRecord struct { Value interface{} `json:"value"` } -func patchVpa(vpaClient vpa_api.VerticalPodAutoscalerInterface, vpaName string, patches []patchRecord) (result *vpa_types.VerticalPodAutoscaler, err error) { +func patchVpaStatus(vpaClient vpa_api.VerticalPodAutoscalerInterface, vpaName string, patches []patchRecord) (result *vpa_types.VerticalPodAutoscaler, err error) { bytes, err := json.Marshal(patches) if err != nil { klog.Errorf("Cannot marshal VPA status patches %+v. Reason: %+v", patches, err) return } - return vpaClient.Patch(context.TODO(), vpaName, types.JSONPatchType, bytes, meta.PatchOptions{}) + return vpaClient.Patch(context.TODO(), vpaName, types.JSONPatchType, bytes, meta.PatchOptions{}, "status") } // UpdateVpaStatusIfNeeded updates the status field of the VPA API object. @@ -69,7 +69,7 @@ func UpdateVpaStatusIfNeeded(vpaClient vpa_api.VerticalPodAutoscalerInterface, v }} if !apiequality.Semantic.DeepEqual(*oldStatus, *newStatus) { - return patchVpa(vpaClient, vpaName, patches) + return patchVpaStatus(vpaClient, vpaName, patches) } return nil, nil }