From 93bdea80baf6cad19b383f0cf97dd6a17c923391 Mon Sep 17 00:00:00 2001 From: Kensei Nakada Date: Thu, 12 Oct 2023 00:18:15 +0900 Subject: [PATCH] implement v1beta2 --- PROJECT | 8 + README.md | 4 +- .../horizontalpodautoscaler_webhook_test.go | 4 +- .../has-annotation-but-invalid1/tortoise.yaml | 6 +- .../has-annotation-but-invalid2/tortoise.yaml | 6 +- .../mutate-by-recommendations/tortoise.yaml | 6 +- api/autoscaling/v2/webhook_suite_test.go | 4 +- api/v1alpha1/tortoise_conversion.go | 116 ++-- api/v1alpha1/webhook_suite_test.go | 141 ----- api/v1beta1/tortoise_conversion.go | 280 ++++++++- api/v1beta1/tortoise_types.go | 1 - api/v1beta1/zz_generated.deepcopy.go | 2 +- api/v1beta2/groupversion_info.go | 45 ++ api/{v1beta1 => v1beta2}/service.go | 2 +- .../testdata/mutating/after.yaml | 2 +- .../testdata/mutating/before.yaml | 2 +- .../testdata/mutating/deployment.yaml | 0 .../deployment.yaml | 0 .../hpa-specified-but-no-horizontal/hpa.yaml | 0 .../tortoise.yaml | 2 +- .../no-horizontal-in-tortoise/deployment.yaml | 0 .../no-horizontal-in-tortoise/hpa.yaml | 0 .../no-horizontal-in-tortoise/tortoise.yaml | 2 +- .../before-tortoise.yaml | 2 +- .../no-horizontal-with-hpa/deployment.yaml | 0 .../no-horizontal-with-hpa/hpa.yaml | 0 .../updating-tortoise.yaml | 2 +- .../before-tortoise.yaml | 2 +- .../deployment.yaml | 0 .../no-horizontal-with-no-deletion/hpa.yaml | 0 .../updating-tortoise.yaml | 2 +- .../no-metric-in-hpa/deployment.yaml | 0 .../validating/no-metric-in-hpa/hpa.yaml | 0 .../no-metric-in-hpa}/tortoise.yaml | 2 +- .../deployment.yaml | 0 .../not-targetting-deployment}/hpa.yaml | 0 .../not-targetting-deployment/tortoise.yaml | 22 + .../before-tortoise.yaml | 2 +- .../deployment.yaml | 0 .../success-remove-all-horizontal}/hpa.yaml | 0 .../updating-tortoise.yaml | 2 +- .../validating/success}/deployment.yaml | 0 .../testdata/validating/success}/hpa.yaml | 0 .../validating/success}/tortoise.yaml | 2 +- .../validating/useless-policy/deployment.yaml | 26 + .../validating/useless-policy/hpa.yaml | 27 + .../validating/useless-policy/tortoise.yaml | 2 +- .../tortoise_conversion.go} | 15 +- api/v1beta2/tortoise_types.go | 363 ++++++++++++ api/{v1beta1 => v1beta2}/tortoise_webhook.go | 17 +- .../tortoise_webhook_test.go | 5 +- .../webhook_suite_test.go | 2 +- api/v1beta2/zz_generated.deepcopy.go | 513 +++++++++++++++++ .../autoscaling.mercari.com_tortoises.yaml | 434 ++++++++++++++ .../samples/autoscaling_v1beta2_tortoise.yaml | 12 + config/webhook/manifests.yaml | 8 +- controllers/suite_test.go | 4 +- .../deletion-policy-all/before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 4 +- .../before/tortoise.yaml | 4 +- .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - .../after/tortoise.yaml | 1 - .../before/tortoise.yaml | 1 - controllers/tortoise_controller.go | 16 +- controllers/tortoise_controller_test.go | 58 +- go.mod | 2 +- main.go | 8 +- ...ion_tortoises.autoscaling.mercari.com.yaml | 356 ++++++++++++ ...rtoise-mutating-webhook-configuration.yaml | 4 +- ...oise-validating-webhook-configuration.yaml | 4 +- ...ion_tortoises.autoscaling.mercari.com.yaml | 356 ++++++++++++ pkg/deployment/service.go | 4 +- pkg/hpa/service.go | 58 +- pkg/hpa/service_test.go | 534 +++++++++--------- pkg/recommender/recommender.go | 30 +- pkg/recommender/recommender_test.go | 384 ++++++------- pkg/tortoise/tortoise.go | 118 ++-- pkg/tortoise/tortoise_test.go | 452 ++++++++------- pkg/utils/tortoise_builder.go | 24 +- pkg/vpa/service.go | 46 +- pkg/vpa/service_test.go | 76 +-- 104 files changed, 3470 insertions(+), 1194 deletions(-) delete mode 100644 api/v1alpha1/webhook_suite_test.go create mode 100644 api/v1beta2/groupversion_info.go rename api/{v1beta1 => v1beta2}/service.go (98%) rename api/{v1beta1 => v1beta2}/testdata/mutating/after.yaml (90%) rename api/{v1beta1 => v1beta2}/testdata/mutating/before.yaml (77%) rename api/{v1beta1 => v1beta2}/testdata/mutating/deployment.yaml (100%) rename api/{v1beta1 => v1beta2}/testdata/validating/hpa-specified-but-no-horizontal/deployment.yaml (100%) rename api/{v1beta1 => v1beta2}/testdata/validating/hpa-specified-but-no-horizontal/hpa.yaml (100%) rename api/{v1beta1 => v1beta2}/testdata/validating/hpa-specified-but-no-horizontal/tortoise.yaml (91%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-horizontal-in-tortoise/deployment.yaml (100%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-horizontal-in-tortoise/hpa.yaml (100%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-horizontal-in-tortoise/tortoise.yaml (91%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-horizontal-with-hpa/before-tortoise.yaml (91%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-horizontal-with-hpa/deployment.yaml (100%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-horizontal-with-hpa/hpa.yaml (100%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-horizontal-with-hpa/updating-tortoise.yaml (91%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-horizontal-with-no-deletion/before-tortoise.yaml (90%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-horizontal-with-no-deletion/deployment.yaml (100%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-horizontal-with-no-deletion/hpa.yaml (100%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-horizontal-with-no-deletion/updating-tortoise.yaml (90%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-metric-in-hpa/deployment.yaml (100%) rename api/{v1beta1 => v1beta2}/testdata/validating/no-metric-in-hpa/hpa.yaml (100%) rename api/{v1beta1/testdata/validating/success => v1beta2/testdata/validating/no-metric-in-hpa}/tortoise.yaml (91%) rename api/{v1beta1/testdata/validating/success-remove-all-horizontal => v1beta2/testdata/validating/not-targetting-deployment}/deployment.yaml (100%) rename api/{v1beta1/testdata/validating/success-remove-all-horizontal => v1beta2/testdata/validating/not-targetting-deployment}/hpa.yaml (100%) create mode 100644 api/v1beta2/testdata/validating/not-targetting-deployment/tortoise.yaml rename api/{v1beta1 => v1beta2}/testdata/validating/success-remove-all-horizontal/before-tortoise.yaml (91%) rename api/{v1beta1/testdata/validating/success => v1beta2/testdata/validating/success-remove-all-horizontal}/deployment.yaml (100%) rename api/{v1beta1/testdata/validating/success => v1beta2/testdata/validating/success-remove-all-horizontal}/hpa.yaml (100%) rename api/{v1beta1 => v1beta2}/testdata/validating/success-remove-all-horizontal/updating-tortoise.yaml (90%) rename api/{v1beta1/testdata/validating/useless-policy => v1beta2/testdata/validating/success}/deployment.yaml (100%) rename api/{v1beta1/testdata/validating/useless-policy => v1beta2/testdata/validating/success}/hpa.yaml (100%) rename api/{v1beta1/testdata/validating/no-metric-in-hpa => v1beta2/testdata/validating/success}/tortoise.yaml (91%) create mode 100644 api/v1beta2/testdata/validating/useless-policy/deployment.yaml create mode 100644 api/v1beta2/testdata/validating/useless-policy/hpa.yaml rename api/{v1beta1 => v1beta2}/testdata/validating/useless-policy/tortoise.yaml (92%) rename api/{v1alpha1/tortoise_webhook.go => v1beta2/tortoise_conversion.go} (79%) create mode 100644 api/v1beta2/tortoise_types.go rename api/{v1beta1 => v1beta2}/tortoise_webhook.go (96%) rename api/{v1beta1 => v1beta2}/tortoise_webhook_test.go (96%) rename api/{v1beta1 => v1beta2}/webhook_suite_test.go (99%) create mode 100644 api/v1beta2/zz_generated.deepcopy.go create mode 100644 config/samples/autoscaling_v1beta2_tortoise.yaml diff --git a/PROJECT b/PROJECT index 94bb9261..bc72fc48 100644 --- a/PROJECT +++ b/PROJECT @@ -33,4 +33,12 @@ resources: webhooks: conversion: true webhookVersion: v1 +- api: + crdVersion: v1 + namespaced: true + domain: mercari.com + group: autoscaling + kind: Tortoise + path: github.com/mercari/tortoise/api/v1beta2 + version: v1beta2 version: "3" diff --git a/README.md b/README.md index 54467b74..39007b98 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Tortoise, you don't need a rearing cage, but need VPA in your Kubernetes cluster Tortoise, they only need the deployment name basically. ```yaml -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: lovely-tortoise @@ -55,7 +55,7 @@ Tortoise, then they'll prepare/keep adjusting HPA and VPA to achieve efficient a ## API definition -- [Tortoise](./api/v1beta1/tortoise_types.go) +- [Tortoise](./api/v1beta2/tortoise_types.go) ## Contribution diff --git a/api/autoscaling/v2/horizontalpodautoscaler_webhook_test.go b/api/autoscaling/v2/horizontalpodautoscaler_webhook_test.go index 5d9cf2ac..dd9f64d9 100644 --- a/api/autoscaling/v2/horizontalpodautoscaler_webhook_test.go +++ b/api/autoscaling/v2/horizontalpodautoscaler_webhook_test.go @@ -35,7 +35,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/yaml" - "github.com/mercari/tortoise/api/v1beta1" + "github.com/mercari/tortoise/api/v1beta2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -46,7 +46,7 @@ func mutateTest(before, after, torotise string) { y, err := os.ReadFile(torotise) Expect(err).NotTo(HaveOccurred()) - tor := &v1beta1.Tortoise{} + tor := &v1beta2.Tortoise{} err = yaml.NewYAMLOrJSONDecoder(bytes.NewReader(y), 4096).Decode(tor) status := tor.Status Expect(err).NotTo(HaveOccurred()) diff --git a/api/autoscaling/v2/testdata/mutating/has-annotation-but-invalid1/tortoise.yaml b/api/autoscaling/v2/testdata/mutating/has-annotation-but-invalid1/tortoise.yaml index b2e68624..17ebdf04 100644 --- a/api/autoscaling/v2/testdata/mutating/has-annotation-but-invalid1/tortoise.yaml +++ b/api/autoscaling/v2/testdata/mutating/has-annotation-but-invalid1/tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample @@ -36,7 +36,9 @@ status: memory: phase: Working targets: - deployment: sample + scaleTargetRef: + kind: Deployment + name: sample horizontalPodAutoscaler: sample verticalPodAutoscalers: - name: tortoise-monitor-sample diff --git a/api/autoscaling/v2/testdata/mutating/has-annotation-but-invalid2/tortoise.yaml b/api/autoscaling/v2/testdata/mutating/has-annotation-but-invalid2/tortoise.yaml index e27ad9bc..15792489 100644 --- a/api/autoscaling/v2/testdata/mutating/has-annotation-but-invalid2/tortoise.yaml +++ b/api/autoscaling/v2/testdata/mutating/has-annotation-but-invalid2/tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample @@ -36,7 +36,9 @@ status: memory: phase: Working targets: - deployment: sample + scaleTargetRef: + kind: Deployment + name: sample horizontalPodAutoscaler: sample2 verticalPodAutoscalers: - name: tortoise-monitor-sample diff --git a/api/autoscaling/v2/testdata/mutating/mutate-by-recommendations/tortoise.yaml b/api/autoscaling/v2/testdata/mutating/mutate-by-recommendations/tortoise.yaml index b2e68624..17ebdf04 100644 --- a/api/autoscaling/v2/testdata/mutating/mutate-by-recommendations/tortoise.yaml +++ b/api/autoscaling/v2/testdata/mutating/mutate-by-recommendations/tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample @@ -36,7 +36,9 @@ status: memory: phase: Working targets: - deployment: sample + scaleTargetRef: + kind: Deployment + name: sample horizontalPodAutoscaler: sample verticalPodAutoscalers: - name: tortoise-monitor-sample diff --git a/api/autoscaling/v2/webhook_suite_test.go b/api/autoscaling/v2/webhook_suite_test.go index 96b4be2a..8a502f89 100644 --- a/api/autoscaling/v2/webhook_suite_test.go +++ b/api/autoscaling/v2/webhook_suite_test.go @@ -51,7 +51,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - "github.com/mercari/tortoise/api/v1beta1" + "github.com/mercari/tortoise/api/v1beta2" "github.com/mercari/tortoise/pkg/config" "github.com/mercari/tortoise/pkg/hpa" "github.com/mercari/tortoise/pkg/tortoise" @@ -115,7 +115,7 @@ var _ = BeforeSuite(func() { Expect(cfg).NotTo(BeNil()) scheme := runtime.NewScheme() - err = v1beta1.AddToScheme(scheme) + err = v1beta2.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) err = clientgoscheme.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) diff --git a/api/v1alpha1/tortoise_conversion.go b/api/v1alpha1/tortoise_conversion.go index da8ec5ad..505bdfdd 100644 --- a/api/v1alpha1/tortoise_conversion.go +++ b/api/v1alpha1/tortoise_conversion.go @@ -31,43 +31,47 @@ import ( v1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/conversion" - "github.com/mercari/tortoise/api/v1beta1" + "github.com/mercari/tortoise/api/v1beta2" ) -// ConvertTo converts this CronJob to the Hub version (v1beta1). +// ConvertTo converts this CronJob to the Hub version (v1beta2). func (src *Tortoise) ConvertTo(dstRaw conversion.Hub) error { - dst := dstRaw.(*v1beta1.Tortoise) + dst := dstRaw.(*v1beta2.Tortoise) dst.ObjectMeta = src.ObjectMeta - dst.Spec = v1beta1.TortoiseSpec{ - TargetRefs: v1beta1.TargetRefs{ + dst.Spec = v1beta2.TortoiseSpec{ + TargetRefs: v1beta2.TargetRefs{ HorizontalPodAutoscalerName: src.Spec.TargetRefs.HorizontalPodAutoscalerName, - ScaleTargetRef: v1beta1.CrossVersionObjectReference{ + ScaleTargetRef: v1beta2.CrossVersionObjectReference{ APIVersion: "apps/v1", Kind: "Deployment", Name: src.Spec.TargetRefs.DeploymentName, }, }, - UpdateMode: v1beta1.UpdateMode(src.Spec.UpdateMode), + UpdateMode: v1beta2.UpdateMode(src.Spec.UpdateMode), ResourcePolicy: containerResourcePolicyConversionToV1Beta1(src.Spec.ResourcePolicy), - DeletionPolicy: v1beta1.DeletionPolicy(src.Spec.DeletionPolicy), + DeletionPolicy: v1beta2.DeletionPolicy(src.Spec.DeletionPolicy), } - dst.Status = v1beta1.TortoiseStatus{ - TortoisePhase: v1beta1.TortoisePhase(src.Status.TortoisePhase), - Conditions: v1beta1.Conditions{ + dst.Status = v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhase(src.Status.TortoisePhase), + Conditions: v1beta2.Conditions{ ContainerRecommendationFromVPA: containerRecommendationFromVPAConversionToV1Beta1(src.Status.Conditions.ContainerRecommendationFromVPA), }, - Targets: v1beta1.TargetsStatus{ + Targets: v1beta2.TargetsStatus{ HorizontalPodAutoscaler: src.Status.Targets.HorizontalPodAutoscaler, - Deployment: src.Status.Targets.Deployment, - VerticalPodAutoscalers: verticalPodAutoscalersConversionToV1Beta1(src.Status.Targets.VerticalPodAutoscalers), + ScaleTargetRef: v1beta2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: src.Status.Targets.Deployment, + }, + VerticalPodAutoscalers: verticalPodAutoscalersConversionToV1Beta1(src.Status.Targets.VerticalPodAutoscalers), }, } if src.Status.Recommendations.Horizontal != nil { - dst.Status = v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ + dst.Status = v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ TargetUtilizations: hPATargetUtilizationRecommendationPerContainerConversionToV1Beta1(src.Status.Recommendations.Horizontal.TargetUtilizations), MaxReplicas: replicasRecommendationConversionToV1Beta1(src.Status.Recommendations.Horizontal.MaxReplicas), MinReplicas: replicasRecommendationConversionToV1Beta1(src.Status.Recommendations.Horizontal.MinReplicas), @@ -76,9 +80,9 @@ func (src *Tortoise) ConvertTo(dstRaw conversion.Hub) error { } } if src.Status.Recommendations.Vertical != nil { - dst.Status = v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Vertical: v1beta1.VerticalRecommendations{ + dst.Status = v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Vertical: v1beta2.VerticalRecommendations{ ContainerResourceRecommendation: containerResourceRecommendationConversionToV1Beta1(src.Status.Recommendations.Vertical.ContainerResourceRecommendation), }, }, @@ -88,9 +92,9 @@ func (src *Tortoise) ConvertTo(dstRaw conversion.Hub) error { return nil } -// ConvertFrom converts from the Hub version (v1beta1) to this version. +// ConvertFrom converts from the Hub version (v1beta2) to this version. func (dst *Tortoise) ConvertFrom(srcRaw conversion.Hub) error { - src := srcRaw.(*v1beta1.Tortoise) + src := srcRaw.(*v1beta2.Tortoise) if src.Spec.TargetRefs.ScaleTargetRef.Kind != "Deployment" { return fmt.Errorf("scaleTargetRef is not Deployment, but %s which isn't supported in v1alpha1", src.Spec.TargetRefs.ScaleTargetRef.Kind) } @@ -113,7 +117,7 @@ func (dst *Tortoise) ConvertFrom(srcRaw conversion.Hub) error { }, Targets: TargetsStatus{ HorizontalPodAutoscaler: src.Status.Targets.HorizontalPodAutoscaler, - Deployment: src.Status.Targets.Deployment, + Deployment: src.Status.Targets.ScaleTargetRef.Name, VerticalPodAutoscalers: verticalPodAutoscalersConversionFromV1Beta1(src.Status.Targets.VerticalPodAutoscalers), }, Recommendations: Recommendations{ @@ -130,7 +134,7 @@ func (dst *Tortoise) ConvertFrom(srcRaw conversion.Hub) error { return nil } -func verticalPodAutoscalersConversionFromV1Beta1(vpas []v1beta1.TargetStatusVerticalPodAutoscaler) []TargetStatusVerticalPodAutoscaler { +func verticalPodAutoscalersConversionFromV1Beta1(vpas []v1beta2.TargetStatusVerticalPodAutoscaler) []TargetStatusVerticalPodAutoscaler { converted := make([]TargetStatusVerticalPodAutoscaler, 0, len(vpas)) for _, vpa := range vpas { converted = append(converted, TargetStatusVerticalPodAutoscaler{ @@ -141,18 +145,18 @@ func verticalPodAutoscalersConversionFromV1Beta1(vpas []v1beta1.TargetStatusVert return converted } -func verticalPodAutoscalersConversionToV1Beta1(vpas []TargetStatusVerticalPodAutoscaler) []v1beta1.TargetStatusVerticalPodAutoscaler { - converted := make([]v1beta1.TargetStatusVerticalPodAutoscaler, 0, len(vpas)) +func verticalPodAutoscalersConversionToV1Beta1(vpas []TargetStatusVerticalPodAutoscaler) []v1beta2.TargetStatusVerticalPodAutoscaler { + converted := make([]v1beta2.TargetStatusVerticalPodAutoscaler, 0, len(vpas)) for _, vpa := range vpas { - converted = append(converted, v1beta1.TargetStatusVerticalPodAutoscaler{ + converted = append(converted, v1beta2.TargetStatusVerticalPodAutoscaler{ Name: vpa.Name, - Role: v1beta1.VerticalPodAutoscalerRole(vpa.Role), + Role: v1beta2.VerticalPodAutoscalerRole(vpa.Role), }) } return converted } -func containerResourceRecommendationConversionFromV1Beta1(resources []v1beta1.RecommendedContainerResources) []RecommendedContainerResources { +func containerResourceRecommendationConversionFromV1Beta1(resources []v1beta2.RecommendedContainerResources) []RecommendedContainerResources { converted := make([]RecommendedContainerResources, 0, len(resources)) for _, resource := range resources { converted = append(converted, RecommendedContainerResources{ @@ -163,10 +167,10 @@ func containerResourceRecommendationConversionFromV1Beta1(resources []v1beta1.Re return converted } -func containerResourceRecommendationConversionToV1Beta1(resources []RecommendedContainerResources) []v1beta1.RecommendedContainerResources { - converted := make([]v1beta1.RecommendedContainerResources, 0, len(resources)) +func containerResourceRecommendationConversionToV1Beta1(resources []RecommendedContainerResources) []v1beta2.RecommendedContainerResources { + converted := make([]v1beta2.RecommendedContainerResources, 0, len(resources)) for _, resource := range resources { - converted = append(converted, v1beta1.RecommendedContainerResources{ + converted = append(converted, v1beta2.RecommendedContainerResources{ ContainerName: resource.ContainerName, RecommendedResource: resource.RecommendedResource, }) @@ -174,7 +178,7 @@ func containerResourceRecommendationConversionToV1Beta1(resources []RecommendedC return converted } -func replicasRecommendationConversionFromV1Beta1(recommendations []v1beta1.ReplicasRecommendation) []ReplicasRecommendation { +func replicasRecommendationConversionFromV1Beta1(recommendations []v1beta2.ReplicasRecommendation) []ReplicasRecommendation { converted := make([]ReplicasRecommendation, 0, len(recommendations)) for _, recommendation := range recommendations { converted = append(converted, ReplicasRecommendation{ @@ -189,10 +193,10 @@ func replicasRecommendationConversionFromV1Beta1(recommendations []v1beta1.Repli return converted } -func replicasRecommendationConversionToV1Beta1(recommendations []ReplicasRecommendation) []v1beta1.ReplicasRecommendation { - converted := make([]v1beta1.ReplicasRecommendation, 0, len(recommendations)) +func replicasRecommendationConversionToV1Beta1(recommendations []ReplicasRecommendation) []v1beta2.ReplicasRecommendation { + converted := make([]v1beta2.ReplicasRecommendation, 0, len(recommendations)) for _, recommendation := range recommendations { - converted = append(converted, v1beta1.ReplicasRecommendation{ + converted = append(converted, v1beta2.ReplicasRecommendation{ From: recommendation.From, To: recommendation.To, WeekDay: recommendation.WeekDay, @@ -204,7 +208,7 @@ func replicasRecommendationConversionToV1Beta1(recommendations []ReplicasRecomme return converted } -func hPATargetUtilizationRecommendationPerContainerConversionFromV1Beta1(recommendations []v1beta1.HPATargetUtilizationRecommendationPerContainer) []HPATargetUtilizationRecommendationPerContainer { +func hPATargetUtilizationRecommendationPerContainerConversionFromV1Beta1(recommendations []v1beta2.HPATargetUtilizationRecommendationPerContainer) []HPATargetUtilizationRecommendationPerContainer { converted := make([]HPATargetUtilizationRecommendationPerContainer, 0, len(recommendations)) for _, recommendation := range recommendations { converted = append(converted, HPATargetUtilizationRecommendationPerContainer{ @@ -215,10 +219,10 @@ func hPATargetUtilizationRecommendationPerContainerConversionFromV1Beta1(recomme return converted } -func hPATargetUtilizationRecommendationPerContainerConversionToV1Beta1(recommendations []HPATargetUtilizationRecommendationPerContainer) []v1beta1.HPATargetUtilizationRecommendationPerContainer { - converted := make([]v1beta1.HPATargetUtilizationRecommendationPerContainer, 0, len(recommendations)) +func hPATargetUtilizationRecommendationPerContainerConversionToV1Beta1(recommendations []HPATargetUtilizationRecommendationPerContainer) []v1beta2.HPATargetUtilizationRecommendationPerContainer { + converted := make([]v1beta2.HPATargetUtilizationRecommendationPerContainer, 0, len(recommendations)) for _, recommendation := range recommendations { - converted = append(converted, v1beta1.HPATargetUtilizationRecommendationPerContainer{ + converted = append(converted, v1beta2.HPATargetUtilizationRecommendationPerContainer{ ContainerName: recommendation.ContainerName, TargetUtilization: recommendation.TargetUtilization, }) @@ -226,7 +230,7 @@ func hPATargetUtilizationRecommendationPerContainerConversionToV1Beta1(recommend return converted } -func containerRecommendationFromVPAConversionFromV1Beta1(conditions []v1beta1.ContainerRecommendationFromVPA) []ContainerRecommendationFromVPA { +func containerRecommendationFromVPAConversionFromV1Beta1(conditions []v1beta2.ContainerRecommendationFromVPA) []ContainerRecommendationFromVPA { converted := make([]ContainerRecommendationFromVPA, 0, len(conditions)) for _, condition := range conditions { converted = append(converted, ContainerRecommendationFromVPA{ @@ -238,10 +242,10 @@ func containerRecommendationFromVPAConversionFromV1Beta1(conditions []v1beta1.Co return converted } -func containerRecommendationFromVPAConversionToV1Beta1(conditions []ContainerRecommendationFromVPA) []v1beta1.ContainerRecommendationFromVPA { - converted := make([]v1beta1.ContainerRecommendationFromVPA, 0, len(conditions)) +func containerRecommendationFromVPAConversionToV1Beta1(conditions []ContainerRecommendationFromVPA) []v1beta2.ContainerRecommendationFromVPA { + converted := make([]v1beta2.ContainerRecommendationFromVPA, 0, len(conditions)) for _, condition := range conditions { - converted = append(converted, v1beta1.ContainerRecommendationFromVPA{ + converted = append(converted, v1beta2.ContainerRecommendationFromVPA{ ContainerName: condition.ContainerName, MaxRecommendation: resourceQuantityMapConversionToV1Beta1(condition.MaxRecommendation), Recommendation: resourceQuantityMapConversionToV1Beta1(condition.Recommendation), @@ -250,7 +254,7 @@ func containerRecommendationFromVPAConversionToV1Beta1(conditions []ContainerRec return converted } -func resourceQuantityMapConversionFromV1Beta1(resources map[v1.ResourceName]v1beta1.ResourceQuantity) map[v1.ResourceName]ResourceQuantity { +func resourceQuantityMapConversionFromV1Beta1(resources map[v1.ResourceName]v1beta2.ResourceQuantity) map[v1.ResourceName]ResourceQuantity { converted := make(map[v1.ResourceName]ResourceQuantity, len(resources)) for k, v := range resources { converted[k] = ResourceQuantity(v) @@ -258,15 +262,15 @@ func resourceQuantityMapConversionFromV1Beta1(resources map[v1.ResourceName]v1be return converted } -func resourceQuantityMapConversionToV1Beta1(resources map[v1.ResourceName]ResourceQuantity) map[v1.ResourceName]v1beta1.ResourceQuantity { - converted := make(map[v1.ResourceName]v1beta1.ResourceQuantity, len(resources)) +func resourceQuantityMapConversionToV1Beta1(resources map[v1.ResourceName]ResourceQuantity) map[v1.ResourceName]v1beta2.ResourceQuantity { + converted := make(map[v1.ResourceName]v1beta2.ResourceQuantity, len(resources)) for k, v := range resources { - converted[k] = v1beta1.ResourceQuantity(v) + converted[k] = v1beta2.ResourceQuantity(v) } return converted } -func containerResourcePolicyConversionFromV1Beta1(policies []v1beta1.ContainerResourcePolicy) []ContainerResourcePolicy { +func containerResourcePolicyConversionFromV1Beta1(policies []v1beta2.ContainerResourcePolicy) []ContainerResourcePolicy { converted := make([]ContainerResourcePolicy, 0, len(policies)) for _, policy := range policies { converted = append(converted, ContainerResourcePolicy{ @@ -278,10 +282,10 @@ func containerResourcePolicyConversionFromV1Beta1(policies []v1beta1.ContainerRe return converted } -func containerResourcePolicyConversionToV1Beta1(policies []ContainerResourcePolicy) []v1beta1.ContainerResourcePolicy { - converted := make([]v1beta1.ContainerResourcePolicy, 0, len(policies)) +func containerResourcePolicyConversionToV1Beta1(policies []ContainerResourcePolicy) []v1beta2.ContainerResourcePolicy { + converted := make([]v1beta2.ContainerResourcePolicy, 0, len(policies)) for _, policy := range policies { - converted = append(converted, v1beta1.ContainerResourcePolicy{ + converted = append(converted, v1beta2.ContainerResourcePolicy{ ContainerName: policy.ContainerName, MinAllocatedResources: policy.MinAllocatedResources, AutoscalingPolicy: autoscalingPolicyConversionToV1Beta1(policy.AutoscalingPolicy), @@ -290,7 +294,7 @@ func containerResourcePolicyConversionToV1Beta1(policies []ContainerResourcePoli return converted } -func autoscalingPolicyConversionFromV1Beta1(policies map[v1.ResourceName]v1beta1.AutoscalingType) map[v1.ResourceName]AutoscalingType { +func autoscalingPolicyConversionFromV1Beta1(policies map[v1.ResourceName]v1beta2.AutoscalingType) map[v1.ResourceName]AutoscalingType { converted := make(map[v1.ResourceName]AutoscalingType, len(policies)) for k, v := range policies { converted[k] = AutoscalingType(v) @@ -298,10 +302,10 @@ func autoscalingPolicyConversionFromV1Beta1(policies map[v1.ResourceName]v1beta1 return converted } -func autoscalingPolicyConversionToV1Beta1(policies map[v1.ResourceName]AutoscalingType) map[v1.ResourceName]v1beta1.AutoscalingType { - converted := make(map[v1.ResourceName]v1beta1.AutoscalingType, len(policies)) +func autoscalingPolicyConversionToV1Beta1(policies map[v1.ResourceName]AutoscalingType) map[v1.ResourceName]v1beta2.AutoscalingType { + converted := make(map[v1.ResourceName]v1beta2.AutoscalingType, len(policies)) for k, v := range policies { - converted[k] = v1beta1.AutoscalingType(v) + converted[k] = v1beta2.AutoscalingType(v) } return converted } diff --git a/api/v1alpha1/webhook_suite_test.go b/api/v1alpha1/webhook_suite_test.go deleted file mode 100644 index 270fb129..00000000 --- a/api/v1alpha1/webhook_suite_test.go +++ /dev/null @@ -1,141 +0,0 @@ -/* -MIT License - -Copyright (c) 2023 mercari - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -package v1alpha1 - -import ( - "context" - "crypto/tls" - "fmt" - "net" - "path/filepath" - "testing" - "time" - - admissionv1beta1 "k8s.io/api/admission/v1beta1" - //+kubebuilder:scaffold:imports - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/rest" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -// These tests use Ginkgo (BDD-style Go testing framework). Refer to -// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. - -var cfg *rest.Config -var k8sClient client.Client -var testEnv *envtest.Environment -var ctx context.Context -var cancel context.CancelFunc - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecs(t, "Webhook Suite") -} - -var _ = BeforeSuite(func() { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - - ctx, cancel = context.WithCancel(context.TODO()) - - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, - ErrorIfCRDPathMissing: false, - WebhookInstallOptions: envtest.WebhookInstallOptions{ - Paths: []string{filepath.Join("..", "..", "config", "webhook")}, - }, - } - - var err error - // cfg is defined in this file globally. - cfg, err = testEnv.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) - - scheme := runtime.NewScheme() - err = AddToScheme(scheme) - Expect(err).NotTo(HaveOccurred()) - - err = admissionv1beta1.AddToScheme(scheme) - Expect(err).NotTo(HaveOccurred()) - - //+kubebuilder:scaffold:scheme - - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) - - // start webhook server using Manager - webhookInstallOptions := &testEnv.WebhookInstallOptions - mgr, err := ctrl.NewManager(cfg, ctrl.Options{ - Scheme: scheme, - Host: webhookInstallOptions.LocalServingHost, - Port: webhookInstallOptions.LocalServingPort, - CertDir: webhookInstallOptions.LocalServingCertDir, - LeaderElection: false, - MetricsBindAddress: "0", - }) - Expect(err).NotTo(HaveOccurred()) - - err = (&Tortoise{}).SetupWebhookWithManager(mgr) - Expect(err).NotTo(HaveOccurred()) - - //+kubebuilder:scaffold:webhook - - go func() { - defer GinkgoRecover() - err = mgr.Start(ctx) - Expect(err).NotTo(HaveOccurred()) - }() - - // wait for the webhook server to get ready - dialer := &net.Dialer{Timeout: time.Second} - addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort) - Eventually(func() error { - conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true}) - if err != nil { - return err - } - conn.Close() - return nil - }).Should(Succeed()) - -}) - -var _ = AfterSuite(func() { - cancel() - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) -}) diff --git a/api/v1beta1/tortoise_conversion.go b/api/v1beta1/tortoise_conversion.go index 7c2f8c0a..34308480 100644 --- a/api/v1beta1/tortoise_conversion.go +++ b/api/v1beta1/tortoise_conversion.go @@ -25,5 +25,281 @@ SOFTWARE. package v1beta1 -// Hub marks this type as a conversion hub. -func (*Tortoise) Hub() {} +import ( + "fmt" + + v1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/conversion" + + "github.com/mercari/tortoise/api/v1beta2" +) + +// ConvertTo converts this CronJob to the Hub version (v1beta2). +func (src *Tortoise) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*v1beta2.Tortoise) + dst.ObjectMeta = src.ObjectMeta + + dst.Spec = v1beta2.TortoiseSpec{ + TargetRefs: v1beta2.TargetRefs{ + HorizontalPodAutoscalerName: src.Spec.TargetRefs.HorizontalPodAutoscalerName, + ScaleTargetRef: v1beta2.CrossVersionObjectReference{ + APIVersion: src.Spec.TargetRefs.ScaleTargetRef.APIVersion, + Kind: src.Spec.TargetRefs.ScaleTargetRef.Kind, + Name: src.Spec.TargetRefs.ScaleTargetRef.Name, + }, + }, + UpdateMode: v1beta2.UpdateMode(src.Spec.UpdateMode), + ResourcePolicy: containerResourcePolicyConversionToV1Beta1(src.Spec.ResourcePolicy), + DeletionPolicy: v1beta2.DeletionPolicy(src.Spec.DeletionPolicy), + } + + dst.Status = v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhase(src.Status.TortoisePhase), + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: containerRecommendationFromVPAConversionToV1Beta1(src.Status.Conditions.ContainerRecommendationFromVPA), + }, + Targets: v1beta2.TargetsStatus{ + HorizontalPodAutoscaler: src.Status.Targets.HorizontalPodAutoscaler, + ScaleTargetRef: v1beta2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: src.Status.Targets.Deployment, + }, + VerticalPodAutoscalers: verticalPodAutoscalersConversionToV1Beta1(src.Status.Targets.VerticalPodAutoscalers), + }, + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + TargetUtilizations: hPATargetUtilizationRecommendationPerContainerConversionToV1Beta1(src.Status.Recommendations.Horizontal.TargetUtilizations), + MaxReplicas: replicasRecommendationConversionToV1Beta1(src.Status.Recommendations.Horizontal.MaxReplicas), + MinReplicas: replicasRecommendationConversionToV1Beta1(src.Status.Recommendations.Horizontal.MinReplicas), + }, + Vertical: v1beta2.VerticalRecommendations{ + ContainerResourceRecommendation: containerResourceRecommendationConversionToV1Beta1(src.Status.Recommendations.Vertical.ContainerResourceRecommendation), + }, + }, + } + + return nil +} + +// ConvertFrom converts from the Hub version (v1beta2) to this version. +func (dst *Tortoise) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*v1beta2.Tortoise) + if src.Spec.TargetRefs.ScaleTargetRef.Kind != "Deployment" { + return fmt.Errorf("scaleTargetRef is not Deployment, but %s which isn't supported in v1alpha1", src.Spec.TargetRefs.ScaleTargetRef.Kind) + } + + dst.ObjectMeta = src.ObjectMeta + dst.Spec = TortoiseSpec{ + TargetRefs: TargetRefs{ + HorizontalPodAutoscalerName: src.Spec.TargetRefs.HorizontalPodAutoscalerName, + ScaleTargetRef: CrossVersionObjectReference{ + APIVersion: src.Spec.TargetRefs.ScaleTargetRef.APIVersion, + Kind: src.Spec.TargetRefs.ScaleTargetRef.Kind, + Name: src.Spec.TargetRefs.ScaleTargetRef.Name, + }, + }, + UpdateMode: UpdateMode(src.Spec.UpdateMode), + ResourcePolicy: containerResourcePolicyConversionFromV1Beta1(src.Spec.ResourcePolicy), + DeletionPolicy: DeletionPolicy(src.Spec.DeletionPolicy), + } + + dst.Status = TortoiseStatus{ + TortoisePhase: TortoisePhase(src.Status.TortoisePhase), + Conditions: Conditions{ + ContainerRecommendationFromVPA: containerRecommendationFromVPAConversionFromV1Beta1(src.Status.Conditions.ContainerRecommendationFromVPA), + }, + Targets: TargetsStatus{ + HorizontalPodAutoscaler: src.Status.Targets.HorizontalPodAutoscaler, + Deployment: src.Status.Targets.ScaleTargetRef.Name, + VerticalPodAutoscalers: verticalPodAutoscalersConversionFromV1Beta1(src.Status.Targets.VerticalPodAutoscalers), + }, + Recommendations: Recommendations{ + Horizontal: HorizontalRecommendations{ + TargetUtilizations: hPATargetUtilizationRecommendationPerContainerConversionFromV1Beta1(src.Status.Recommendations.Horizontal.TargetUtilizations), + MaxReplicas: replicasRecommendationConversionFromV1Beta1(src.Status.Recommendations.Horizontal.MaxReplicas), + MinReplicas: replicasRecommendationConversionFromV1Beta1(src.Status.Recommendations.Horizontal.MinReplicas), + }, + Vertical: VerticalRecommendations{ + ContainerResourceRecommendation: containerResourceRecommendationConversionFromV1Beta1(src.Status.Recommendations.Vertical.ContainerResourceRecommendation), + }, + }, + } + return nil +} + +func verticalPodAutoscalersConversionFromV1Beta1(vpas []v1beta2.TargetStatusVerticalPodAutoscaler) []TargetStatusVerticalPodAutoscaler { + converted := make([]TargetStatusVerticalPodAutoscaler, 0, len(vpas)) + for _, vpa := range vpas { + converted = append(converted, TargetStatusVerticalPodAutoscaler{ + Name: vpa.Name, + Role: VerticalPodAutoscalerRole(vpa.Role), + }) + } + return converted +} + +func verticalPodAutoscalersConversionToV1Beta1(vpas []TargetStatusVerticalPodAutoscaler) []v1beta2.TargetStatusVerticalPodAutoscaler { + converted := make([]v1beta2.TargetStatusVerticalPodAutoscaler, 0, len(vpas)) + for _, vpa := range vpas { + converted = append(converted, v1beta2.TargetStatusVerticalPodAutoscaler{ + Name: vpa.Name, + Role: v1beta2.VerticalPodAutoscalerRole(vpa.Role), + }) + } + return converted +} + +func containerResourceRecommendationConversionFromV1Beta1(resources []v1beta2.RecommendedContainerResources) []RecommendedContainerResources { + converted := make([]RecommendedContainerResources, 0, len(resources)) + for _, resource := range resources { + converted = append(converted, RecommendedContainerResources{ + ContainerName: resource.ContainerName, + RecommendedResource: resource.RecommendedResource, + }) + } + return converted +} + +func containerResourceRecommendationConversionToV1Beta1(resources []RecommendedContainerResources) []v1beta2.RecommendedContainerResources { + converted := make([]v1beta2.RecommendedContainerResources, 0, len(resources)) + for _, resource := range resources { + converted = append(converted, v1beta2.RecommendedContainerResources{ + ContainerName: resource.ContainerName, + RecommendedResource: resource.RecommendedResource, + }) + } + return converted +} + +func replicasRecommendationConversionFromV1Beta1(recommendations []v1beta2.ReplicasRecommendation) []ReplicasRecommendation { + converted := make([]ReplicasRecommendation, 0, len(recommendations)) + for _, recommendation := range recommendations { + converted = append(converted, ReplicasRecommendation{ + From: recommendation.From, + To: recommendation.To, + WeekDay: recommendation.WeekDay, + TimeZone: recommendation.TimeZone, + Value: recommendation.Value, + UpdatedAt: recommendation.UpdatedAt, + }) + } + return converted +} + +func replicasRecommendationConversionToV1Beta1(recommendations []ReplicasRecommendation) []v1beta2.ReplicasRecommendation { + converted := make([]v1beta2.ReplicasRecommendation, 0, len(recommendations)) + for _, recommendation := range recommendations { + converted = append(converted, v1beta2.ReplicasRecommendation{ + From: recommendation.From, + To: recommendation.To, + WeekDay: recommendation.WeekDay, + TimeZone: recommendation.TimeZone, + Value: recommendation.Value, + UpdatedAt: recommendation.UpdatedAt, + }) + } + return converted +} + +func hPATargetUtilizationRecommendationPerContainerConversionFromV1Beta1(recommendations []v1beta2.HPATargetUtilizationRecommendationPerContainer) []HPATargetUtilizationRecommendationPerContainer { + converted := make([]HPATargetUtilizationRecommendationPerContainer, 0, len(recommendations)) + for _, recommendation := range recommendations { + converted = append(converted, HPATargetUtilizationRecommendationPerContainer{ + ContainerName: recommendation.ContainerName, + TargetUtilization: recommendation.TargetUtilization, + }) + } + return converted +} + +func hPATargetUtilizationRecommendationPerContainerConversionToV1Beta1(recommendations []HPATargetUtilizationRecommendationPerContainer) []v1beta2.HPATargetUtilizationRecommendationPerContainer { + converted := make([]v1beta2.HPATargetUtilizationRecommendationPerContainer, 0, len(recommendations)) + for _, recommendation := range recommendations { + converted = append(converted, v1beta2.HPATargetUtilizationRecommendationPerContainer{ + ContainerName: recommendation.ContainerName, + TargetUtilization: recommendation.TargetUtilization, + }) + } + return converted +} + +func containerRecommendationFromVPAConversionFromV1Beta1(conditions []v1beta2.ContainerRecommendationFromVPA) []ContainerRecommendationFromVPA { + converted := make([]ContainerRecommendationFromVPA, 0, len(conditions)) + for _, condition := range conditions { + converted = append(converted, ContainerRecommendationFromVPA{ + ContainerName: condition.ContainerName, + MaxRecommendation: resourceQuantityMapConversionFromV1Beta1(condition.MaxRecommendation), + Recommendation: resourceQuantityMapConversionFromV1Beta1(condition.Recommendation), + }) + } + return converted +} + +func containerRecommendationFromVPAConversionToV1Beta1(conditions []ContainerRecommendationFromVPA) []v1beta2.ContainerRecommendationFromVPA { + converted := make([]v1beta2.ContainerRecommendationFromVPA, 0, len(conditions)) + for _, condition := range conditions { + converted = append(converted, v1beta2.ContainerRecommendationFromVPA{ + ContainerName: condition.ContainerName, + MaxRecommendation: resourceQuantityMapConversionToV1Beta1(condition.MaxRecommendation), + Recommendation: resourceQuantityMapConversionToV1Beta1(condition.Recommendation), + }) + } + return converted +} + +func resourceQuantityMapConversionFromV1Beta1(resources map[v1.ResourceName]v1beta2.ResourceQuantity) map[v1.ResourceName]ResourceQuantity { + converted := make(map[v1.ResourceName]ResourceQuantity, len(resources)) + for k, v := range resources { + converted[k] = ResourceQuantity(v) + } + return converted +} + +func resourceQuantityMapConversionToV1Beta1(resources map[v1.ResourceName]ResourceQuantity) map[v1.ResourceName]v1beta2.ResourceQuantity { + converted := make(map[v1.ResourceName]v1beta2.ResourceQuantity, len(resources)) + for k, v := range resources { + converted[k] = v1beta2.ResourceQuantity(v) + } + return converted +} + +func containerResourcePolicyConversionFromV1Beta1(policies []v1beta2.ContainerResourcePolicy) []ContainerResourcePolicy { + converted := make([]ContainerResourcePolicy, 0, len(policies)) + for _, policy := range policies { + converted = append(converted, ContainerResourcePolicy{ + ContainerName: policy.ContainerName, + MinAllocatedResources: policy.MinAllocatedResources, + AutoscalingPolicy: autoscalingPolicyConversionFromV1Beta1(policy.AutoscalingPolicy), + }) + } + return converted +} + +func containerResourcePolicyConversionToV1Beta1(policies []ContainerResourcePolicy) []v1beta2.ContainerResourcePolicy { + converted := make([]v1beta2.ContainerResourcePolicy, 0, len(policies)) + for _, policy := range policies { + converted = append(converted, v1beta2.ContainerResourcePolicy{ + ContainerName: policy.ContainerName, + MinAllocatedResources: policy.MinAllocatedResources, + AutoscalingPolicy: autoscalingPolicyConversionToV1Beta1(policy.AutoscalingPolicy), + }) + } + return converted +} + +func autoscalingPolicyConversionFromV1Beta1(policies map[v1.ResourceName]v1beta2.AutoscalingType) map[v1.ResourceName]AutoscalingType { + converted := make(map[v1.ResourceName]AutoscalingType, len(policies)) + for k, v := range policies { + converted[k] = AutoscalingType(v) + } + return converted +} + +func autoscalingPolicyConversionToV1Beta1(policies map[v1.ResourceName]AutoscalingType) map[v1.ResourceName]v1beta2.AutoscalingType { + converted := make(map[v1.ResourceName]v1beta2.AutoscalingType, len(policies)) + for k, v := range policies { + converted[k] = v1beta2.AutoscalingType(v) + } + return converted +} diff --git a/api/v1beta1/tortoise_types.go b/api/v1beta1/tortoise_types.go index fde40524..491f709c 100644 --- a/api/v1beta1/tortoise_types.go +++ b/api/v1beta1/tortoise_types.go @@ -335,7 +335,6 @@ type ResourceQuantity struct { } //+kubebuilder:object:root=true -//+kubebuilder:storageversion //+kubebuilder:subresource:status //+kubebuilder:printcolumn:name="MODE",type="string",JSONPath=".spec.updateMode" //+kubebuilder:printcolumn:name="PHASE",type="string",JSONPath=".status.tortoisePhase" diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index b1b62c16..6f1dc177 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -31,7 +31,7 @@ package v1beta1 import ( "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" + runtime "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. diff --git a/api/v1beta2/groupversion_info.go b/api/v1beta2/groupversion_info.go new file mode 100644 index 00000000..0179fcc9 --- /dev/null +++ b/api/v1beta2/groupversion_info.go @@ -0,0 +1,45 @@ +/* +MIT License + +Copyright (c) 2023 mercari + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// Package v1beta2 contains API Schema definitions for the autoscaling v1beta2 API group +// +kubebuilder:object:generate=true +// +groupName=autoscaling.mercari.com +package v1beta2 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "autoscaling.mercari.com", Version: "v1beta2"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/v1beta1/service.go b/api/v1beta2/service.go similarity index 98% rename from api/v1beta1/service.go rename to api/v1beta2/service.go index 64597815..49824558 100644 --- a/api/v1beta1/service.go +++ b/api/v1beta2/service.go @@ -1,4 +1,4 @@ -package v1beta1 +package v1beta2 import ( "context" diff --git a/api/v1beta1/testdata/mutating/after.yaml b/api/v1beta2/testdata/mutating/after.yaml similarity index 90% rename from api/v1beta1/testdata/mutating/after.yaml rename to api/v1beta2/testdata/mutating/after.yaml index 91ab691c..ee722d8b 100644 --- a/api/v1beta1/testdata/mutating/after.yaml +++ b/api/v1beta2/testdata/mutating/after.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta1/testdata/mutating/before.yaml b/api/v1beta2/testdata/mutating/before.yaml similarity index 77% rename from api/v1beta1/testdata/mutating/before.yaml rename to api/v1beta2/testdata/mutating/before.yaml index 23de87e3..a2c1c522 100644 --- a/api/v1beta1/testdata/mutating/before.yaml +++ b/api/v1beta2/testdata/mutating/before.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta1/testdata/mutating/deployment.yaml b/api/v1beta2/testdata/mutating/deployment.yaml similarity index 100% rename from api/v1beta1/testdata/mutating/deployment.yaml rename to api/v1beta2/testdata/mutating/deployment.yaml diff --git a/api/v1beta1/testdata/validating/hpa-specified-but-no-horizontal/deployment.yaml b/api/v1beta2/testdata/validating/hpa-specified-but-no-horizontal/deployment.yaml similarity index 100% rename from api/v1beta1/testdata/validating/hpa-specified-but-no-horizontal/deployment.yaml rename to api/v1beta2/testdata/validating/hpa-specified-but-no-horizontal/deployment.yaml diff --git a/api/v1beta1/testdata/validating/hpa-specified-but-no-horizontal/hpa.yaml b/api/v1beta2/testdata/validating/hpa-specified-but-no-horizontal/hpa.yaml similarity index 100% rename from api/v1beta1/testdata/validating/hpa-specified-but-no-horizontal/hpa.yaml rename to api/v1beta2/testdata/validating/hpa-specified-but-no-horizontal/hpa.yaml diff --git a/api/v1beta1/testdata/validating/hpa-specified-but-no-horizontal/tortoise.yaml b/api/v1beta2/testdata/validating/hpa-specified-but-no-horizontal/tortoise.yaml similarity index 91% rename from api/v1beta1/testdata/validating/hpa-specified-but-no-horizontal/tortoise.yaml rename to api/v1beta2/testdata/validating/hpa-specified-but-no-horizontal/tortoise.yaml index df9955bf..7fda7623 100644 --- a/api/v1beta1/testdata/validating/hpa-specified-but-no-horizontal/tortoise.yaml +++ b/api/v1beta2/testdata/validating/hpa-specified-but-no-horizontal/tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta1/testdata/validating/no-horizontal-in-tortoise/deployment.yaml b/api/v1beta2/testdata/validating/no-horizontal-in-tortoise/deployment.yaml similarity index 100% rename from api/v1beta1/testdata/validating/no-horizontal-in-tortoise/deployment.yaml rename to api/v1beta2/testdata/validating/no-horizontal-in-tortoise/deployment.yaml diff --git a/api/v1beta1/testdata/validating/no-horizontal-in-tortoise/hpa.yaml b/api/v1beta2/testdata/validating/no-horizontal-in-tortoise/hpa.yaml similarity index 100% rename from api/v1beta1/testdata/validating/no-horizontal-in-tortoise/hpa.yaml rename to api/v1beta2/testdata/validating/no-horizontal-in-tortoise/hpa.yaml diff --git a/api/v1beta1/testdata/validating/no-horizontal-in-tortoise/tortoise.yaml b/api/v1beta2/testdata/validating/no-horizontal-in-tortoise/tortoise.yaml similarity index 91% rename from api/v1beta1/testdata/validating/no-horizontal-in-tortoise/tortoise.yaml rename to api/v1beta2/testdata/validating/no-horizontal-in-tortoise/tortoise.yaml index 34bbecdd..70650b1c 100644 --- a/api/v1beta1/testdata/validating/no-horizontal-in-tortoise/tortoise.yaml +++ b/api/v1beta2/testdata/validating/no-horizontal-in-tortoise/tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta1/testdata/validating/no-horizontal-with-hpa/before-tortoise.yaml b/api/v1beta2/testdata/validating/no-horizontal-with-hpa/before-tortoise.yaml similarity index 91% rename from api/v1beta1/testdata/validating/no-horizontal-with-hpa/before-tortoise.yaml rename to api/v1beta2/testdata/validating/no-horizontal-with-hpa/before-tortoise.yaml index 2b9ce752..a70a2227 100644 --- a/api/v1beta1/testdata/validating/no-horizontal-with-hpa/before-tortoise.yaml +++ b/api/v1beta2/testdata/validating/no-horizontal-with-hpa/before-tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta1/testdata/validating/no-horizontal-with-hpa/deployment.yaml b/api/v1beta2/testdata/validating/no-horizontal-with-hpa/deployment.yaml similarity index 100% rename from api/v1beta1/testdata/validating/no-horizontal-with-hpa/deployment.yaml rename to api/v1beta2/testdata/validating/no-horizontal-with-hpa/deployment.yaml diff --git a/api/v1beta1/testdata/validating/no-horizontal-with-hpa/hpa.yaml b/api/v1beta2/testdata/validating/no-horizontal-with-hpa/hpa.yaml similarity index 100% rename from api/v1beta1/testdata/validating/no-horizontal-with-hpa/hpa.yaml rename to api/v1beta2/testdata/validating/no-horizontal-with-hpa/hpa.yaml diff --git a/api/v1beta1/testdata/validating/no-horizontal-with-hpa/updating-tortoise.yaml b/api/v1beta2/testdata/validating/no-horizontal-with-hpa/updating-tortoise.yaml similarity index 91% rename from api/v1beta1/testdata/validating/no-horizontal-with-hpa/updating-tortoise.yaml rename to api/v1beta2/testdata/validating/no-horizontal-with-hpa/updating-tortoise.yaml index 6426ad71..4d74a2ba 100644 --- a/api/v1beta1/testdata/validating/no-horizontal-with-hpa/updating-tortoise.yaml +++ b/api/v1beta2/testdata/validating/no-horizontal-with-hpa/updating-tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta1/testdata/validating/no-horizontal-with-no-deletion/before-tortoise.yaml b/api/v1beta2/testdata/validating/no-horizontal-with-no-deletion/before-tortoise.yaml similarity index 90% rename from api/v1beta1/testdata/validating/no-horizontal-with-no-deletion/before-tortoise.yaml rename to api/v1beta2/testdata/validating/no-horizontal-with-no-deletion/before-tortoise.yaml index 91ab691c..ee722d8b 100644 --- a/api/v1beta1/testdata/validating/no-horizontal-with-no-deletion/before-tortoise.yaml +++ b/api/v1beta2/testdata/validating/no-horizontal-with-no-deletion/before-tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta1/testdata/validating/no-horizontal-with-no-deletion/deployment.yaml b/api/v1beta2/testdata/validating/no-horizontal-with-no-deletion/deployment.yaml similarity index 100% rename from api/v1beta1/testdata/validating/no-horizontal-with-no-deletion/deployment.yaml rename to api/v1beta2/testdata/validating/no-horizontal-with-no-deletion/deployment.yaml diff --git a/api/v1beta1/testdata/validating/no-horizontal-with-no-deletion/hpa.yaml b/api/v1beta2/testdata/validating/no-horizontal-with-no-deletion/hpa.yaml similarity index 100% rename from api/v1beta1/testdata/validating/no-horizontal-with-no-deletion/hpa.yaml rename to api/v1beta2/testdata/validating/no-horizontal-with-no-deletion/hpa.yaml diff --git a/api/v1beta1/testdata/validating/no-horizontal-with-no-deletion/updating-tortoise.yaml b/api/v1beta2/testdata/validating/no-horizontal-with-no-deletion/updating-tortoise.yaml similarity index 90% rename from api/v1beta1/testdata/validating/no-horizontal-with-no-deletion/updating-tortoise.yaml rename to api/v1beta2/testdata/validating/no-horizontal-with-no-deletion/updating-tortoise.yaml index 5fca8cbe..fc70dda1 100644 --- a/api/v1beta1/testdata/validating/no-horizontal-with-no-deletion/updating-tortoise.yaml +++ b/api/v1beta2/testdata/validating/no-horizontal-with-no-deletion/updating-tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta1/testdata/validating/no-metric-in-hpa/deployment.yaml b/api/v1beta2/testdata/validating/no-metric-in-hpa/deployment.yaml similarity index 100% rename from api/v1beta1/testdata/validating/no-metric-in-hpa/deployment.yaml rename to api/v1beta2/testdata/validating/no-metric-in-hpa/deployment.yaml diff --git a/api/v1beta1/testdata/validating/no-metric-in-hpa/hpa.yaml b/api/v1beta2/testdata/validating/no-metric-in-hpa/hpa.yaml similarity index 100% rename from api/v1beta1/testdata/validating/no-metric-in-hpa/hpa.yaml rename to api/v1beta2/testdata/validating/no-metric-in-hpa/hpa.yaml diff --git a/api/v1beta1/testdata/validating/success/tortoise.yaml b/api/v1beta2/testdata/validating/no-metric-in-hpa/tortoise.yaml similarity index 91% rename from api/v1beta1/testdata/validating/success/tortoise.yaml rename to api/v1beta2/testdata/validating/no-metric-in-hpa/tortoise.yaml index feb5dd5e..0ae3caab 100644 --- a/api/v1beta1/testdata/validating/success/tortoise.yaml +++ b/api/v1beta2/testdata/validating/no-metric-in-hpa/tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta1/testdata/validating/success-remove-all-horizontal/deployment.yaml b/api/v1beta2/testdata/validating/not-targetting-deployment/deployment.yaml similarity index 100% rename from api/v1beta1/testdata/validating/success-remove-all-horizontal/deployment.yaml rename to api/v1beta2/testdata/validating/not-targetting-deployment/deployment.yaml diff --git a/api/v1beta1/testdata/validating/success-remove-all-horizontal/hpa.yaml b/api/v1beta2/testdata/validating/not-targetting-deployment/hpa.yaml similarity index 100% rename from api/v1beta1/testdata/validating/success-remove-all-horizontal/hpa.yaml rename to api/v1beta2/testdata/validating/not-targetting-deployment/hpa.yaml diff --git a/api/v1beta2/testdata/validating/not-targetting-deployment/tortoise.yaml b/api/v1beta2/testdata/validating/not-targetting-deployment/tortoise.yaml new file mode 100644 index 00000000..da5cf2b4 --- /dev/null +++ b/api/v1beta2/testdata/validating/not-targetting-deployment/tortoise.yaml @@ -0,0 +1,22 @@ +apiVersion: autoscaling.mercari.com/v1beta2 +kind: Tortoise +metadata: + name: tortoise-sample + namespace: default +spec: + updateMode: "Off" + deletionPolicy: "DeleteAll" + targetRefs: + horizontalPodAutoscalerName: sample + scaleTargetRef: + kind: ReplicaSet + name: sample + resourcePolicy: + - containerName: istio-proxy + autoscalingPolicy: + cpu: Horizontal + memory: Vertical + - containerName: nginx + autoscalingPolicy: + cpu: Horizontal + memory: Vertical \ No newline at end of file diff --git a/api/v1beta1/testdata/validating/success-remove-all-horizontal/before-tortoise.yaml b/api/v1beta2/testdata/validating/success-remove-all-horizontal/before-tortoise.yaml similarity index 91% rename from api/v1beta1/testdata/validating/success-remove-all-horizontal/before-tortoise.yaml rename to api/v1beta2/testdata/validating/success-remove-all-horizontal/before-tortoise.yaml index a609d33a..33ffc497 100644 --- a/api/v1beta1/testdata/validating/success-remove-all-horizontal/before-tortoise.yaml +++ b/api/v1beta2/testdata/validating/success-remove-all-horizontal/before-tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta1/testdata/validating/success/deployment.yaml b/api/v1beta2/testdata/validating/success-remove-all-horizontal/deployment.yaml similarity index 100% rename from api/v1beta1/testdata/validating/success/deployment.yaml rename to api/v1beta2/testdata/validating/success-remove-all-horizontal/deployment.yaml diff --git a/api/v1beta1/testdata/validating/success/hpa.yaml b/api/v1beta2/testdata/validating/success-remove-all-horizontal/hpa.yaml similarity index 100% rename from api/v1beta1/testdata/validating/success/hpa.yaml rename to api/v1beta2/testdata/validating/success-remove-all-horizontal/hpa.yaml diff --git a/api/v1beta1/testdata/validating/success-remove-all-horizontal/updating-tortoise.yaml b/api/v1beta2/testdata/validating/success-remove-all-horizontal/updating-tortoise.yaml similarity index 90% rename from api/v1beta1/testdata/validating/success-remove-all-horizontal/updating-tortoise.yaml rename to api/v1beta2/testdata/validating/success-remove-all-horizontal/updating-tortoise.yaml index 216bec5e..24eb4f95 100644 --- a/api/v1beta1/testdata/validating/success-remove-all-horizontal/updating-tortoise.yaml +++ b/api/v1beta2/testdata/validating/success-remove-all-horizontal/updating-tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta1/testdata/validating/useless-policy/deployment.yaml b/api/v1beta2/testdata/validating/success/deployment.yaml similarity index 100% rename from api/v1beta1/testdata/validating/useless-policy/deployment.yaml rename to api/v1beta2/testdata/validating/success/deployment.yaml diff --git a/api/v1beta1/testdata/validating/useless-policy/hpa.yaml b/api/v1beta2/testdata/validating/success/hpa.yaml similarity index 100% rename from api/v1beta1/testdata/validating/useless-policy/hpa.yaml rename to api/v1beta2/testdata/validating/success/hpa.yaml diff --git a/api/v1beta1/testdata/validating/no-metric-in-hpa/tortoise.yaml b/api/v1beta2/testdata/validating/success/tortoise.yaml similarity index 91% rename from api/v1beta1/testdata/validating/no-metric-in-hpa/tortoise.yaml rename to api/v1beta2/testdata/validating/success/tortoise.yaml index feb5dd5e..0ae3caab 100644 --- a/api/v1beta1/testdata/validating/no-metric-in-hpa/tortoise.yaml +++ b/api/v1beta2/testdata/validating/success/tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1beta2/testdata/validating/useless-policy/deployment.yaml b/api/v1beta2/testdata/validating/useless-policy/deployment.yaml new file mode 100644 index 00000000..d431d7f5 --- /dev/null +++ b/api/v1beta2/testdata/validating/useless-policy/deployment.yaml @@ -0,0 +1,26 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sample + namespace: default + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: istio-proxy + image: istio-proxy:1.0.0 + ports: + - containerPort: 81 + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 \ No newline at end of file diff --git a/api/v1beta2/testdata/validating/useless-policy/hpa.yaml b/api/v1beta2/testdata/validating/useless-policy/hpa.yaml new file mode 100644 index 00000000..fa1875c6 --- /dev/null +++ b/api/v1beta2/testdata/validating/useless-policy/hpa.yaml @@ -0,0 +1,27 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: sample + namespace: default +spec: + maxReplicas: 10 + metrics: + - type: ContainerResource + containerResource: + name: cpu + container: nginx + target: + type: Utilization + averageUtilization: 60 + - type: ContainerResource + containerResource: + name: cpu + container: istio-proxy + target: + type: Utilization + averageUtilization: 60 + minReplicas: 3 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: sample \ No newline at end of file diff --git a/api/v1beta1/testdata/validating/useless-policy/tortoise.yaml b/api/v1beta2/testdata/validating/useless-policy/tortoise.yaml similarity index 92% rename from api/v1beta1/testdata/validating/useless-policy/tortoise.yaml rename to api/v1beta2/testdata/validating/useless-policy/tortoise.yaml index d26fee5e..a0f3acc0 100644 --- a/api/v1beta1/testdata/validating/useless-policy/tortoise.yaml +++ b/api/v1beta2/testdata/validating/useless-policy/tortoise.yaml @@ -1,4 +1,4 @@ -apiVersion: autoscaling.mercari.com/v1beta1 +apiVersion: autoscaling.mercari.com/v1beta2 kind: Tortoise metadata: name: tortoise-sample diff --git a/api/v1alpha1/tortoise_webhook.go b/api/v1beta2/tortoise_conversion.go similarity index 79% rename from api/v1alpha1/tortoise_webhook.go rename to api/v1beta2/tortoise_conversion.go index cb4f8bdb..8d12bf1b 100644 --- a/api/v1alpha1/tortoise_webhook.go +++ b/api/v1beta2/tortoise_conversion.go @@ -23,16 +23,7 @@ SOFTWARE. */ -package v1alpha1 +package v1beta2 -import ( - ctrl "sigs.k8s.io/controller-runtime" -) - -func (r *Tortoise) SetupWebhookWithManager(mgr ctrl.Manager) error { - return ctrl.NewWebhookManagedBy(mgr). - For(r). - Complete() -} - -// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// Hub marks this type as a conversion hub. +func (*Tortoise) Hub() {} diff --git a/api/v1beta2/tortoise_types.go b/api/v1beta2/tortoise_types.go new file mode 100644 index 00000000..8ebfda0c --- /dev/null +++ b/api/v1beta2/tortoise_types.go @@ -0,0 +1,363 @@ +/* +MIT License + +Copyright (c) 2023 mercari + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +package v1beta2 + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster +// Important: Run "make" to regenerate code after modifying this file + +// TortoiseSpec defines the desired state of Tortoise +type TortoiseSpec struct { + // TargetRefs has reference to involved resources. + TargetRefs TargetRefs `json:"targetRefs" protobuf:"bytes,1,name=targetRefs"` + // UpdateMode is how tortoise update resources. + // If "Off", tortoise generates the recommendations in .Status, but doesn't apply it actually. + // If "Auto", tortoise generates the recommendations in .Status, and apply it to resources. + // If "Emergency", tortoise generates the recommendations in .Status as usual, but increase replica number high enough value. + // "Emergency" is useful when something unexpected happens in workloads, and you want to scale up the workload with high enough resources. + // See https://github.com/mercari/tortoise/blob/main/docs/emergency.md to know more about emergency mode. + // + // "Off" is the default value. + // +optional + UpdateMode UpdateMode `json:"updateMode,omitempty" protobuf:"bytes,2,opt,name=updateMode"` + // ResourcePolicy contains the policy how each resource is updated. + // +optional + ResourcePolicy []ContainerResourcePolicy `json:"resourcePolicy,omitempty" protobuf:"bytes,3,opt,name=resourcePolicy"` + // DeletionPolicy is the policy how the controller deletes associated HPA and VPAs when tortoise is removed. + // If "DeleteAll", tortoise deletes all associated HPA and VPAs, created by tortoise. If the associated HPA is not created by tortoise, + // which is associated by spec.targetRefs.horizontalPodAutoscalerName, tortoise never delete the HPA. + // If "NoDelete", tortoise doesn't delete any associated HPA and VPAs. + // + // "NoDelete" is the default value. + // +optional + DeletionPolicy DeletionPolicy `json:"deletionPolicy,omitempty" protobuf:"bytes,4,opt,name=deletionPolicy"` +} + +type ContainerResourcePolicy struct { + // ContainerName is the name of target container. + ContainerName string `json:"containerName" protobuf:"bytes,1,name=containerName"` + // MinAllocatedResources is the minimum amount of resources which is given to the container. + // Tortoise never set the resources request on the container than MinAllocatedResources. + // + // If empty, tortoise may reduce the resource request to the value which is suggested from VPA. + // Leaving this field empty is basically safe, but you may consider using MinAllocatedResources when maybe your application will consume resources more than usual, + // given the VPA suggests values based on the historical resource usage. + // For example, your application will soon have new feature which leads to increase in the resource usage, + // it is expected that your application will soon get more requests than usual, etc. + // +optional + MinAllocatedResources v1.ResourceList `json:"minAllocatedResources,omitempty" protobuf:"bytes,2,opt,name=minAllocatedResources"` + // AutoscalingPolicy specifies how each resource is scaled. + // If "Horizontal", the resource is horizontally scaled. + // If "Vertical", the resource is vertically scaled. + // If "Off", tortoise doesn't scale at all based on that resource. + // + // The default value is "Horizontal" for cpu, and "Vertical" for memory. + // +optional + AutoscalingPolicy map[v1.ResourceName]AutoscalingType `json:"autoscalingPolicy,omitempty" protobuf:"bytes,3,opt,name=autoscalingPolicy"` +} + +// +kubebuilder:validation:Enum=DeleteAll;NoDelete +type DeletionPolicy string + +const ( + DeletionPolicyDeleteAll DeletionPolicy = "DeleteAll" + DeletionPolicyNoDelete DeletionPolicy = "NoDelete" +) + +// +kubebuilder:validation:Enum=Off;Auto;Emergency +type UpdateMode string + +const ( + UpdateModeOff UpdateMode = "Off" + UpdateModeEmergency UpdateMode = "Emergency" + UpdateModeAuto UpdateMode = "Auto" +) + +// +kubebuilder:validation:Enum=Off;Horizontal;Vertical +type AutoscalingType string + +const ( + AutoscalingTypeOff AutoscalingType = "Off" + AutoscalingTypeHorizontal AutoscalingType = "Horizontal" + AutoscalingTypeVertical AutoscalingType = "Vertical" +) + +type TargetRefs struct { + // ScaleTargetRef is the target of scaling. + // It should be the same as the target of HPA. + ScaleTargetRef CrossVersionObjectReference `json:"scaleTargetRef" protobuf:"bytes,1,name=scaleTargetRef"` + // HorizontalPodAutoscalerName is the name of the target HPA. + // The target of this HPA should be the same as the ScaleTargetRef above. + // The target HPA should have the ContainerResource type metric or the external metric refers to the container resource utilization. + // Please check out the document for more detail: https://github.com/mercari/tortoise/blob/master/docs/horizontal.md#supported-metrics-in-hpa + // + // You can specify either of existing HPA only. + // This is an optional field, and if you don't specify this field, tortoise will create a new default HPA named `tortoise-hpa-{tortoise name}`. + // +optional + HorizontalPodAutoscalerName *string `json:"horizontalPodAutoscalerName,omitempty" protobuf:"bytes,2,opt,name=horizontalPodAutoscalerName"` +} + +// CrossVersionObjectReference contains enough information toet identify the referred resource. +type CrossVersionObjectReference struct { + // kind is the kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind" protobuf:"bytes,1,opt,name=kind"` + + // name is the name of the referent; More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + Name string `json:"name" protobuf:"bytes,2,opt,name=name"` + + // apiVersion is the API version of the referent + // +optional + APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,3,opt,name=apiVersion"` +} + +// TortoiseStatus defines the observed state of Tortoise +type TortoiseStatus struct { + TortoisePhase TortoisePhase `json:"tortoisePhase" protobuf:"bytes,1,name=tortoisePhase"` + Conditions Conditions `json:"conditions" protobuf:"bytes,2,name=conditions"` + Recommendations Recommendations `json:"recommendations" protobuf:"bytes,3,name=recommendations"` + Targets TargetsStatus `json:"targets" protobuf:"bytes,4,name=targets"` + ContainerResourcePhases []ContainerResourcePhases `json:"containerResourcePhases" protobuf:"bytes,5,name=containerResourcePhases"` +} + +type ContainerResourcePhases struct { + // ContainerName is the name of target container. + ContainerName string `json:"containerName" protobuf:"bytes,1,name=containerName"` + // ResourcePhases is the phase of each resource of this container. + ResourcePhases map[v1.ResourceName]ResourcePhase `json:"resourcePhases" protobuf:"bytes,2,name=resourcePhases"` +} + +type ResourcePhase struct { + Phase ContainerResourcePhase `json:"phase" protobuf:"bytes,1,name=phase"` + // lastTransitionTime is the last time the condition transitioned from + // one status to another + // +optional + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,2,opt,name=lastTransitionTime"` +} + +type ContainerResourcePhase string + +const ( + ContainerResourcePhaseGatheringData ContainerResourcePhase = "GatheringData" + ContainerResourcePhaseWorking ContainerResourcePhase = "Working" + ContainerResourcePhaseOff ContainerResourcePhase = "Off" +) + +type TortoisePhase string + +const ( + // TortoisePhaseInitializing means tortoise is just created and initializing some components (HPA and VPAs), + // and wait for those components to be ready. + TortoisePhaseInitializing TortoisePhase = "Initializing" + // TortoisePhaseGatheringData means tortoise is now gathering data and cannot make the accurate recommendations. + TortoisePhaseGatheringData TortoisePhase = "GatheringData" + // TortoisePhaseWorking means tortoise is making the recommendations, + // and applying the recommendation values. + TortoisePhaseWorking TortoisePhase = "Working" + // TortoisePhasePartlyWorking means tortoise has maxReplicas and minReplicas recommendations ready, + // and applying the recommendation values. + // But, some of the resources are not scaled due to some reasons. (probably still gathering data) + TortoisePhasePartlyWorking TortoisePhase = "PartlyWorking" + // TortoisePhaseEmergency means tortoise is in the emergency mode. + TortoisePhaseEmergency TortoisePhase = "Emergency" + // TortoisePhaseBackToNormal means tortoise was in the emergency mode, and now it's coming back to the normal operation. + // During TortoisePhaseBackToNormal, the number of replicas of workloads are gradually reduced to the usual value. + TortoisePhaseBackToNormal TortoisePhase = "BackToNormal" +) + +type TargetsStatus struct { + // +optional + HorizontalPodAutoscaler string `json:"horizontalPodAutoscaler" protobuf:"bytes,1,opt,name=horizontalPodAutoscaler"` + ScaleTargetRef CrossVersionObjectReference `json:"scaleTargetRef" protobuf:"bytes,2,name=scaleTargetRef"` + VerticalPodAutoscalers []TargetStatusVerticalPodAutoscaler `json:"verticalPodAutoscalers" protobuf:"bytes,3,name=verticalPodAutoscalers"` +} + +type TargetStatusVerticalPodAutoscaler struct { + Name string `json:"name" protobuf:"bytes,1,name=name"` + Role VerticalPodAutoscalerRole `json:"role" protobuf:"bytes,2,name=role"` +} + +// +kubebuilder:validation:Enum=Updater;Monitor +type VerticalPodAutoscalerRole string + +const ( + VerticalPodAutoscalerRoleUpdater = "Updater" + VerticalPodAutoscalerRoleMonitor = "Monitor" +) + +type Recommendations struct { + // +optional + Horizontal HorizontalRecommendations `json:"horizontal,omitempty" protobuf:"bytes,1,opt,name=horizontal"` + // +optional + Vertical VerticalRecommendations `json:"vertical,omitempty" protobuf:"bytes,2,opt,name=vertical"` +} + +type VerticalRecommendations struct { + // +optional + ContainerResourceRecommendation []RecommendedContainerResources `json:"containerResourceRecommendation" protobuf:"bytes,1,name=containerResourceRecommendation"` +} + +type RecommendedContainerResources struct { + // ContainerName is the name of target container. + ContainerName string `json:"containerName" protobuf:"bytes,1,name=containerName"` + // RecommendedResource is the recommendation calculated by the tortoise. + // If AutoscalingPolicy is vertical, it's the same value as the VPA suggests. + // If AutoscalingPolicy is horizontal, it's basically the same value as the current resource request. + // But, when the number of replicas are too small or too large, + // tortoise may try to increase/decrease the amount of resources given to the container, + // so that the number of replicas won't be very small or very large. + RecommendedResource v1.ResourceList `json:"RecommendedResource" protobuf:"bytes,2,name=containerName"` +} + +type HorizontalRecommendations struct { + // +optional + TargetUtilizations []HPATargetUtilizationRecommendationPerContainer `json:"targetUtilizations,omitempty" protobuf:"bytes,1,opt,name=targetUtilizations"` + // MaxReplicas has the recommendation of maxReplicas. + // It contains the recommendations for each time slot. + // +optional + MaxReplicas []ReplicasRecommendation `json:"maxReplicas,omitempty" protobuf:"bytes,2,opt,name=maxReplicas"` + // MinReplicas has the recommendation of minReplicas. + // It contains the recommendations for each time slot. + // +optional + MinReplicas []ReplicasRecommendation `json:"minReplicas,omitempty" protobuf:"bytes,3,opt,name=minReplicas"` +} + +type ReplicasRecommendation struct { + // From represented in hour. + From int `json:"from" protobuf:"variant,1,name=from"` + // To represented in hour. + To int `json:"to" protobuf:"variant,2,name=to"` + // WeekDay is the day of the week. + // If empty, it means it applies to all days of the week. + WeekDay *string `json:"weekday,omitempty" protobuf:"bytes,3,opt,name=weekday"` + TimeZone string `json:"timezone" protobuf:"bytes,4,name=timezone"` + // Value is the recommendation value. + // It's calculated every reconciliation, + // and updated if the calculated recommendation value is more than the current recommendation value on tortoise. + Value int32 `json:"value" protobuf:"variant,5,name=value"` + // +optional + UpdatedAt metav1.Time `json:"updatedAt,omitempty" protobuf:"bytes,6,opt,name=updatedAt"` +} + +type HPATargetUtilizationRecommendationPerContainer struct { + // ContainerName is the name of target container. + ContainerName string `json:"containerName" protobuf:"bytes,1,name=containerName"` + // TargetUtilization is the recommendation of targetUtilization of HPA. + TargetUtilization map[v1.ResourceName]int32 `json:"targetUtilization" protobuf:"bytes,2,name=targetUtilization"` +} + +type Conditions struct { + // TortoiseConditions is the condition of this tortoise. + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // +optional + TortoiseConditions []TortoiseCondition `json:"tortoiseConditions" protobuf:"bytes,1,name=tortoiseConditions"` + // ContainerRecommendationFromVPA is the condition of container recommendation from VPA, which is observed last time. + // +optional + ContainerRecommendationFromVPA []ContainerRecommendationFromVPA `json:"containerRecommendationFromVPA,omitempty" protobuf:"bytes,1,opt,name=containerRecommendationFromVPA"` +} + +// TortoiseConditionType are the valid conditions of a Tortoise. +type TortoiseConditionType string + +const ( + // TortoiseConditionTypeFailedToReconcile means tortoise failed to reconcile due to some reasons. + TortoiseConditionTypeFailedToReconcile TortoiseConditionType = "FailedToReconcile" +) + +type TortoiseCondition struct { + // Type is the type of the condition. + Type TortoiseConditionType `json:"type" protobuf:"bytes,1,name=type"` + // Status is the status of the condition. (True, False, Unknown) + Status v1.ConditionStatus `json:"status" protobuf:"bytes,2,name=status"` + // The last time this condition was updated. + LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty" protobuf:"bytes,6,opt,name=lastUpdateTime"` + // lastTransitionTime is the last time the condition transitioned from + // one status to another + // +optional + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,3,opt,name=lastTransitionTime"` + // reason is the reason for the condition's last transition. + // +optional + Reason string `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"` + // message is a human-readable explanation containing details about + // the transition + // +optional + Message string `json:"message,omitempty" protobuf:"bytes,5,opt,name=message"` +} + +type ContainerRecommendationFromVPA struct { + // ContainerName is the name of target container. + ContainerName string `json:"containerName" protobuf:"bytes,1,name=containerName"` + // MaxRecommendation is the max recommendation value from VPA in a certain period (1 week). + // Tortoise generates all recommendation based on this MaxRecommendation. + MaxRecommendation map[v1.ResourceName]ResourceQuantity `json:"maxRecommendation" protobuf:"bytes,2,name=maxRecommendation"` + // Recommendation is the latest recommendation value from VPA. + Recommendation map[v1.ResourceName]ResourceQuantity `json:"recommendation" protobuf:"bytes,3,name=recommendation"` +} + +type ResourceQuantity struct { + // +optional + Quantity resource.Quantity `json:"quantity,omitempty" protobuf:"bytes,1,opt,name=quantity"` + // +optional + UpdatedAt metav1.Time `json:"updatedAt,omitempty" protobuf:"bytes,2,opt,name=updatedAt"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:storageversion +//+kubebuilder:subresource:status +//+kubebuilder:printcolumn:name="MODE",type="string",JSONPath=".spec.updateMode" +//+kubebuilder:printcolumn:name="PHASE",type="string",JSONPath=".status.tortoisePhase" + +// Tortoise is the Schema for the tortoises API +type Tortoise struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec TortoiseSpec `json:"spec,omitempty"` + Status TortoiseStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// TortoiseList contains a list of Tortoise +type TortoiseList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Tortoise `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Tortoise{}, &TortoiseList{}) +} diff --git a/api/v1beta1/tortoise_webhook.go b/api/v1beta2/tortoise_webhook.go similarity index 96% rename from api/v1beta1/tortoise_webhook.go rename to api/v1beta2/tortoise_webhook.go index ba0e6f77..88854086 100644 --- a/api/v1beta1/tortoise_webhook.go +++ b/api/v1beta2/tortoise_webhook.go @@ -23,7 +23,7 @@ SOFTWARE. */ -package v1beta1 +package v1beta2 import ( "context" @@ -55,7 +55,7 @@ func (r *Tortoise) SetupWebhookWithManager(mgr ctrl.Manager) error { // TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -//+kubebuilder:webhook:path=/mutate-autoscaling-mercari-com-v1beta1-tortoise,mutating=true,failurePolicy=fail,sideEffects=None,groups=autoscaling.mercari.com,resources=tortoises,verbs=create;update,versions=v1beta1,name=mtortoise.kb.io,admissionReviewVersions=v1 +//+kubebuilder:webhook:path=/mutate-autoscaling-mercari-com-v1beta2-tortoise,mutating=true,failurePolicy=fail,sideEffects=None,groups=autoscaling.mercari.com,resources=tortoises,verbs=create;update,versions=v1beta2,name=mtortoise.kb.io,admissionReviewVersions=v1 var _ webhook.Defaulter = &Tortoise{} @@ -77,7 +77,6 @@ func (r *Tortoise) Default() { } if r.Spec.TargetRefs.ScaleTargetRef.Kind == "Deployment" { - // TODO: do the same validation for other resources. d, err := ClientService.GetDeploymentOnTortoise(context.Background(), r) if err != nil { tortoiselog.Error(err, "failed to get deployment") @@ -115,7 +114,7 @@ func (r *Tortoise) Default() { } } -//+kubebuilder:webhook:path=/validate-autoscaling-mercari-com-v1beta1-tortoise,mutating=false,failurePolicy=fail,sideEffects=None,groups=autoscaling.mercari.com,resources=tortoises,verbs=create;update,versions=v1beta1,name=vtortoise.kb.io,admissionReviewVersions=v1 +//+kubebuilder:webhook:path=/validate-autoscaling-mercari-com-v1beta2-tortoise,mutating=false,failurePolicy=fail,sideEffects=None,groups=autoscaling.mercari.com,resources=tortoises,verbs=create;update,versions=v1beta2,name=vtortoise.kb.io,admissionReviewVersions=v1 var _ webhook.Validator = &Tortoise{} @@ -132,13 +131,17 @@ func hasHorizontal(tortoise *Tortoise) bool { func validateTortoise(t *Tortoise) error { fieldPath := field.NewPath("spec") + if t.Spec.TargetRefs.ScaleTargetRef.Kind == "" { + return fmt.Errorf("%s: shouldn't be empty", fieldPath.Child("targetRefs", "scaleTargetRef", "kind")) + } + + if t.Spec.TargetRefs.ScaleTargetRef.Kind != "Deployment" { + return fmt.Errorf("%s: only Deployment is supported now", fieldPath.Child("targetRefs", "scaleTargetRef", "kind")) + } if t.Spec.TargetRefs.ScaleTargetRef.Name == "" { return fmt.Errorf("%s: shouldn't be empty", fieldPath.Child("targetRefs", "scaleTargetRef", "name")) } - if t.Spec.TargetRefs.ScaleTargetRef.Kind == "" { - return fmt.Errorf("%s: shouldn't be empty", fieldPath.Child("targetRefs", "scaleTargetRef", "kind")) - } if t.Spec.UpdateMode == UpdateModeEmergency && t.Status.TortoisePhase != TortoisePhaseWorking && t.Status.TortoisePhase != TortoisePhaseEmergency && t.Status.TortoisePhase != TortoisePhaseBackToNormal { diff --git a/api/v1beta1/tortoise_webhook_test.go b/api/v1beta2/tortoise_webhook_test.go similarity index 96% rename from api/v1beta1/tortoise_webhook_test.go rename to api/v1beta2/tortoise_webhook_test.go index 93d86081..6fa1d9ac 100644 --- a/api/v1beta1/tortoise_webhook_test.go +++ b/api/v1beta2/tortoise_webhook_test.go @@ -23,7 +23,7 @@ SOFTWARE. */ -package v1beta1 +package v1beta2 import ( "bytes" @@ -202,6 +202,9 @@ var _ = Describe("Tortoise Webhook", func() { It("should create a valid Tortoise", func() { validateCreationTest(filepath.Join("testdata", "validating", "success", "tortoise.yaml"), filepath.Join("testdata", "validating", "success", "hpa.yaml"), filepath.Join("testdata", "validating", "success", "deployment.yaml"), true) }) + It("invalid: Tortoise is targetting the resource other than Deployment", func() { + validateCreationTest(filepath.Join("testdata", "validating", "not-targetting-deployment", "tortoise.yaml"), filepath.Join("testdata", "validating", "not-targetting-deployment", "hpa.yaml"), filepath.Join("testdata", "validating", "not-targetting-deployment", "deployment.yaml"), false) + }) It("invalid: Tortoise has Horizontal for the container, but HPA doens't have ContainerResource metric for that container", func() { validateCreationTest(filepath.Join("testdata", "validating", "no-metric-in-hpa", "tortoise.yaml"), filepath.Join("testdata", "validating", "no-metric-in-hpa", "hpa.yaml"), filepath.Join("testdata", "validating", "no-metric-in-hpa", "deployment.yaml"), false) }) diff --git a/api/v1beta1/webhook_suite_test.go b/api/v1beta2/webhook_suite_test.go similarity index 99% rename from api/v1beta1/webhook_suite_test.go rename to api/v1beta2/webhook_suite_test.go index 8aa801d6..f9bde61b 100644 --- a/api/v1beta1/webhook_suite_test.go +++ b/api/v1beta2/webhook_suite_test.go @@ -23,7 +23,7 @@ SOFTWARE. */ -package v1beta1 +package v1beta2 import ( "bytes" diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go new file mode 100644 index 00000000..6ef05da3 --- /dev/null +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -0,0 +1,513 @@ +//go:build !ignore_autogenerated + +/* +MIT License + +Copyright (c) 2023 mercari + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1beta2 + +import ( + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Conditions) DeepCopyInto(out *Conditions) { + *out = *in + if in.TortoiseConditions != nil { + in, out := &in.TortoiseConditions, &out.TortoiseConditions + *out = make([]TortoiseCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ContainerRecommendationFromVPA != nil { + in, out := &in.ContainerRecommendationFromVPA, &out.ContainerRecommendationFromVPA + *out = make([]ContainerRecommendationFromVPA, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Conditions. +func (in *Conditions) DeepCopy() *Conditions { + if in == nil { + return nil + } + out := new(Conditions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerRecommendationFromVPA) DeepCopyInto(out *ContainerRecommendationFromVPA) { + *out = *in + if in.MaxRecommendation != nil { + in, out := &in.MaxRecommendation, &out.MaxRecommendation + *out = make(map[v1.ResourceName]ResourceQuantity, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.Recommendation != nil { + in, out := &in.Recommendation, &out.Recommendation + *out = make(map[v1.ResourceName]ResourceQuantity, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerRecommendationFromVPA. +func (in *ContainerRecommendationFromVPA) DeepCopy() *ContainerRecommendationFromVPA { + if in == nil { + return nil + } + out := new(ContainerRecommendationFromVPA) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourcePhases) DeepCopyInto(out *ContainerResourcePhases) { + *out = *in + if in.ResourcePhases != nil { + in, out := &in.ResourcePhases, &out.ResourcePhases + *out = make(map[v1.ResourceName]ResourcePhase, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourcePhases. +func (in *ContainerResourcePhases) DeepCopy() *ContainerResourcePhases { + if in == nil { + return nil + } + out := new(ContainerResourcePhases) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourcePolicy) DeepCopyInto(out *ContainerResourcePolicy) { + *out = *in + if in.MinAllocatedResources != nil { + in, out := &in.MinAllocatedResources, &out.MinAllocatedResources + *out = make(v1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.AutoscalingPolicy != nil { + in, out := &in.AutoscalingPolicy, &out.AutoscalingPolicy + *out = make(map[v1.ResourceName]AutoscalingType, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourcePolicy. +func (in *ContainerResourcePolicy) DeepCopy() *ContainerResourcePolicy { + if in == nil { + return nil + } + out := new(ContainerResourcePolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CrossVersionObjectReference) DeepCopyInto(out *CrossVersionObjectReference) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CrossVersionObjectReference. +func (in *CrossVersionObjectReference) DeepCopy() *CrossVersionObjectReference { + if in == nil { + return nil + } + out := new(CrossVersionObjectReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HPATargetUtilizationRecommendationPerContainer) DeepCopyInto(out *HPATargetUtilizationRecommendationPerContainer) { + *out = *in + if in.TargetUtilization != nil { + in, out := &in.TargetUtilization, &out.TargetUtilization + *out = make(map[v1.ResourceName]int32, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HPATargetUtilizationRecommendationPerContainer. +func (in *HPATargetUtilizationRecommendationPerContainer) DeepCopy() *HPATargetUtilizationRecommendationPerContainer { + if in == nil { + return nil + } + out := new(HPATargetUtilizationRecommendationPerContainer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HorizontalRecommendations) DeepCopyInto(out *HorizontalRecommendations) { + *out = *in + if in.TargetUtilizations != nil { + in, out := &in.TargetUtilizations, &out.TargetUtilizations + *out = make([]HPATargetUtilizationRecommendationPerContainer, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.MaxReplicas != nil { + in, out := &in.MaxReplicas, &out.MaxReplicas + *out = make([]ReplicasRecommendation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.MinReplicas != nil { + in, out := &in.MinReplicas, &out.MinReplicas + *out = make([]ReplicasRecommendation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalRecommendations. +func (in *HorizontalRecommendations) DeepCopy() *HorizontalRecommendations { + if in == nil { + return nil + } + out := new(HorizontalRecommendations) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Recommendations) DeepCopyInto(out *Recommendations) { + *out = *in + in.Horizontal.DeepCopyInto(&out.Horizontal) + in.Vertical.DeepCopyInto(&out.Vertical) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Recommendations. +func (in *Recommendations) DeepCopy() *Recommendations { + if in == nil { + return nil + } + out := new(Recommendations) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RecommendedContainerResources) DeepCopyInto(out *RecommendedContainerResources) { + *out = *in + if in.RecommendedResource != nil { + in, out := &in.RecommendedResource, &out.RecommendedResource + *out = make(v1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecommendedContainerResources. +func (in *RecommendedContainerResources) DeepCopy() *RecommendedContainerResources { + if in == nil { + return nil + } + out := new(RecommendedContainerResources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicasRecommendation) DeepCopyInto(out *ReplicasRecommendation) { + *out = *in + if in.WeekDay != nil { + in, out := &in.WeekDay, &out.WeekDay + *out = new(string) + **out = **in + } + in.UpdatedAt.DeepCopyInto(&out.UpdatedAt) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicasRecommendation. +func (in *ReplicasRecommendation) DeepCopy() *ReplicasRecommendation { + if in == nil { + return nil + } + out := new(ReplicasRecommendation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourcePhase) DeepCopyInto(out *ResourcePhase) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourcePhase. +func (in *ResourcePhase) DeepCopy() *ResourcePhase { + if in == nil { + return nil + } + out := new(ResourcePhase) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceQuantity) DeepCopyInto(out *ResourceQuantity) { + *out = *in + out.Quantity = in.Quantity.DeepCopy() + in.UpdatedAt.DeepCopyInto(&out.UpdatedAt) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceQuantity. +func (in *ResourceQuantity) DeepCopy() *ResourceQuantity { + if in == nil { + return nil + } + out := new(ResourceQuantity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetRefs) DeepCopyInto(out *TargetRefs) { + *out = *in + out.ScaleTargetRef = in.ScaleTargetRef + if in.HorizontalPodAutoscalerName != nil { + in, out := &in.HorizontalPodAutoscalerName, &out.HorizontalPodAutoscalerName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetRefs. +func (in *TargetRefs) DeepCopy() *TargetRefs { + if in == nil { + return nil + } + out := new(TargetRefs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetStatusVerticalPodAutoscaler) DeepCopyInto(out *TargetStatusVerticalPodAutoscaler) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetStatusVerticalPodAutoscaler. +func (in *TargetStatusVerticalPodAutoscaler) DeepCopy() *TargetStatusVerticalPodAutoscaler { + if in == nil { + return nil + } + out := new(TargetStatusVerticalPodAutoscaler) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetsStatus) DeepCopyInto(out *TargetsStatus) { + *out = *in + out.ScaleTargetRef = in.ScaleTargetRef + if in.VerticalPodAutoscalers != nil { + in, out := &in.VerticalPodAutoscalers, &out.VerticalPodAutoscalers + *out = make([]TargetStatusVerticalPodAutoscaler, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetsStatus. +func (in *TargetsStatus) DeepCopy() *TargetsStatus { + if in == nil { + return nil + } + out := new(TargetsStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Tortoise) DeepCopyInto(out *Tortoise) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Tortoise. +func (in *Tortoise) DeepCopy() *Tortoise { + if in == nil { + return nil + } + out := new(Tortoise) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Tortoise) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TortoiseCondition) DeepCopyInto(out *TortoiseCondition) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TortoiseCondition. +func (in *TortoiseCondition) DeepCopy() *TortoiseCondition { + if in == nil { + return nil + } + out := new(TortoiseCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TortoiseList) DeepCopyInto(out *TortoiseList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Tortoise, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TortoiseList. +func (in *TortoiseList) DeepCopy() *TortoiseList { + if in == nil { + return nil + } + out := new(TortoiseList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TortoiseList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TortoiseSpec) DeepCopyInto(out *TortoiseSpec) { + *out = *in + in.TargetRefs.DeepCopyInto(&out.TargetRefs) + if in.ResourcePolicy != nil { + in, out := &in.ResourcePolicy, &out.ResourcePolicy + *out = make([]ContainerResourcePolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TortoiseSpec. +func (in *TortoiseSpec) DeepCopy() *TortoiseSpec { + if in == nil { + return nil + } + out := new(TortoiseSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TortoiseStatus) DeepCopyInto(out *TortoiseStatus) { + *out = *in + in.Conditions.DeepCopyInto(&out.Conditions) + in.Recommendations.DeepCopyInto(&out.Recommendations) + in.Targets.DeepCopyInto(&out.Targets) + if in.ContainerResourcePhases != nil { + in, out := &in.ContainerResourcePhases, &out.ContainerResourcePhases + *out = make([]ContainerResourcePhases, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TortoiseStatus. +func (in *TortoiseStatus) DeepCopy() *TortoiseStatus { + if in == nil { + return nil + } + out := new(TortoiseStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VerticalRecommendations) DeepCopyInto(out *VerticalRecommendations) { + *out = *in + if in.ContainerResourceRecommendation != nil { + in, out := &in.ContainerResourceRecommendation, &out.ContainerResourceRecommendation + *out = make([]RecommendedContainerResources, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VerticalRecommendations. +func (in *VerticalRecommendations) DeepCopy() *VerticalRecommendations { + if in == nil { + return nil + } + out := new(VerticalRecommendations) + in.DeepCopyInto(out) + return out +} diff --git a/config/crd/bases/autoscaling.mercari.com_tortoises.yaml b/config/crd/bases/autoscaling.mercari.com_tortoises.yaml index c70398a1..b4aefd13 100644 --- a/config/crd/bases/autoscaling.mercari.com_tortoises.yaml +++ b/config/crd/bases/autoscaling.mercari.com_tortoises.yaml @@ -771,6 +771,440 @@ spec: type: object type: object served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.updateMode + name: MODE + type: string + - jsonPath: .status.tortoisePhase + name: PHASE + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: Tortoise is the Schema for the tortoises API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TortoiseSpec defines the desired state of Tortoise + properties: + deletionPolicy: + description: "DeletionPolicy is the policy how the controller deletes + associated HPA and VPAs when tortoise is removed. If \"DeleteAll\", + tortoise deletes all associated HPA and VPAs, created by tortoise. + If the associated HPA is not created by tortoise, which is associated + by spec.targetRefs.horizontalPodAutoscalerName, tortoise never delete + the HPA. If \"NoDelete\", tortoise doesn't delete any associated + HPA and VPAs. \n \"NoDelete\" is the default value." + enum: + - DeleteAll + - NoDelete + type: string + resourcePolicy: + description: ResourcePolicy contains the policy how each resource + is updated. + items: + properties: + autoscalingPolicy: + additionalProperties: + enum: + - "Off" + - Horizontal + - Vertical + type: string + description: "AutoscalingPolicy specifies how each resource + is scaled. If \"Horizontal\", the resource is horizontally + scaled. If \"Vertical\", the resource is vertically scaled. + If \"Off\", tortoise doesn't scale at all based on that resource. + \n The default value is \"Horizontal\" for cpu, and \"Vertical\" + for memory." + type: object + containerName: + description: ContainerName is the name of target container. + type: string + minAllocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: "MinAllocatedResources is the minimum amount of + resources which is given to the container. Tortoise never + set the resources request on the container than MinAllocatedResources. + \n If empty, tortoise may reduce the resource request to the + value which is suggested from VPA. Leaving this field empty + is basically safe, but you may consider using MinAllocatedResources + when maybe your application will consume resources more than + usual, given the VPA suggests values based on the historical + resource usage. For example, your application will soon have + new feature which leads to increase in the resource usage, + it is expected that your application will soon get more requests + than usual, etc." + type: object + required: + - containerName + type: object + type: array + targetRefs: + description: TargetRefs has reference to involved resources. + properties: + horizontalPodAutoscalerName: + description: "HorizontalPodAutoscalerName is the name of the target + HPA. The target of this HPA should be the same as the ScaleTargetRef + above. The target HPA should have the ContainerResource type + metric or the external metric refers to the container resource + utilization. Please check out the document for more detail: + https://github.com/mercari/tortoise/blob/master/docs/horizontal.md#supported-metrics-in-hpa + \n You can specify either of existing HPA only. This is an optional + field, and if you don't specify this field, tortoise will create + a new default HPA named `tortoise-hpa-{tortoise name}`." + type: string + scaleTargetRef: + description: ScaleTargetRef is the target of scaling. It should + be the same as the target of HPA. + properties: + apiVersion: + description: apiVersion is the API version of the referent + type: string + kind: + description: 'kind is the kind of the referent; More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'name is the name of the referent; More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + required: + - kind + - name + type: object + required: + - scaleTargetRef + type: object + updateMode: + description: "UpdateMode is how tortoise update resources. If \"Off\", + tortoise generates the recommendations in .Status, but doesn't apply + it actually. If \"Auto\", tortoise generates the recommendations + in .Status, and apply it to resources. If \"Emergency\", tortoise + generates the recommendations in .Status as usual, but increase + replica number high enough value. \"Emergency\" is useful when something + unexpected happens in workloads, and you want to scale up the workload + with high enough resources. See https://github.com/mercari/tortoise/blob/main/docs/emergency.md + to know more about emergency mode. \n \"Off\" is the default value." + enum: + - "Off" + - Auto + - Emergency + type: string + required: + - targetRefs + type: object + status: + description: TortoiseStatus defines the observed state of Tortoise + properties: + conditions: + properties: + containerRecommendationFromVPA: + description: ContainerRecommendationFromVPA is the condition of + container recommendation from VPA, which is observed last time. + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + maxRecommendation: + additionalProperties: + properties: + quantity: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + updatedAt: + format: date-time + type: string + type: object + description: MaxRecommendation is the max recommendation + value from VPA in a certain period (1 week). Tortoise + generates all recommendation based on this MaxRecommendation. + type: object + recommendation: + additionalProperties: + properties: + quantity: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + updatedAt: + format: date-time + type: string + type: object + description: Recommendation is the latest recommendation + value from VPA. + type: object + required: + - containerName + - maxRecommendation + - recommendation + type: object + type: array + tortoiseConditions: + description: TortoiseConditions is the condition of this tortoise. + items: + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another + format: date-time + type: string + lastUpdateTime: + description: The last time this condition was updated. + format: date-time + type: string + message: + description: message is a human-readable explanation containing + details about the transition + type: string + reason: + description: reason is the reason for the condition's last + transition. + type: string + status: + description: Status is the status of the condition. (True, + False, Unknown) + type: string + type: + description: Type is the type of the condition. + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + containerResourcePhases: + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + resourcePhases: + additionalProperties: + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another + format: date-time + type: string + phase: + type: string + required: + - phase + type: object + description: ResourcePhases is the phase of each resource of + this container. + type: object + required: + - containerName + - resourcePhases + type: object + type: array + recommendations: + properties: + horizontal: + properties: + maxReplicas: + description: MaxReplicas has the recommendation of maxReplicas. + It contains the recommendations for each time slot. + items: + properties: + from: + description: From represented in hour. + type: integer + timezone: + type: string + to: + description: To represented in hour. + type: integer + updatedAt: + format: date-time + type: string + value: + description: Value is the recommendation value. It's + calculated every reconciliation, and updated if the + calculated recommendation value is more than the current + recommendation value on tortoise. + format: int32 + type: integer + weekday: + description: WeekDay is the day of the week. If empty, + it means it applies to all days of the week. + type: string + required: + - from + - timezone + - to + - value + type: object + type: array + minReplicas: + description: MinReplicas has the recommendation of minReplicas. + It contains the recommendations for each time slot. + items: + properties: + from: + description: From represented in hour. + type: integer + timezone: + type: string + to: + description: To represented in hour. + type: integer + updatedAt: + format: date-time + type: string + value: + description: Value is the recommendation value. It's + calculated every reconciliation, and updated if the + calculated recommendation value is more than the current + recommendation value on tortoise. + format: int32 + type: integer + weekday: + description: WeekDay is the day of the week. If empty, + it means it applies to all days of the week. + type: string + required: + - from + - timezone + - to + - value + type: object + type: array + targetUtilizations: + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + targetUtilization: + additionalProperties: + format: int32 + type: integer + description: TargetUtilization is the recommendation + of targetUtilization of HPA. + type: object + required: + - containerName + - targetUtilization + type: object + type: array + type: object + vertical: + properties: + containerResourceRecommendation: + items: + properties: + RecommendedResource: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: RecommendedResource is the recommendation + calculated by the tortoise. If AutoscalingPolicy is + vertical, it's the same value as the VPA suggests. + If AutoscalingPolicy is horizontal, it's basically + the same value as the current resource request. But, + when the number of replicas are too small or too large, + tortoise may try to increase/decrease the amount of + resources given to the container, so that the number + of replicas won't be very small or very large. + type: object + containerName: + description: ContainerName is the name of target container. + type: string + required: + - RecommendedResource + - containerName + type: object + type: array + type: object + type: object + targets: + properties: + horizontalPodAutoscaler: + type: string + scaleTargetRef: + description: CrossVersionObjectReference contains enough information + toet identify the referred resource. + properties: + apiVersion: + description: apiVersion is the API version of the referent + type: string + kind: + description: 'kind is the kind of the referent; More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'name is the name of the referent; More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + required: + - kind + - name + type: object + verticalPodAutoscalers: + items: + properties: + name: + type: string + role: + enum: + - Updater + - Monitor + type: string + required: + - name + - role + type: object + type: array + required: + - scaleTargetRef + - verticalPodAutoscalers + type: object + tortoisePhase: + type: string + required: + - conditions + - containerResourcePhases + - recommendations + - targets + - tortoisePhase + type: object + type: object + served: true storage: true subresources: status: {} diff --git a/config/samples/autoscaling_v1beta2_tortoise.yaml b/config/samples/autoscaling_v1beta2_tortoise.yaml new file mode 100644 index 00000000..2e9e7f76 --- /dev/null +++ b/config/samples/autoscaling_v1beta2_tortoise.yaml @@ -0,0 +1,12 @@ +apiVersion: autoscaling.mercari.com/v1beta2 +kind: Tortoise +metadata: + labels: + app.kubernetes.io/name: tortoise + app.kubernetes.io/instance: tortoise-sample + app.kubernetes.io/part-of: tortoise + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: tortoise + name: tortoise-sample +spec: + # TODO(user): Add fields here diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index a60f01a0..bd07b07a 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -10,14 +10,14 @@ webhooks: service: name: webhook-service namespace: system - path: /mutate-autoscaling-mercari-com-v1beta1-tortoise + path: /mutate-autoscaling-mercari-com-v1beta2-tortoise failurePolicy: Fail name: mtortoise.kb.io rules: - apiGroups: - autoscaling.mercari.com apiVersions: - - v1beta1 + - v1beta2 operations: - CREATE - UPDATE @@ -56,14 +56,14 @@ webhooks: service: name: webhook-service namespace: system - path: /validate-autoscaling-mercari-com-v1beta1-tortoise + path: /validate-autoscaling-mercari-com-v1beta2-tortoise failurePolicy: Fail name: vtortoise.kb.io rules: - apiGroups: - autoscaling.mercari.com apiVersions: - - v1beta1 + - v1beta2 operations: - CREATE - UPDATE diff --git a/controllers/suite_test.go b/controllers/suite_test.go index ecfc2d6a..7b671d28 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -43,7 +43,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - autoscalingv1beta1 "github.com/mercari/tortoise/api/v1beta1" + autoscalingv1beta2 "github.com/mercari/tortoise/api/v1beta2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -82,7 +82,7 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) Expect(cfg).NotTo(BeNil()) - err = autoscalingv1beta1.AddToScheme(scheme) + err = autoscalingv1beta2.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) err = v1.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) diff --git a/controllers/testdata/deletion-policy-all/before/tortoise.yaml b/controllers/testdata/deletion-policy-all/before/tortoise.yaml index 8172727c..69658265 100644 --- a/controllers/testdata/deletion-policy-all/before/tortoise.yaml +++ b/controllers/testdata/deletion-policy-all/before/tortoise.yaml @@ -75,7 +75,6 @@ status: vertical: containerResourceRecommendation: null targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/mutable-autoscalingpolicy-add-another-horizontal/after/tortoise.yaml b/controllers/testdata/mutable-autoscalingpolicy-add-another-horizontal/after/tortoise.yaml index e26f3f07..7dc9a618 100644 --- a/controllers/testdata/mutable-autoscalingpolicy-add-another-horizontal/after/tortoise.yaml +++ b/controllers/testdata/mutable-autoscalingpolicy-add-another-horizontal/after/tortoise.yaml @@ -83,7 +83,6 @@ status: memory: 4Gi containerName: istio-proxy targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/mutable-autoscalingpolicy-add-another-horizontal/before/tortoise.yaml b/controllers/testdata/mutable-autoscalingpolicy-add-another-horizontal/before/tortoise.yaml index 527ffd2c..f01426db 100644 --- a/controllers/testdata/mutable-autoscalingpolicy-add-another-horizontal/before/tortoise.yaml +++ b/controllers/testdata/mutable-autoscalingpolicy-add-another-horizontal/before/tortoise.yaml @@ -74,7 +74,6 @@ status: vertical: containerResourceRecommendation: null targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/mutable-autoscalingpolicy-no-hpa-and-add-horizontal/after/tortoise.yaml b/controllers/testdata/mutable-autoscalingpolicy-no-hpa-and-add-horizontal/after/tortoise.yaml index e60cb081..f8bee479 100644 --- a/controllers/testdata/mutable-autoscalingpolicy-no-hpa-and-add-horizontal/after/tortoise.yaml +++ b/controllers/testdata/mutable-autoscalingpolicy-no-hpa-and-add-horizontal/after/tortoise.yaml @@ -81,7 +81,6 @@ status: memory: 3Gi containerName: istio-proxy targets: - deployment: "" horizontalPodAutoscaler: "tortoise-hpa-mercari" verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/mutable-autoscalingpolicy-no-hpa-and-add-horizontal/before/tortoise.yaml b/controllers/testdata/mutable-autoscalingpolicy-no-hpa-and-add-horizontal/before/tortoise.yaml index a5575367..2f628d3e 100644 --- a/controllers/testdata/mutable-autoscalingpolicy-no-hpa-and-add-horizontal/before/tortoise.yaml +++ b/controllers/testdata/mutable-autoscalingpolicy-no-hpa-and-add-horizontal/before/tortoise.yaml @@ -80,7 +80,6 @@ status: memory: 3Gi containerName: istio-proxy targets: - deployment: "" verticalPodAutoscalers: - name: tortoise-updater-mercari role: Updater diff --git a/controllers/testdata/mutable-autoscalingpolicy-remove-horizontal/after/tortoise.yaml b/controllers/testdata/mutable-autoscalingpolicy-remove-horizontal/after/tortoise.yaml index 805dd83d..8444175b 100644 --- a/controllers/testdata/mutable-autoscalingpolicy-remove-horizontal/after/tortoise.yaml +++ b/controllers/testdata/mutable-autoscalingpolicy-remove-horizontal/after/tortoise.yaml @@ -80,7 +80,9 @@ status: memory: 3Gi containerName: istio-proxy targets: - deployment: "mercari-app" + scaleTargetRef: + kind: Deployment + name: mercari-app horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/mutable-autoscalingpolicy-remove-horizontal/before/tortoise.yaml b/controllers/testdata/mutable-autoscalingpolicy-remove-horizontal/before/tortoise.yaml index 64e254dd..d69babba 100644 --- a/controllers/testdata/mutable-autoscalingpolicy-remove-horizontal/before/tortoise.yaml +++ b/controllers/testdata/mutable-autoscalingpolicy-remove-horizontal/before/tortoise.yaml @@ -74,7 +74,9 @@ status: vertical: containerResourceRecommendation: null targets: - deployment: mercari-app + scaleTargetRef: + kind: Deployment + name: mercari-app horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-multiple-containers-pod-all-vertical/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-multiple-containers-pod-all-vertical/after/tortoise.yaml index dd84ae2c..36bfdbac 100644 --- a/controllers/testdata/reconcile-for-the-multiple-containers-pod-all-vertical/after/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-multiple-containers-pod-all-vertical/after/tortoise.yaml @@ -80,7 +80,6 @@ status: memory: 3Gi containerName: istio-proxy targets: - deployment: "" verticalPodAutoscalers: - name: tortoise-updater-mercari role: Updater diff --git a/controllers/testdata/reconcile-for-the-multiple-containers-pod-all-vertical/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-multiple-containers-pod-all-vertical/before/tortoise.yaml index 351e064e..147dcf1d 100644 --- a/controllers/testdata/reconcile-for-the-multiple-containers-pod-all-vertical/before/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-multiple-containers-pod-all-vertical/before/tortoise.yaml @@ -72,7 +72,6 @@ status: vertical: containerResourceRecommendation: null targets: - deployment: "" verticalPodAutoscalers: - name: tortoise-updater-mercari role: Updater diff --git a/controllers/testdata/reconcile-for-the-multiple-containers-pod-emergency/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-multiple-containers-pod-emergency/after/tortoise.yaml index b0a9d79c..79f32bc0 100644 --- a/controllers/testdata/reconcile-for-the-multiple-containers-pod-emergency/after/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-multiple-containers-pod-emergency/after/tortoise.yaml @@ -83,7 +83,6 @@ status: memory: 3Gi containerName: istio-proxy targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-multiple-containers-pod-emergency/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-multiple-containers-pod-emergency/before/tortoise.yaml index 38382456..002d8b30 100644 --- a/controllers/testdata/reconcile-for-the-multiple-containers-pod-emergency/before/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-multiple-containers-pod-emergency/before/tortoise.yaml @@ -75,7 +75,6 @@ status: vertical: containerResourceRecommendation: null targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-multiple-containers-pod-one-off/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-multiple-containers-pod-one-off/after/tortoise.yaml index 5e54f6b2..1b9655e7 100644 --- a/controllers/testdata/reconcile-for-the-multiple-containers-pod-one-off/after/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-multiple-containers-pod-one-off/after/tortoise.yaml @@ -81,7 +81,6 @@ status: memory: 4Gi containerName: istio-proxy targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-multiple-containers-pod-one-off/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-multiple-containers-pod-one-off/before/tortoise.yaml index bb8794cd..5d4e8b2f 100644 --- a/controllers/testdata/reconcile-for-the-multiple-containers-pod-one-off/before/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-multiple-containers-pod-one-off/before/tortoise.yaml @@ -74,7 +74,6 @@ status: vertical: containerResourceRecommendation: null targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-multiple-containers-pod-working/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-multiple-containers-pod-working/after/tortoise.yaml index cc880c6e..be3f16f8 100644 --- a/controllers/testdata/reconcile-for-the-multiple-containers-pod-working/after/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-multiple-containers-pod-working/after/tortoise.yaml @@ -82,7 +82,6 @@ status: memory: 3Gi containerName: istio-proxy targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-multiple-containers-pod-working/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-multiple-containers-pod-working/before/tortoise.yaml index 2fcee779..8d798ea5 100644 --- a/controllers/testdata/reconcile-for-the-multiple-containers-pod-working/before/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-multiple-containers-pod-working/before/tortoise.yaml @@ -74,7 +74,6 @@ status: vertical: containerResourceRecommendation: null targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-dryrun/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-dryrun/after/tortoise.yaml index eddb0e13..d1038313 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-dryrun/after/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-dryrun/after/tortoise.yaml @@ -57,7 +57,6 @@ status: memory: 3Gi containerName: app targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-dryrun/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-dryrun/before/tortoise.yaml index 92767d5d..3e5fa3f6 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-dryrun/before/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-dryrun/before/tortoise.yaml @@ -53,7 +53,6 @@ status: vertical: containerResourceRecommendation: null targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-emergency/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-emergency/after/tortoise.yaml index 622c0a37..d46102d5 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-emergency/after/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-emergency/after/tortoise.yaml @@ -57,7 +57,6 @@ status: memory: 3Gi containerName: app targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-emergency/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-emergency/before/tortoise.yaml index 800b9d82..a994b6e7 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-emergency/before/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-emergency/before/tortoise.yaml @@ -53,7 +53,6 @@ status: vertical: containerResourceRecommendation: null targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data-finished/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data-finished/after/tortoise.yaml index db0a79c5..c1cd2452 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data-finished/after/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data-finished/after/tortoise.yaml @@ -56,7 +56,6 @@ status: memory: 3Gi containerName: app targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data-finished/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data-finished/before/tortoise.yaml index 67c6bf68..f1e3c939 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data-finished/before/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data-finished/before/tortoise.yaml @@ -52,7 +52,6 @@ status: vertical: containerResourceRecommendation: null targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data/after/tortoise.yaml index f28da578..b5e36375 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data/after/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data/after/tortoise.yaml @@ -56,7 +56,6 @@ status: memory: 3Gi containerName: app targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data/before/tortoise.yaml index 08e16e30..be7be9e5 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data/before/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-gathering-data/before/tortoise.yaml @@ -56,7 +56,6 @@ status: memory: 3Gi containerName: app targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-initializing/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-initializing/after/tortoise.yaml index 08e16e30..be7be9e5 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-initializing/after/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-initializing/after/tortoise.yaml @@ -56,7 +56,6 @@ status: memory: 3Gi containerName: app targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-initializing/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-initializing/before/tortoise.yaml index 08e16e30..be7be9e5 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-initializing/before/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-initializing/before/tortoise.yaml @@ -56,7 +56,6 @@ status: memory: 3Gi containerName: app targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-partly-working/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-partly-working/after/tortoise.yaml index 627b803a..63768cf8 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-partly-working/after/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-partly-working/after/tortoise.yaml @@ -56,7 +56,6 @@ status: memory: 3Gi containerName: app targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-partly-working/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-partly-working/before/tortoise.yaml index 627b803a..63768cf8 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-partly-working/before/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-partly-working/before/tortoise.yaml @@ -56,7 +56,6 @@ status: memory: 3Gi containerName: app targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-working/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-working/after/tortoise.yaml index db0a79c5..c1cd2452 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-working/after/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-working/after/tortoise.yaml @@ -56,7 +56,6 @@ status: memory: 3Gi containerName: app targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-working/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-working/before/tortoise.yaml index 8f2bf843..97c37a87 100644 --- a/controllers/testdata/reconcile-for-the-single-container-pod-working/before/tortoise.yaml +++ b/controllers/testdata/reconcile-for-the-single-container-pod-working/before/tortoise.yaml @@ -52,7 +52,6 @@ status: vertical: containerResourceRecommendation: null targets: - deployment: "" horizontalPodAutoscaler: tortoise-hpa-mercari verticalPodAutoscalers: - name: tortoise-updater-mercari diff --git a/controllers/tortoise_controller.go b/controllers/tortoise_controller.go index e881c37c..0507c60f 100644 --- a/controllers/tortoise_controller.go +++ b/controllers/tortoise_controller.go @@ -38,7 +38,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/log" - autoscalingv1beta1 "github.com/mercari/tortoise/api/v1beta1" + autoscalingv1beta2 "github.com/mercari/tortoise/api/v1beta2" "github.com/mercari/tortoise/pkg/deployment" "github.com/mercari/tortoise/pkg/hpa" "github.com/mercari/tortoise/pkg/recommender" @@ -129,7 +129,7 @@ func (r *TortoiseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ } tortoise = r.TortoiseService.UpdateTortoisePhase(tortoise, dm, now) - if tortoise.Status.TortoisePhase == autoscalingv1beta1.TortoisePhaseInitializing { + if tortoise.Status.TortoisePhase == autoscalingv1beta2.TortoisePhaseInitializing { logger.V(4).Info("initializing tortoise", "tortoise", req.NamespacedName) // need to initialize HPA and VPA. if err := r.initializeVPAAndHPA(ctx, tortoise, dm, now); err != nil { @@ -152,7 +152,7 @@ func (r *TortoiseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ } if !ready { logger.V(4).Info("VPA created by tortoise isn't ready yet", "tortoise", req.NamespacedName) - tortoise.Status.TortoisePhase = autoscalingv1beta1.TortoisePhaseInitializing + tortoise.Status.TortoisePhase = autoscalingv1beta2.TortoisePhaseInitializing _, err = r.TortoiseService.UpdateTortoiseStatus(ctx, tortoise, now, true) if err != nil { logger.Error(err, "update Tortoise status", "tortoise", req.NamespacedName) @@ -187,7 +187,7 @@ func (r *TortoiseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ r.EventRecorder.Event(tortoise, corev1.EventTypeNormal, "RecommendationUpdated", "The recommendation on Tortoise status is updated") - if tortoise.Status.TortoisePhase == autoscalingv1beta1.TortoisePhaseGatheringData { + if tortoise.Status.TortoisePhase == autoscalingv1beta2.TortoisePhaseGatheringData { logger.V(4).Info("tortoise is GatheringData phase; skip applying the recommendation to HPA or VPAs") return ctrl.Result{RequeueAfter: r.Interval}, nil } @@ -213,8 +213,8 @@ func (r *TortoiseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ return ctrl.Result{RequeueAfter: r.Interval}, nil } -func (r *TortoiseReconciler) deleteVPAAndHPA(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise, now time.Time) error { - if tortoise.Spec.DeletionPolicy == autoscalingv1beta1.DeletionPolicyNoDelete { +func (r *TortoiseReconciler) deleteVPAAndHPA(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise, now time.Time) error { + if tortoise.Spec.DeletionPolicy == autoscalingv1beta2.DeletionPolicyNoDelete { // don't delete anything. return nil } @@ -239,7 +239,7 @@ func (r *TortoiseReconciler) deleteVPAAndHPA(ctx context.Context, tortoise *auto return nil } -func (r *TortoiseReconciler) initializeVPAAndHPA(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise, dm *v1.Deployment, now time.Time) error { +func (r *TortoiseReconciler) initializeVPAAndHPA(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise, dm *v1.Deployment, now time.Time) error { // need to initialize HPA and VPA. tortoise, err := r.HpaService.InitializeHPA(ctx, tortoise, dm, now) if err != nil { @@ -264,6 +264,6 @@ func (r *TortoiseReconciler) initializeVPAAndHPA(ctx context.Context, tortoise * // SetupWithManager sets up the controller with the Manager. func (r *TortoiseReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&autoscalingv1beta1.Tortoise{}). + For(&autoscalingv1beta2.Tortoise{}). Complete(r) } diff --git a/controllers/tortoise_controller_test.go b/controllers/tortoise_controller_test.go index 3dd1473c..97021724 100644 --- a/controllers/tortoise_controller_test.go +++ b/controllers/tortoise_controller_test.go @@ -20,7 +20,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/yaml" - "github.com/mercari/tortoise/api/v1beta1" + "github.com/mercari/tortoise/api/v1beta2" "github.com/mercari/tortoise/pkg/deployment" "github.com/mercari/tortoise/pkg/hpa" "github.com/mercari/tortoise/pkg/recommender" @@ -38,10 +38,10 @@ func newResource(path string) resources { updaterVPAPath := fmt.Sprintf("%s/vpa-Updater.yaml", path) monitorVPAPath := fmt.Sprintf("%s/vpa-Monitor.yaml", path) - var tortoise *v1beta1.Tortoise + var tortoise *v1beta2.Tortoise y, err := os.ReadFile(tortoisePath) if err == nil { - tortoise = &v1beta1.Tortoise{} + tortoise = &v1beta2.Tortoise{} err = yaml.Unmarshal(y, tortoise) Expect(err).NotTo(HaveOccurred()) } @@ -82,9 +82,9 @@ func newResource(path string) resources { tortoise: tortoise, hpa: hpa, deployment: deploy, - vpa: map[v1beta1.VerticalPodAutoscalerRole]*autoscalingv1.VerticalPodAutoscaler{ - v1beta1.VerticalPodAutoscalerRoleUpdater: vpa, - v1beta1.VerticalPodAutoscalerRoleMonitor: vpa2, + vpa: map[v1beta2.VerticalPodAutoscalerRole]*autoscalingv1.VerticalPodAutoscaler{ + v1beta2.VerticalPodAutoscalerRoleUpdater: vpa, + v1beta2.VerticalPodAutoscalerRoleMonitor: vpa2, }, } } @@ -114,11 +114,11 @@ func createVPAWithStatus(ctx context.Context, k8sClient client.Client, vpa *auto Expect(err).NotTo(HaveOccurred()) } -func createTortoiseWithStatus(ctx context.Context, k8sClient client.Client, tortoise *v1beta1.Tortoise) { +func createTortoiseWithStatus(ctx context.Context, k8sClient client.Client, tortoise *v1beta2.Tortoise) { err := k8sClient.Create(ctx, tortoise.DeepCopy()) Expect(err).NotTo(HaveOccurred()) - v := &v1beta1.Tortoise{} + v := &v1beta2.Tortoise{} err = k8sClient.Get(ctx, client.ObjectKey{Namespace: tortoise.Namespace, Name: tortoise.Name}, v) Expect(err).NotTo(HaveOccurred()) @@ -135,8 +135,8 @@ func initializeResourcesFromFiles(ctx context.Context, k8sClient client.Client, } createDeploymentWithStatus(ctx, k8sClient, resource.deployment) - createVPAWithStatus(ctx, k8sClient, resource.vpa[v1beta1.VerticalPodAutoscalerRoleUpdater]) - createVPAWithStatus(ctx, k8sClient, resource.vpa[v1beta1.VerticalPodAutoscalerRoleMonitor]) + createVPAWithStatus(ctx, k8sClient, resource.vpa[v1beta2.VerticalPodAutoscalerRoleUpdater]) + createVPAWithStatus(ctx, k8sClient, resource.vpa[v1beta2.VerticalPodAutoscalerRoleMonitor]) createTortoiseWithStatus(ctx, k8sClient, resource.tortoise) return resource @@ -182,7 +182,7 @@ var _ = Describe("Test TortoiseController", func() { ctx := context.Background() var stopFunc func() cleanUp := func() { - err := deleteObj(ctx, &v1beta1.Tortoise{}, "mercari") + err := deleteObj(ctx, &v1beta2.Tortoise{}, "mercari") if err != nil { Expect(apierrors.IsNotFound(err)).To(Equal(true)) } @@ -209,7 +209,7 @@ var _ = Describe("Test TortoiseController", func() { time.Sleep(1 * time.Second) tc := testCase{want: newResource(filepath.Join(path, "after"))} Eventually(func(g Gomega) { - gotTortoise := &v1beta1.Tortoise{} + gotTortoise := &v1beta2.Tortoise{} err := k8sClient.Get(ctx, client.ObjectKey{Namespace: "default", Name: "mercari"}, gotTortoise) g.Expect(err).ShouldNot(HaveOccurred()) var gotHPA *v2.HorizontalPodAutoscaler @@ -231,9 +231,9 @@ var _ = Describe("Test TortoiseController", func() { err = k8sClient.Get(ctx, client.ObjectKey{Namespace: "default", Name: "tortoise-monitor-mercari"}, gotMonitorVPA) g.Expect(err).ShouldNot(HaveOccurred()) - err = tc.compare(resources{tortoise: gotTortoise, hpa: gotHPA, vpa: map[v1beta1.VerticalPodAutoscalerRole]*autoscalingv1.VerticalPodAutoscaler{ - v1beta1.VerticalPodAutoscalerRoleUpdater: gotUpdaterVPA, - v1beta1.VerticalPodAutoscalerRoleMonitor: gotMonitorVPA, + err = tc.compare(resources{tortoise: gotTortoise, hpa: gotHPA, vpa: map[v1beta2.VerticalPodAutoscalerRole]*autoscalingv1.VerticalPodAutoscaler{ + v1beta2.VerticalPodAutoscalerRoleUpdater: gotUpdaterVPA, + v1beta2.VerticalPodAutoscalerRoleMonitor: gotMonitorVPA, }}) g.Expect(err).ShouldNot(HaveOccurred()) }).Should(Succeed()) @@ -254,7 +254,7 @@ var _ = Describe("Test TortoiseController", func() { cleanUp() for { // make sure all resources are deleted - t := &v1beta1.Tortoise{} + t := &v1beta2.Tortoise{} err := k8sClient.Get(ctx, client.ObjectKey{Namespace: "default", Name: "mercari"}, t) if apierrors.IsNotFound(err) { break @@ -274,12 +274,12 @@ var _ = Describe("Test TortoiseController", func() { path := filepath.Join("testdata", "reconcile-for-the-single-container-pod-partly-working") r := initializeResourcesFromFiles(ctx, k8sClient, filepath.Join(path, "before")) // We need to dynamically modify the status of the Tortoise object from the file because we need to set time. - r.tortoise.Status.ContainerResourcePhases[0].ResourcePhases[corev1.ResourceCPU] = v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseGatheringData, + r.tortoise.Status.ContainerResourcePhases[0].ResourcePhases[corev1.ResourceCPU] = v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.Now(), } - v := &v1beta1.Tortoise{} + v := &v1beta2.Tortoise{} err := k8sClient.Get(ctx, client.ObjectKey{Namespace: r.tortoise.Namespace, Name: r.tortoise.Name}, v) Expect(err).NotTo(HaveOccurred()) @@ -295,16 +295,16 @@ var _ = Describe("Test TortoiseController", func() { path := filepath.Join("testdata", "reconcile-for-the-single-container-pod-gathering-data") r := initializeResourcesFromFiles(ctx, k8sClient, filepath.Join(path, "before")) // We need to dynamically modify the status of the Tortoise object from the file because we need to set time. - r.tortoise.Status.ContainerResourcePhases[0].ResourcePhases[corev1.ResourceCPU] = v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseGatheringData, + r.tortoise.Status.ContainerResourcePhases[0].ResourcePhases[corev1.ResourceCPU] = v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.Now(), } - r.tortoise.Status.ContainerResourcePhases[0].ResourcePhases[corev1.ResourceMemory] = v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseGatheringData, + r.tortoise.Status.ContainerResourcePhases[0].ResourcePhases[corev1.ResourceMemory] = v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.Now(), } - v := &v1beta1.Tortoise{} + v := &v1beta2.Tortoise{} err := k8sClient.Get(ctx, client.ObjectKey{Namespace: r.tortoise.Namespace, Name: r.tortoise.Name}, v) Expect(err).NotTo(HaveOccurred()) @@ -368,7 +368,7 @@ var _ = Describe("Test TortoiseController", func() { Eventually(func(g Gomega) { // make sure all resources are deleted - err = k8sClient.Get(ctx, client.ObjectKey{Namespace: "default", Name: "mercari"}, &v1beta1.Tortoise{}) + err = k8sClient.Get(ctx, client.ObjectKey{Namespace: "default", Name: "mercari"}, &v1beta2.Tortoise{}) g.Expect(apierrors.IsNotFound(err)).To(Equal(true)) err = k8sClient.Get(ctx, client.ObjectKey{Namespace: "default", Name: "tortoise-hpa-mercari"}, &v2.HorizontalPodAutoscaler{}) g.Expect(apierrors.IsNotFound(err)).To(Equal(true)) @@ -393,7 +393,7 @@ var _ = Describe("Test TortoiseController", func() { Expect(err).ShouldNot(HaveOccurred()) err = k8sClient.Get(ctx, client.ObjectKey{Namespace: "default", Name: "tortoise-monitor-mercari"}, &autoscalingv1.VerticalPodAutoscaler{}) Expect(err).ShouldNot(HaveOccurred()) - err = k8sClient.Get(ctx, client.ObjectKey{Namespace: "default", Name: "mercari"}, &v1beta1.Tortoise{}) + err = k8sClient.Get(ctx, client.ObjectKey{Namespace: "default", Name: "mercari"}, &v1beta2.Tortoise{}) g.Expect(apierrors.IsNotFound(err)).To(Equal(true)) }).Should(Succeed()) }) @@ -405,14 +405,14 @@ type testCase struct { } type resources struct { - tortoise *v1beta1.Tortoise + tortoise *v1beta2.Tortoise deployment *v1.Deployment hpa *v2.HorizontalPodAutoscaler - vpa map[v1beta1.VerticalPodAutoscalerRole]*autoscalingv1.VerticalPodAutoscaler + vpa map[v1beta2.VerticalPodAutoscalerRole]*autoscalingv1.VerticalPodAutoscaler } func (t *testCase) compare(got resources) error { - if d := cmp.Diff(t.want.tortoise, got.tortoise, cmpopts.IgnoreFields(v1beta1.Tortoise{}, "ObjectMeta"), cmpopts.IgnoreTypes(metav1.Time{})); d != "" { + if d := cmp.Diff(t.want.tortoise, got.tortoise, cmpopts.IgnoreFields(v1beta2.Tortoise{}, "ObjectMeta"), cmpopts.IgnoreTypes(metav1.Time{})); d != "" { return fmt.Errorf("unexpected tortoise: diff = %s", d) } if d := cmp.Diff(t.want.hpa, got.hpa, cmpopts.IgnoreFields(v2.HorizontalPodAutoscaler{}, "ObjectMeta"), cmpopts.IgnoreTypes(metav1.Time{})); d != "" { diff --git a/go.mod b/go.mod index 5802acb1..fad261e7 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( k8s.io/klog/v2 v2.90.1 k8s.io/utils v0.0.0-20230209194617-a36077c30491 sigs.k8s.io/controller-runtime v0.15.1 + sigs.k8s.io/yaml v1.3.0 ) require ( @@ -72,5 +73,4 @@ require ( k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/main.go b/main.go index 6b6a921b..174719d1 100644 --- a/main.go +++ b/main.go @@ -40,6 +40,7 @@ import ( autoscalingv2 "github.com/mercari/tortoise/api/autoscaling/v2" autoscalingv1alpha1 "github.com/mercari/tortoise/api/v1alpha1" autoscalingv1beta1 "github.com/mercari/tortoise/api/v1beta1" + autoscalingv1beta2 "github.com/mercari/tortoise/api/v1beta2" "github.com/mercari/tortoise/controllers" "github.com/mercari/tortoise/pkg/config" "github.com/mercari/tortoise/pkg/deployment" @@ -63,6 +64,7 @@ func init() { utilruntime.Must(autoscalingv1alpha1.AddToScheme(scheme)) utilruntime.Must(autoscalingv1beta1.AddToScheme(scheme)) + utilruntime.Must(autoscalingv1beta2.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme } @@ -147,11 +149,7 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "Tortoise") os.Exit(1) } - if err = (&autoscalingv1alpha1.Tortoise{}).SetupWebhookWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create webhook", "webhook", "Tortoise") - os.Exit(1) - } - if err = (&autoscalingv1beta1.Tortoise{}).SetupWebhookWithManager(mgr); err != nil { + if err = (&autoscalingv1beta2.Tortoise{}).SetupWebhookWithManager(mgr); err != nil { setupLog.Error(err, "unable to create webhook", "webhook", "Tortoise") os.Exit(1) } diff --git a/manifests/crd/apiextensions.k8s.io_v1_customresourcedefinition_tortoises.autoscaling.mercari.com.yaml b/manifests/crd/apiextensions.k8s.io_v1_customresourcedefinition_tortoises.autoscaling.mercari.com.yaml index 48d2efbb..82bf2229 100644 --- a/manifests/crd/apiextensions.k8s.io_v1_customresourcedefinition_tortoises.autoscaling.mercari.com.yaml +++ b/manifests/crd/apiextensions.k8s.io_v1_customresourcedefinition_tortoises.autoscaling.mercari.com.yaml @@ -640,6 +640,362 @@ spec: type: object type: object served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.updateMode + name: MODE + type: string + - jsonPath: .status.tortoisePhase + name: PHASE + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: Tortoise is the Schema for the tortoises API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TortoiseSpec defines the desired state of Tortoise + properties: + deletionPolicy: + description: "DeletionPolicy is the policy how the controller deletes associated HPA and VPAs when tortoise is removed. If \"DeleteAll\", tortoise deletes all associated HPA and VPAs, created by tortoise. If the associated HPA is not created by tortoise, which is associated by spec.targetRefs.horizontalPodAutoscalerName, tortoise never delete the HPA. If \"NoDelete\", tortoise doesn't delete any associated HPA and VPAs. \n \"NoDelete\" is the default value." + enum: + - DeleteAll + - NoDelete + type: string + resourcePolicy: + description: ResourcePolicy contains the policy how each resource is updated. + items: + properties: + autoscalingPolicy: + additionalProperties: + enum: + - "Off" + - Horizontal + - Vertical + type: string + description: "AutoscalingPolicy specifies how each resource is scaled. If \"Horizontal\", the resource is horizontally scaled. If \"Vertical\", the resource is vertically scaled. If \"Off\", tortoise doesn't scale at all based on that resource. \n The default value is \"Horizontal\" for cpu, and \"Vertical\" for memory." + type: object + containerName: + description: ContainerName is the name of target container. + type: string + minAllocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: "MinAllocatedResources is the minimum amount of resources which is given to the container. Tortoise never set the resources request on the container than MinAllocatedResources. \n If empty, tortoise may reduce the resource request to the value which is suggested from VPA. Leaving this field empty is basically safe, but you may consider using MinAllocatedResources when maybe your application will consume resources more than usual, given the VPA suggests values based on the historical resource usage. For example, your application will soon have new feature which leads to increase in the resource usage, it is expected that your application will soon get more requests than usual, etc." + type: object + required: + - containerName + type: object + type: array + targetRefs: + description: TargetRefs has reference to involved resources. + properties: + horizontalPodAutoscalerName: + description: "HorizontalPodAutoscalerName is the name of the target HPA. The target of this HPA should be the same as the ScaleTargetRef above. The target HPA should have the ContainerResource type metric or the external metric refers to the container resource utilization. Please check out the document for more detail: https://github.com/mercari/tortoise/blob/master/docs/horizontal.md#supported-metrics-in-hpa \n You can specify either of existing HPA only. This is an optional field, and if you don't specify this field, tortoise will create a new default HPA named `tortoise-hpa-{tortoise name}`." + type: string + scaleTargetRef: + description: ScaleTargetRef is the target of scaling. It should be the same as the target of HPA. + properties: + apiVersion: + description: apiVersion is the API version of the referent + type: string + kind: + description: 'kind is the kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'name is the name of the referent; More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + required: + - kind + - name + type: object + required: + - scaleTargetRef + type: object + updateMode: + description: "UpdateMode is how tortoise update resources. If \"Off\", tortoise generates the recommendations in .Status, but doesn't apply it actually. If \"Auto\", tortoise generates the recommendations in .Status, and apply it to resources. If \"Emergency\", tortoise generates the recommendations in .Status as usual, but increase replica number high enough value. \"Emergency\" is useful when something unexpected happens in workloads, and you want to scale up the workload with high enough resources. See https://github.com/mercari/tortoise/blob/main/docs/emergency.md to know more about emergency mode. \n \"Off\" is the default value." + enum: + - "Off" + - Auto + - Emergency + type: string + required: + - targetRefs + type: object + status: + description: TortoiseStatus defines the observed state of Tortoise + properties: + conditions: + properties: + containerRecommendationFromVPA: + description: ContainerRecommendationFromVPA is the condition of container recommendation from VPA, which is observed last time. + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + maxRecommendation: + additionalProperties: + properties: + quantity: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + updatedAt: + format: date-time + type: string + type: object + description: MaxRecommendation is the max recommendation value from VPA in a certain period (1 week). Tortoise generates all recommendation based on this MaxRecommendation. + type: object + recommendation: + additionalProperties: + properties: + quantity: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + updatedAt: + format: date-time + type: string + type: object + description: Recommendation is the latest recommendation value from VPA. + type: object + required: + - containerName + - maxRecommendation + - recommendation + type: object + type: array + tortoiseConditions: + description: TortoiseConditions is the condition of this tortoise. + items: + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another + format: date-time + type: string + lastUpdateTime: + description: The last time this condition was updated. + format: date-time + type: string + message: + description: message is a human-readable explanation containing details about the transition + type: string + reason: + description: reason is the reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. (True, False, Unknown) + type: string + type: + description: Type is the type of the condition. + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + containerResourcePhases: + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + resourcePhases: + additionalProperties: + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another + format: date-time + type: string + phase: + type: string + required: + - phase + type: object + description: ResourcePhases is the phase of each resource of this container. + type: object + required: + - containerName + - resourcePhases + type: object + type: array + recommendations: + properties: + horizontal: + properties: + maxReplicas: + description: MaxReplicas has the recommendation of maxReplicas. It contains the recommendations for each time slot. + items: + properties: + from: + description: From represented in hour. + type: integer + timezone: + type: string + to: + description: To represented in hour. + type: integer + updatedAt: + format: date-time + type: string + value: + description: Value is the recommendation value. It's calculated every reconciliation, and updated if the calculated recommendation value is more than the current recommendation value on tortoise. + format: int32 + type: integer + weekday: + description: WeekDay is the day of the week. If empty, it means it applies to all days of the week. + type: string + required: + - from + - timezone + - to + - value + type: object + type: array + minReplicas: + description: MinReplicas has the recommendation of minReplicas. It contains the recommendations for each time slot. + items: + properties: + from: + description: From represented in hour. + type: integer + timezone: + type: string + to: + description: To represented in hour. + type: integer + updatedAt: + format: date-time + type: string + value: + description: Value is the recommendation value. It's calculated every reconciliation, and updated if the calculated recommendation value is more than the current recommendation value on tortoise. + format: int32 + type: integer + weekday: + description: WeekDay is the day of the week. If empty, it means it applies to all days of the week. + type: string + required: + - from + - timezone + - to + - value + type: object + type: array + targetUtilizations: + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + targetUtilization: + additionalProperties: + format: int32 + type: integer + description: TargetUtilization is the recommendation of targetUtilization of HPA. + type: object + required: + - containerName + - targetUtilization + type: object + type: array + type: object + vertical: + properties: + containerResourceRecommendation: + items: + properties: + RecommendedResource: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: RecommendedResource is the recommendation calculated by the tortoise. If AutoscalingPolicy is vertical, it's the same value as the VPA suggests. If AutoscalingPolicy is horizontal, it's basically the same value as the current resource request. But, when the number of replicas are too small or too large, tortoise may try to increase/decrease the amount of resources given to the container, so that the number of replicas won't be very small or very large. + type: object + containerName: + description: ContainerName is the name of target container. + type: string + required: + - RecommendedResource + - containerName + type: object + type: array + type: object + type: object + targets: + properties: + horizontalPodAutoscaler: + type: string + scaleTargetRef: + description: CrossVersionObjectReference contains enough information toet identify the referred resource. + properties: + apiVersion: + description: apiVersion is the API version of the referent + type: string + kind: + description: 'kind is the kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'name is the name of the referent; More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + required: + - kind + - name + type: object + verticalPodAutoscalers: + items: + properties: + name: + type: string + role: + enum: + - Updater + - Monitor + type: string + required: + - name + - role + type: object + type: array + required: + - scaleTargetRef + - verticalPodAutoscalers + type: object + tortoisePhase: + type: string + required: + - conditions + - containerResourcePhases + - recommendations + - targets + - tortoisePhase + type: object + type: object + served: true storage: true subresources: status: {} diff --git a/manifests/default/admissionregistration.k8s.io_v1_mutatingwebhookconfiguration_tortoise-mutating-webhook-configuration.yaml b/manifests/default/admissionregistration.k8s.io_v1_mutatingwebhookconfiguration_tortoise-mutating-webhook-configuration.yaml index 6d81114f..fb9f01f8 100644 --- a/manifests/default/admissionregistration.k8s.io_v1_mutatingwebhookconfiguration_tortoise-mutating-webhook-configuration.yaml +++ b/manifests/default/admissionregistration.k8s.io_v1_mutatingwebhookconfiguration_tortoise-mutating-webhook-configuration.yaml @@ -11,14 +11,14 @@ webhooks: service: name: tortoise-webhook-service namespace: tortoise-system - path: /mutate-autoscaling-mercari-com-v1beta1-tortoise + path: /mutate-autoscaling-mercari-com-v1beta2-tortoise failurePolicy: Fail name: mtortoise.kb.io rules: - apiGroups: - autoscaling.mercari.com apiVersions: - - v1beta1 + - v1beta2 operations: - CREATE - UPDATE diff --git a/manifests/default/admissionregistration.k8s.io_v1_validatingwebhookconfiguration_tortoise-validating-webhook-configuration.yaml b/manifests/default/admissionregistration.k8s.io_v1_validatingwebhookconfiguration_tortoise-validating-webhook-configuration.yaml index a6a2f2df..d0a7445f 100644 --- a/manifests/default/admissionregistration.k8s.io_v1_validatingwebhookconfiguration_tortoise-validating-webhook-configuration.yaml +++ b/manifests/default/admissionregistration.k8s.io_v1_validatingwebhookconfiguration_tortoise-validating-webhook-configuration.yaml @@ -11,14 +11,14 @@ webhooks: service: name: tortoise-webhook-service namespace: tortoise-system - path: /validate-autoscaling-mercari-com-v1beta1-tortoise + path: /validate-autoscaling-mercari-com-v1beta2-tortoise failurePolicy: Fail name: vtortoise.kb.io rules: - apiGroups: - autoscaling.mercari.com apiVersions: - - v1beta1 + - v1beta2 operations: - CREATE - UPDATE diff --git a/manifests/default/apiextensions.k8s.io_v1_customresourcedefinition_tortoises.autoscaling.mercari.com.yaml b/manifests/default/apiextensions.k8s.io_v1_customresourcedefinition_tortoises.autoscaling.mercari.com.yaml index cf1bac45..d40e7908 100644 --- a/manifests/default/apiextensions.k8s.io_v1_customresourcedefinition_tortoises.autoscaling.mercari.com.yaml +++ b/manifests/default/apiextensions.k8s.io_v1_customresourcedefinition_tortoises.autoscaling.mercari.com.yaml @@ -640,6 +640,362 @@ spec: type: object type: object served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.updateMode + name: MODE + type: string + - jsonPath: .status.tortoisePhase + name: PHASE + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: Tortoise is the Schema for the tortoises API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TortoiseSpec defines the desired state of Tortoise + properties: + deletionPolicy: + description: "DeletionPolicy is the policy how the controller deletes associated HPA and VPAs when tortoise is removed. If \"DeleteAll\", tortoise deletes all associated HPA and VPAs, created by tortoise. If the associated HPA is not created by tortoise, which is associated by spec.targetRefs.horizontalPodAutoscalerName, tortoise never delete the HPA. If \"NoDelete\", tortoise doesn't delete any associated HPA and VPAs. \n \"NoDelete\" is the default value." + enum: + - DeleteAll + - NoDelete + type: string + resourcePolicy: + description: ResourcePolicy contains the policy how each resource is updated. + items: + properties: + autoscalingPolicy: + additionalProperties: + enum: + - "Off" + - Horizontal + - Vertical + type: string + description: "AutoscalingPolicy specifies how each resource is scaled. If \"Horizontal\", the resource is horizontally scaled. If \"Vertical\", the resource is vertically scaled. If \"Off\", tortoise doesn't scale at all based on that resource. \n The default value is \"Horizontal\" for cpu, and \"Vertical\" for memory." + type: object + containerName: + description: ContainerName is the name of target container. + type: string + minAllocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: "MinAllocatedResources is the minimum amount of resources which is given to the container. Tortoise never set the resources request on the container than MinAllocatedResources. \n If empty, tortoise may reduce the resource request to the value which is suggested from VPA. Leaving this field empty is basically safe, but you may consider using MinAllocatedResources when maybe your application will consume resources more than usual, given the VPA suggests values based on the historical resource usage. For example, your application will soon have new feature which leads to increase in the resource usage, it is expected that your application will soon get more requests than usual, etc." + type: object + required: + - containerName + type: object + type: array + targetRefs: + description: TargetRefs has reference to involved resources. + properties: + horizontalPodAutoscalerName: + description: "HorizontalPodAutoscalerName is the name of the target HPA. The target of this HPA should be the same as the ScaleTargetRef above. The target HPA should have the ContainerResource type metric or the external metric refers to the container resource utilization. Please check out the document for more detail: https://github.com/mercari/tortoise/blob/master/docs/horizontal.md#supported-metrics-in-hpa \n You can specify either of existing HPA only. This is an optional field, and if you don't specify this field, tortoise will create a new default HPA named `tortoise-hpa-{tortoise name}`." + type: string + scaleTargetRef: + description: ScaleTargetRef is the target of scaling. It should be the same as the target of HPA. + properties: + apiVersion: + description: apiVersion is the API version of the referent + type: string + kind: + description: 'kind is the kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'name is the name of the referent; More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + required: + - kind + - name + type: object + required: + - scaleTargetRef + type: object + updateMode: + description: "UpdateMode is how tortoise update resources. If \"Off\", tortoise generates the recommendations in .Status, but doesn't apply it actually. If \"Auto\", tortoise generates the recommendations in .Status, and apply it to resources. If \"Emergency\", tortoise generates the recommendations in .Status as usual, but increase replica number high enough value. \"Emergency\" is useful when something unexpected happens in workloads, and you want to scale up the workload with high enough resources. See https://github.com/mercari/tortoise/blob/main/docs/emergency.md to know more about emergency mode. \n \"Off\" is the default value." + enum: + - "Off" + - Auto + - Emergency + type: string + required: + - targetRefs + type: object + status: + description: TortoiseStatus defines the observed state of Tortoise + properties: + conditions: + properties: + containerRecommendationFromVPA: + description: ContainerRecommendationFromVPA is the condition of container recommendation from VPA, which is observed last time. + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + maxRecommendation: + additionalProperties: + properties: + quantity: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + updatedAt: + format: date-time + type: string + type: object + description: MaxRecommendation is the max recommendation value from VPA in a certain period (1 week). Tortoise generates all recommendation based on this MaxRecommendation. + type: object + recommendation: + additionalProperties: + properties: + quantity: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + updatedAt: + format: date-time + type: string + type: object + description: Recommendation is the latest recommendation value from VPA. + type: object + required: + - containerName + - maxRecommendation + - recommendation + type: object + type: array + tortoiseConditions: + description: TortoiseConditions is the condition of this tortoise. + items: + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another + format: date-time + type: string + lastUpdateTime: + description: The last time this condition was updated. + format: date-time + type: string + message: + description: message is a human-readable explanation containing details about the transition + type: string + reason: + description: reason is the reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. (True, False, Unknown) + type: string + type: + description: Type is the type of the condition. + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + containerResourcePhases: + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + resourcePhases: + additionalProperties: + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another + format: date-time + type: string + phase: + type: string + required: + - phase + type: object + description: ResourcePhases is the phase of each resource of this container. + type: object + required: + - containerName + - resourcePhases + type: object + type: array + recommendations: + properties: + horizontal: + properties: + maxReplicas: + description: MaxReplicas has the recommendation of maxReplicas. It contains the recommendations for each time slot. + items: + properties: + from: + description: From represented in hour. + type: integer + timezone: + type: string + to: + description: To represented in hour. + type: integer + updatedAt: + format: date-time + type: string + value: + description: Value is the recommendation value. It's calculated every reconciliation, and updated if the calculated recommendation value is more than the current recommendation value on tortoise. + format: int32 + type: integer + weekday: + description: WeekDay is the day of the week. If empty, it means it applies to all days of the week. + type: string + required: + - from + - timezone + - to + - value + type: object + type: array + minReplicas: + description: MinReplicas has the recommendation of minReplicas. It contains the recommendations for each time slot. + items: + properties: + from: + description: From represented in hour. + type: integer + timezone: + type: string + to: + description: To represented in hour. + type: integer + updatedAt: + format: date-time + type: string + value: + description: Value is the recommendation value. It's calculated every reconciliation, and updated if the calculated recommendation value is more than the current recommendation value on tortoise. + format: int32 + type: integer + weekday: + description: WeekDay is the day of the week. If empty, it means it applies to all days of the week. + type: string + required: + - from + - timezone + - to + - value + type: object + type: array + targetUtilizations: + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + targetUtilization: + additionalProperties: + format: int32 + type: integer + description: TargetUtilization is the recommendation of targetUtilization of HPA. + type: object + required: + - containerName + - targetUtilization + type: object + type: array + type: object + vertical: + properties: + containerResourceRecommendation: + items: + properties: + RecommendedResource: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: RecommendedResource is the recommendation calculated by the tortoise. If AutoscalingPolicy is vertical, it's the same value as the VPA suggests. If AutoscalingPolicy is horizontal, it's basically the same value as the current resource request. But, when the number of replicas are too small or too large, tortoise may try to increase/decrease the amount of resources given to the container, so that the number of replicas won't be very small or very large. + type: object + containerName: + description: ContainerName is the name of target container. + type: string + required: + - RecommendedResource + - containerName + type: object + type: array + type: object + type: object + targets: + properties: + horizontalPodAutoscaler: + type: string + scaleTargetRef: + description: CrossVersionObjectReference contains enough information toet identify the referred resource. + properties: + apiVersion: + description: apiVersion is the API version of the referent + type: string + kind: + description: 'kind is the kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'name is the name of the referent; More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + required: + - kind + - name + type: object + verticalPodAutoscalers: + items: + properties: + name: + type: string + role: + enum: + - Updater + - Monitor + type: string + required: + - name + - role + type: object + type: array + required: + - scaleTargetRef + - verticalPodAutoscalers + type: object + tortoisePhase: + type: string + required: + - conditions + - containerResourcePhases + - recommendations + - targets + - tortoisePhase + type: object + type: object + served: true storage: true subresources: status: {} diff --git a/pkg/deployment/service.go b/pkg/deployment/service.go index ab83e92f..3046f6f0 100644 --- a/pkg/deployment/service.go +++ b/pkg/deployment/service.go @@ -8,7 +8,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - autoscalingv1beta1 "github.com/mercari/tortoise/api/v1beta1" + autoscalingv1beta2 "github.com/mercari/tortoise/api/v1beta2" ) type Service struct { @@ -19,7 +19,7 @@ func New(c client.Client) *Service { return &Service{c: c} } -func (c *Service) GetDeploymentOnTortoise(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise) (*v1.Deployment, error) { +func (c *Service) GetDeploymentOnTortoise(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise) (*v1.Deployment, error) { d := &v1.Deployment{} if err := c.c.Get(ctx, types.NamespacedName{Namespace: tortoise.Namespace, Name: tortoise.Spec.TargetRefs.ScaleTargetRef.Name}, d); err != nil { return nil, fmt.Errorf("failed to get deployment on tortoise: %w", err) diff --git a/pkg/hpa/service.go b/pkg/hpa/service.go index ab218602..20087932 100644 --- a/pkg/hpa/service.go +++ b/pkg/hpa/service.go @@ -21,7 +21,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - autoscalingv1beta1 "github.com/mercari/tortoise/api/v1beta1" + autoscalingv1beta2 "github.com/mercari/tortoise/api/v1beta2" "github.com/mercari/tortoise/pkg/annotation" "github.com/mercari/tortoise/pkg/metrics" ) @@ -43,7 +43,7 @@ func New(c client.Client, recorder record.EventRecorder, replicaReductionFactor } } -func (c *Service) InitializeHPA(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise, dm *v1.Deployment, now time.Time) (*autoscalingv1beta1.Tortoise, error) { +func (c *Service) InitializeHPA(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise, dm *v1.Deployment, now time.Time) (*autoscalingv1beta2.Tortoise, error) { logger := log.FromContext(ctx) // if all policy is off or Vertical, we don't need HPA. if !HasHorizontal(tortoise) { @@ -77,7 +77,7 @@ func (c *Service) InitializeHPA(ctx context.Context, tortoise *autoscalingv1beta return tortoise, nil } -func (c *Service) giveAnnotationsOnExistingHPA(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise) (*autoscalingv1beta1.Tortoise, error) { +func (c *Service) giveAnnotationsOnExistingHPA(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise) (*autoscalingv1beta2.Tortoise, error) { if tortoise.Spec.TargetRefs.HorizontalPodAutoscalerName == nil { // shouldn't reach here since the caller should check this. return tortoise, fmt.Errorf("tortoise.Spec.TargetRefs.HorizontalPodAutoscalerName is nil") @@ -102,8 +102,8 @@ func (c *Service) giveAnnotationsOnExistingHPA(ctx context.Context, tortoise *au return tortoise, retry.RetryOnConflict(retry.DefaultRetry, updateFn) } -func (c *Service) DeleteHPACreatedByTortoise(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise) error { - if tortoise.Spec.DeletionPolicy == autoscalingv1beta1.DeletionPolicyNoDelete { +func (c *Service) DeleteHPACreatedByTortoise(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise) error { + if tortoise.Spec.DeletionPolicy == autoscalingv1beta2.DeletionPolicyNoDelete { // A user specified the existing HPA and tortoise didn't create HPA by itself. return nil } @@ -140,7 +140,7 @@ type resourceNameAndContainerName struct { // addHPAMetricsFromTortoiseAutoscalingPolicy adds metrics to the HPA based on the autoscaling policy in the tortoise. // Note that it doesn't update the HPA in kube-apiserver, you have to do that after this function. -func (c *Service) addHPAMetricsFromTortoiseAutoscalingPolicy(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise, currenthpa *v2.HorizontalPodAutoscaler, now time.Time) (*v2.HorizontalPodAutoscaler, *autoscalingv1beta1.Tortoise, bool) { +func (c *Service) addHPAMetricsFromTortoiseAutoscalingPolicy(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise, currenthpa *v2.HorizontalPodAutoscaler, now time.Time) (*v2.HorizontalPodAutoscaler, *autoscalingv1beta2.Tortoise, bool) { hpaEdited := false policies := sets.New[string]() @@ -148,7 +148,7 @@ func (c *Service) addHPAMetricsFromTortoiseAutoscalingPolicy(ctx context.Context for _, p := range tortoise.Spec.ResourcePolicy { policies.Insert(p.ContainerName) for rn, ap := range p.AutoscalingPolicy { - if ap == autoscalingv1beta1.AutoscalingTypeHorizontal { + if ap == autoscalingv1beta2.AutoscalingTypeHorizontal { horizontalResourceAndContainer.Insert(resourceNameAndContainerName{rn, p.ContainerName}) } } @@ -189,8 +189,8 @@ func (c *Service) addHPAMetricsFromTortoiseAutoscalingPolicy(ctx context.Context found := false for i, p := range tortoise.Status.ContainerResourcePhases { if p.ContainerName == d.containerName { - tortoise.Status.ContainerResourcePhases[i].ResourcePhases[d.rn] = autoscalingv1beta1.ResourcePhase{ - Phase: autoscalingv1beta1.ContainerResourcePhaseGatheringData, + tortoise.Status.ContainerResourcePhases[i].ResourcePhases[d.rn] = autoscalingv1beta2.ResourcePhase{ + Phase: autoscalingv1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.NewTime(now), } @@ -199,11 +199,11 @@ func (c *Service) addHPAMetricsFromTortoiseAutoscalingPolicy(ctx context.Context } } if !found { - tortoise.Status.ContainerResourcePhases = append(tortoise.Status.ContainerResourcePhases, autoscalingv1beta1.ContainerResourcePhases{ + tortoise.Status.ContainerResourcePhases = append(tortoise.Status.ContainerResourcePhases, autoscalingv1beta2.ContainerResourcePhases{ ContainerName: d.containerName, - ResourcePhases: map[corev1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[corev1.ResourceName]autoscalingv1beta2.ResourcePhase{ d.rn: { - Phase: autoscalingv1beta1.ContainerResourcePhaseGatheringData, + Phase: autoscalingv1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.NewTime(now), }, }, @@ -228,7 +228,7 @@ func (c *Service) addHPAMetricsFromTortoiseAutoscalingPolicy(ctx context.Context return currenthpa, tortoise, hpaEdited } -func (c *Service) CreateHPA(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise, dm *v1.Deployment, now time.Time) (*v2.HorizontalPodAutoscaler, *autoscalingv1beta1.Tortoise, error) { +func (c *Service) CreateHPA(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise, dm *v1.Deployment, now time.Time) (*v2.HorizontalPodAutoscaler, *autoscalingv1beta2.Tortoise, error) { if !HasHorizontal(tortoise) { // no need to create HPA return nil, tortoise, nil @@ -240,7 +240,7 @@ func (c *Service) CreateHPA(ctx context.Context, tortoise *autoscalingv1beta1.To hpa := &v2.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{ - Name: autoscalingv1beta1.TortoiseDefaultHPAName(tortoise.Name), + Name: autoscalingv1beta2.TortoiseDefaultHPAName(tortoise.Name), Namespace: tortoise.Namespace, Annotations: map[string]string{ annotation.TortoiseNameAnnotation: tortoise.Name, @@ -286,7 +286,7 @@ func (c *Service) CreateHPA(ctx context.Context, tortoise *autoscalingv1beta1.To return hpa.DeepCopy(), tortoise, err } -func (c *Service) GetHPAOnTortoise(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise) (*v2.HorizontalPodAutoscaler, error) { +func (c *Service) GetHPAOnTortoise(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise) (*v2.HorizontalPodAutoscaler, error) { if !HasHorizontal(tortoise) { // there should be no HPA return nil, nil @@ -298,18 +298,18 @@ func (c *Service) GetHPAOnTortoise(ctx context.Context, tortoise *autoscalingv1b return hpa, nil } -func (c *Service) ChangeHPAFromTortoiseRecommendation(tortoise *autoscalingv1beta1.Tortoise, hpa *v2.HorizontalPodAutoscaler, now time.Time, recordMetrics bool) (*v2.HorizontalPodAutoscaler, *autoscalingv1beta1.Tortoise, error) { +func (c *Service) ChangeHPAFromTortoiseRecommendation(tortoise *autoscalingv1beta2.Tortoise, hpa *v2.HorizontalPodAutoscaler, now time.Time, recordMetrics bool) (*v2.HorizontalPodAutoscaler, *autoscalingv1beta2.Tortoise, error) { readyHorizontalResourceAndContainer := sets.New[resourceNameAndContainerName]() for _, p := range tortoise.Spec.ResourcePolicy { for rn, ap := range p.AutoscalingPolicy { - if ap == autoscalingv1beta1.AutoscalingTypeHorizontal { + if ap == autoscalingv1beta2.AutoscalingTypeHorizontal { readyHorizontalResourceAndContainer.Insert(resourceNameAndContainerName{rn, p.ContainerName}) } } } for _, p := range tortoise.Status.ContainerResourcePhases { for rn, phase := range p.ResourcePhases { - if phase.Phase != autoscalingv1beta1.ContainerResourcePhaseWorking { + if phase.Phase != autoscalingv1beta2.ContainerResourcePhaseWorking { readyHorizontalResourceAndContainer.Delete(resourceNameAndContainerName{rn, p.ContainerName}) } } @@ -336,10 +336,10 @@ func (c *Service) ChangeHPAFromTortoiseRecommendation(tortoise *autoscalingv1bet var min int32 switch tortoise.Status.TortoisePhase { - case autoscalingv1beta1.TortoisePhaseEmergency: + case autoscalingv1beta2.TortoisePhaseEmergency: // when emergency mode, we set the same value on minReplicas. min = max - case autoscalingv1beta1.TortoisePhaseBackToNormal: + case autoscalingv1beta2.TortoisePhaseBackToNormal: idealMin, err := GetReplicasRecommendation(tortoise.Status.Recommendations.Horizontal.MinReplicas, now) if err != nil { return nil, tortoise, fmt.Errorf("get minReplicas recommendation: %w", err) @@ -349,7 +349,7 @@ func (c *Service) ChangeHPAFromTortoiseRecommendation(tortoise *autoscalingv1bet if idealMin > reduced { min = idealMin // BackToNormal is finished - tortoise.Status.TortoisePhase = autoscalingv1beta1.TortoisePhaseWorking + tortoise.Status.TortoisePhase = autoscalingv1beta2.TortoisePhaseWorking } else { min = reduced } @@ -366,7 +366,7 @@ func (c *Service) ChangeHPAFromTortoiseRecommendation(tortoise *autoscalingv1bet return hpa, tortoise, nil } -func (c *Service) UpdateHPASpecFromTortoiseAutoscalingPolicy(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise, dm *v1.Deployment, now time.Time) (*autoscalingv1beta1.Tortoise, error) { +func (c *Service) UpdateHPASpecFromTortoiseAutoscalingPolicy(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise, dm *v1.Deployment, now time.Time) (*autoscalingv1beta2.Tortoise, error) { if !HasHorizontal(tortoise) { err := c.DeleteHPACreatedByTortoise(ctx, tortoise) if err != nil && !apierrors.IsNotFound(err) { @@ -430,10 +430,10 @@ func (c *Service) UpdateHPASpecFromTortoiseAutoscalingPolicy(ctx context.Context return tortoise, nil } -func HasHorizontal(tortoise *autoscalingv1beta1.Tortoise) bool { +func HasHorizontal(tortoise *autoscalingv1beta2.Tortoise) bool { for _, r := range tortoise.Spec.ResourcePolicy { for _, p := range r.AutoscalingPolicy { - if p == autoscalingv1beta1.AutoscalingTypeHorizontal { + if p == autoscalingv1beta2.AutoscalingTypeHorizontal { return true } } @@ -441,13 +441,13 @@ func HasHorizontal(tortoise *autoscalingv1beta1.Tortoise) bool { return false } -func (c *Service) UpdateHPAFromTortoiseRecommendation(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise, now time.Time) (*v2.HorizontalPodAutoscaler, *autoscalingv1beta1.Tortoise, error) { +func (c *Service) UpdateHPAFromTortoiseRecommendation(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise, now time.Time) (*v2.HorizontalPodAutoscaler, *autoscalingv1beta2.Tortoise, error) { // if all policy is off or Vertical, we don't update HPA. if !HasHorizontal(tortoise) { return nil, tortoise, nil } - retTortoise := &autoscalingv1beta1.Tortoise{} + retTortoise := &autoscalingv1beta2.Tortoise{} retHPA := &v2.HorizontalPodAutoscaler{} // we only want to record metric once in every reconcile loop. @@ -465,7 +465,7 @@ func (c *Service) UpdateHPAFromTortoiseRecommendation(ctx context.Context, torto } metricsRecorded = true retTortoise = tortoise - if tortoise.Spec.UpdateMode == autoscalingv1beta1.UpdateModeOff { + if tortoise.Spec.UpdateMode == autoscalingv1beta2.UpdateModeOff { // don't update status if update mode is off. (= dryrun) return nil } @@ -477,7 +477,7 @@ func (c *Service) UpdateHPAFromTortoiseRecommendation(ctx context.Context, torto return nil, nil, err } - if tortoise.Spec.UpdateMode != autoscalingv1beta1.UpdateModeOff { + if tortoise.Spec.UpdateMode != autoscalingv1beta2.UpdateModeOff { c.recorder.Event(tortoise, corev1.EventTypeNormal, "HPAUpdated", fmt.Sprintf("HPA %s/%s is updated by the recommendation", retHPA.Namespace, retHPA.Name)) } @@ -485,7 +485,7 @@ func (c *Service) UpdateHPAFromTortoiseRecommendation(ctx context.Context, torto } // GetReplicasRecommendation finds the corresponding recommendations. -func GetReplicasRecommendation(recommendations []autoscalingv1beta1.ReplicasRecommendation, now time.Time) (int32, error) { +func GetReplicasRecommendation(recommendations []autoscalingv1beta2.ReplicasRecommendation, now time.Time) (int32, error) { for _, r := range recommendations { if now.Hour() < r.To && now.Hour() >= r.From && (r.WeekDay == nil || now.Weekday().String() == *r.WeekDay) { return r.Value, nil diff --git a/pkg/hpa/service_test.go b/pkg/hpa/service_test.go index 789a1341..860f2b15 100644 --- a/pkg/hpa/service_test.go +++ b/pkg/hpa/service_test.go @@ -17,8 +17,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/mercari/tortoise/api/v1beta1" - autoscalingv1beta1 "github.com/mercari/tortoise/api/v1beta1" + "github.com/mercari/tortoise/api/v1beta2" + autoscalingv1beta2 "github.com/mercari/tortoise/api/v1beta2" "github.com/mercari/tortoise/pkg/annotation" ) @@ -27,7 +27,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { type args struct { ctx context.Context - tortoise *autoscalingv1beta1.Tortoise + tortoise *autoscalingv1beta2.Tortoise now time.Time } tests := []struct { @@ -35,55 +35,55 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { args args initialHPA *v2.HorizontalPodAutoscaler want *v2.HorizontalPodAutoscaler - wantTortoise *autoscalingv1beta1.Tortoise + wantTortoise *autoscalingv1beta2.Tortoise wantErr bool }{ { name: "Basic test case with container resource metrics", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta1.Tortoise{ - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + tortoise: &autoscalingv1beta2.Tortoise{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - ContainerResourcePhases: []autoscalingv1beta1.ContainerResourcePhases{ + Status: autoscalingv1beta2.TortoiseStatus{ + ContainerResourcePhases: []autoscalingv1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta1.TargetsStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta1.Recommendations{ - Horizontal: autoscalingv1beta1.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta1.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: autoscalingv1beta2.Recommendations{ + Horizontal: autoscalingv1beta2.HorizontalRecommendations{ + TargetUtilizations: []autoscalingv1beta2.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -97,7 +97,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MaxReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -106,7 +106,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: pointer.String(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MinReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -197,49 +197,49 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "no update preformed when updateMode is Off", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta1.Tortoise{ - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + tortoise: &autoscalingv1beta2.Tortoise{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, - UpdateMode: autoscalingv1beta1.UpdateModeOff, + UpdateMode: autoscalingv1beta2.UpdateModeOff, }, - Status: autoscalingv1beta1.TortoiseStatus{ - ContainerResourcePhases: []autoscalingv1beta1.ContainerResourcePhases{ + Status: autoscalingv1beta2.TortoiseStatus{ + ContainerResourcePhases: []autoscalingv1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta1.TargetsStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta1.Recommendations{ - Horizontal: autoscalingv1beta1.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta1.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: autoscalingv1beta2.Recommendations{ + Horizontal: autoscalingv1beta2.HorizontalRecommendations{ + TargetUtilizations: []autoscalingv1beta2.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -253,7 +253,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MaxReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -262,7 +262,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: pointer.String(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MinReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -353,49 +353,49 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "no update preformed when ContainerResourcePhases isn't working", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta1.Tortoise{ - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + tortoise: &autoscalingv1beta2.Tortoise{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, - UpdateMode: autoscalingv1beta1.UpdateModeAuto, + UpdateMode: autoscalingv1beta2.UpdateModeAuto, }, - Status: autoscalingv1beta1.TortoiseStatus{ - ContainerResourcePhases: []autoscalingv1beta1.ContainerResourcePhases{ + Status: autoscalingv1beta2.TortoiseStatus{ + ContainerResourcePhases: []autoscalingv1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseGatheringData, + Phase: autoscalingv1beta2.ContainerResourcePhaseGatheringData, }, }, }, }, - Targets: autoscalingv1beta1.TargetsStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta1.Recommendations{ - Horizontal: autoscalingv1beta1.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta1.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: autoscalingv1beta2.Recommendations{ + Horizontal: autoscalingv1beta2.HorizontalRecommendations{ + TargetUtilizations: []autoscalingv1beta2.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -409,7 +409,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MaxReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -418,7 +418,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: pointer.String(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MinReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -509,31 +509,31 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "emergency mode", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta1.Tortoise{ - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + tortoise: &autoscalingv1beta2.Tortoise{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - Targets: autoscalingv1beta1.TargetsStatus{ + Status: autoscalingv1beta2.TortoiseStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - TortoisePhase: autoscalingv1beta1.TortoisePhaseEmergency, - Recommendations: autoscalingv1beta1.Recommendations{ - Horizontal: autoscalingv1beta1.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta1.HPATargetUtilizationRecommendationPerContainer{ + TortoisePhase: autoscalingv1beta2.TortoisePhaseEmergency, + Recommendations: autoscalingv1beta2.Recommendations{ + Horizontal: autoscalingv1beta2.HorizontalRecommendations{ + TargetUtilizations: []autoscalingv1beta2.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -547,7 +547,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MaxReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -556,7 +556,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: pointer.String(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MinReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -647,31 +647,31 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "minReplicas are reduced gradually during BackToNormal", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta1.Tortoise{ - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + tortoise: &autoscalingv1beta2.Tortoise{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - Targets: autoscalingv1beta1.TargetsStatus{ + Status: autoscalingv1beta2.TortoiseStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - TortoisePhase: autoscalingv1beta1.TortoisePhaseBackToNormal, - Recommendations: autoscalingv1beta1.Recommendations{ - Horizontal: autoscalingv1beta1.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta1.HPATargetUtilizationRecommendationPerContainer{ + TortoisePhase: autoscalingv1beta2.TortoisePhaseBackToNormal, + Recommendations: autoscalingv1beta2.Recommendations{ + Horizontal: autoscalingv1beta2.HorizontalRecommendations{ + TargetUtilizations: []autoscalingv1beta2.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -685,7 +685,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MaxReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -694,7 +694,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: pointer.String(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MinReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -785,31 +785,31 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "BackToNormal finishes when minReplicas reaches the ideal value", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta1.Tortoise{ - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + tortoise: &autoscalingv1beta2.Tortoise{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - Targets: autoscalingv1beta1.TargetsStatus{ + Status: autoscalingv1beta2.TortoiseStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - TortoisePhase: autoscalingv1beta1.TortoisePhaseBackToNormal, - Recommendations: autoscalingv1beta1.Recommendations{ - Horizontal: autoscalingv1beta1.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta1.HPATargetUtilizationRecommendationPerContainer{ + TortoisePhase: autoscalingv1beta2.TortoisePhaseBackToNormal, + Recommendations: autoscalingv1beta2.Recommendations{ + Horizontal: autoscalingv1beta2.HorizontalRecommendations{ + TargetUtilizations: []autoscalingv1beta2.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -823,7 +823,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MaxReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -832,7 +832,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: pointer.String(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MinReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -917,31 +917,31 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta1.Tortoise{ - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + wantTortoise: &autoscalingv1beta2.Tortoise{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - Targets: autoscalingv1beta1.TargetsStatus{ + Status: autoscalingv1beta2.TortoiseStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - TortoisePhase: autoscalingv1beta1.TortoisePhaseWorking, - Recommendations: autoscalingv1beta1.Recommendations{ - Horizontal: autoscalingv1beta1.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta1.HPATargetUtilizationRecommendationPerContainer{ + TortoisePhase: autoscalingv1beta2.TortoisePhaseWorking, + Recommendations: autoscalingv1beta2.Recommendations{ + Horizontal: autoscalingv1beta2.HorizontalRecommendations{ + TargetUtilizations: []autoscalingv1beta2.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -955,7 +955,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MaxReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -964,7 +964,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: pointer.String(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta1.ReplicasRecommendation{ + MinReplicas: []autoscalingv1beta2.ReplicasRecommendation{ { From: 0, To: 2, @@ -1007,7 +1007,7 @@ func ptrInt32(i int32) *int32 { func TestService_InitializeHPA(t *testing.T) { type args struct { - tortoise *autoscalingv1beta1.Tortoise + tortoise *autoscalingv1beta2.Tortoise dm *appv1.Deployment } tests := []struct { @@ -1020,30 +1020,30 @@ func TestService_InitializeHPA(t *testing.T) { { name: "should create new hpa", args: args{ - tortoise: &autoscalingv1beta1.Tortoise{ + tortoise: &autoscalingv1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, - TargetRefs: autoscalingv1beta1.TargetRefs{ - ScaleTargetRef: autoscalingv1beta1.CrossVersionObjectReference{ + TargetRefs: autoscalingv1beta2.TargetRefs{ + ScaleTargetRef: autoscalingv1beta2.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", APIVersion: "apps/v1", @@ -1143,25 +1143,25 @@ func TestService_InitializeHPA(t *testing.T) { { name: "just give annotation to existing hpa", args: args{ - tortoise: &autoscalingv1beta1.Tortoise{ + tortoise: &autoscalingv1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta1.TortoiseSpec{ - TargetRefs: autoscalingv1beta1.TargetRefs{ + Spec: autoscalingv1beta2.TortoiseSpec{ + TargetRefs: autoscalingv1beta2.TargetRefs{ HorizontalPodAutoscalerName: pointer.String("existing-hpa"), - ScaleTargetRef: autoscalingv1beta1.CrossVersionObjectReference{ + ScaleTargetRef: autoscalingv1beta2.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, @@ -1273,7 +1273,7 @@ func TestService_InitializeHPA(t *testing.T) { func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { type args struct { - tortoise *autoscalingv1beta1.Tortoise + tortoise *autoscalingv1beta2.Tortoise dm *appv1.Deployment } tests := []struct { @@ -1281,68 +1281,68 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { initialHPA *v2.HorizontalPodAutoscaler args args afterHPA *v2.HorizontalPodAutoscaler - wantTortoise *autoscalingv1beta1.Tortoise + wantTortoise *autoscalingv1beta2.Tortoise wantErr bool }{ { name: "add metrics to existing hpa", args: args{ - tortoise: &autoscalingv1beta1.Tortoise{ + tortoise: &autoscalingv1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, - TargetRefs: autoscalingv1beta1.TargetRefs{ + TargetRefs: autoscalingv1beta2.TargetRefs{ HorizontalPodAutoscalerName: pointer.String("existing-hpa"), - ScaleTargetRef: autoscalingv1beta1.CrossVersionObjectReference{ + ScaleTargetRef: autoscalingv1beta2.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - ContainerResourcePhases: []autoscalingv1beta1.ContainerResourcePhases{ + Status: autoscalingv1beta2.TortoiseStatus{ + ContainerResourcePhases: []autoscalingv1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta1.TargetsStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -1411,62 +1411,62 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta1.Tortoise{ + wantTortoise: &autoscalingv1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, - TargetRefs: autoscalingv1beta1.TargetRefs{ + TargetRefs: autoscalingv1beta2.TargetRefs{ HorizontalPodAutoscalerName: pointer.String("existing-hpa"), - ScaleTargetRef: autoscalingv1beta1.CrossVersionObjectReference{ + ScaleTargetRef: autoscalingv1beta2.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - ContainerResourcePhases: []autoscalingv1beta1.ContainerResourcePhases{ + Status: autoscalingv1beta2.TortoiseStatus{ + ContainerResourcePhases: []autoscalingv1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseGatheringData, + Phase: autoscalingv1beta2.ContainerResourcePhaseGatheringData, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta1.TargetsStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -1528,62 +1528,62 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { { name: "remove metrics from hpa", args: args{ - tortoise: &autoscalingv1beta1.Tortoise{ + tortoise: &autoscalingv1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeVertical, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, - TargetRefs: autoscalingv1beta1.TargetRefs{ + TargetRefs: autoscalingv1beta2.TargetRefs{ HorizontalPodAutoscalerName: pointer.String("existing-hpa"), - ScaleTargetRef: autoscalingv1beta1.CrossVersionObjectReference{ + ScaleTargetRef: autoscalingv1beta2.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - ContainerResourcePhases: []autoscalingv1beta1.ContainerResourcePhases{ + Status: autoscalingv1beta2.TortoiseStatus{ + ContainerResourcePhases: []autoscalingv1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta1.TargetsStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -1663,62 +1663,62 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta1.Tortoise{ + wantTortoise: &autoscalingv1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeVertical, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, - TargetRefs: autoscalingv1beta1.TargetRefs{ + TargetRefs: autoscalingv1beta2.TargetRefs{ HorizontalPodAutoscalerName: pointer.String("existing-hpa"), - ScaleTargetRef: autoscalingv1beta1.CrossVersionObjectReference{ + ScaleTargetRef: autoscalingv1beta2.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - ContainerResourcePhases: []autoscalingv1beta1.ContainerResourcePhases{ + Status: autoscalingv1beta2.TortoiseStatus{ + ContainerResourcePhases: []autoscalingv1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta1.TargetsStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -1769,63 +1769,63 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { { name: "remove all metrics from hpa", args: args{ - tortoise: &autoscalingv1beta1.Tortoise{ + tortoise: &autoscalingv1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta1.TortoiseSpec{ - DeletionPolicy: autoscalingv1beta1.DeletionPolicyDeleteAll, - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + Spec: autoscalingv1beta2.TortoiseSpec{ + DeletionPolicy: autoscalingv1beta2.DeletionPolicyDeleteAll, + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeVertical, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeVertical, }, }, }, - TargetRefs: autoscalingv1beta1.TargetRefs{ + TargetRefs: autoscalingv1beta2.TargetRefs{ HorizontalPodAutoscalerName: pointer.String("existing-hpa"), - ScaleTargetRef: autoscalingv1beta1.CrossVersionObjectReference{ + ScaleTargetRef: autoscalingv1beta2.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - ContainerResourcePhases: []autoscalingv1beta1.ContainerResourcePhases{ + Status: autoscalingv1beta2.TortoiseStatus{ + ContainerResourcePhases: []autoscalingv1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta1.TargetsStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -1906,63 +1906,63 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta1.Tortoise{ + wantTortoise: &autoscalingv1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta1.TortoiseSpec{ - DeletionPolicy: autoscalingv1beta1.DeletionPolicyDeleteAll, - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + Spec: autoscalingv1beta2.TortoiseSpec{ + DeletionPolicy: autoscalingv1beta2.DeletionPolicyDeleteAll, + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeVertical, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeVertical, }, }, }, - TargetRefs: autoscalingv1beta1.TargetRefs{ + TargetRefs: autoscalingv1beta2.TargetRefs{ HorizontalPodAutoscalerName: pointer.String("existing-hpa"), - ScaleTargetRef: autoscalingv1beta1.CrossVersionObjectReference{ + ScaleTargetRef: autoscalingv1beta2.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - ContainerResourcePhases: []autoscalingv1beta1.ContainerResourcePhases{ + Status: autoscalingv1beta2.TortoiseStatus{ + ContainerResourcePhases: []autoscalingv1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta1.TargetsStatus{ + Targets: autoscalingv1beta2.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, diff --git a/pkg/recommender/recommender.go b/pkg/recommender/recommender.go index 676a1bf5..322d8d4f 100644 --- a/pkg/recommender/recommender.go +++ b/pkg/recommender/recommender.go @@ -16,7 +16,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - "github.com/mercari/tortoise/api/v1beta1" + "github.com/mercari/tortoise/api/v1beta2" ) type Service struct { @@ -55,7 +55,7 @@ func New( } } -func (s *Service) updateVPARecommendation(tortoise *v1beta1.Tortoise, deployment *v1.Deployment, hpa *v2.HorizontalPodAutoscaler) (*v1beta1.Tortoise, error) { +func (s *Service) updateVPARecommendation(tortoise *v1beta2.Tortoise, deployment *v1.Deployment, hpa *v2.HorizontalPodAutoscaler) (*v1beta2.Tortoise, error) { requestMap := map[string]map[corev1.ResourceName]resource.Quantity{} for _, c := range deployment.Spec.Template.Spec.Containers { requestMap[c.Name] = map[corev1.ResourceName]resource.Quantity{} @@ -72,9 +72,9 @@ func (s *Service) updateVPARecommendation(tortoise *v1beta1.Tortoise, deployment } } - newRecommendations := []v1beta1.RecommendedContainerResources{} + newRecommendations := []v1beta2.RecommendedContainerResources{} for _, r := range tortoise.Spec.ResourcePolicy { - recommendation := v1beta1.RecommendedContainerResources{ + recommendation := v1beta2.RecommendedContainerResources{ ContainerName: r.ContainerName, RecommendedResource: map[corev1.ResourceName]resource.Quantity{}, } @@ -115,7 +115,7 @@ func (s *Service) updateVPARecommendation(tortoise *v1beta1.Tortoise, deployment return tortoise, nil } -func (s *Service) calculateBestNewSize(p v1beta1.AutoscalingType, containerName string, recom resource.Quantity, k corev1.ResourceName, hpa *v2.HorizontalPodAutoscaler, deployment *v1.Deployment, req resource.Quantity, minAllocatedResources corev1.ResourceList) (int64, error) { +func (s *Service) calculateBestNewSize(p v1beta2.AutoscalingType, containerName string, recom resource.Quantity, k corev1.ResourceName, hpa *v2.HorizontalPodAutoscaler, deployment *v1.Deployment, req resource.Quantity, minAllocatedResources corev1.ResourceList) (int64, error) { // Make the container size bigger (just multiple by s.preferredReplicaNumUpperLimit) // when the current replica num is more than or equal to the preferredReplicaNumUpperLimit. if deployment.Status.Replicas >= s.preferredReplicaNumUpperLimit { @@ -126,12 +126,12 @@ func (s *Service) calculateBestNewSize(p v1beta1.AutoscalingType, containerName // change the container size based on the VPA recommendation when: // - user configure Vertical on this container's resource // - the current replica num is less than or equal to the minimumMinReplicas. - if deployment.Status.Replicas <= s.minimumMinReplicas || p == v1beta1.AutoscalingTypeVertical { + if deployment.Status.Replicas <= s.minimumMinReplicas || p == v1beta2.AutoscalingTypeVertical { newSize := recom.MilliValue() return s.justifyNewSizeByMaxMin(newSize, k, req, minAllocatedResources), nil } - if p == v1beta1.AutoscalingTypeHorizontal { + if p == v1beta2.AutoscalingTypeHorizontal { targetUtilizationValue, err := getHPATargetValue(hpa, containerName, k, len(deployment.Spec.Template.Spec.Containers) == 1) if err != nil { return 0, fmt.Errorf("get the target value from HPA: %w", err) @@ -168,7 +168,7 @@ func (s *Service) justifyNewSizeByMaxMin(newSize int64, k corev1.ResourceName, r return newSize } -func (s *Service) updateHPARecommendation(ctx context.Context, tortoise *v1beta1.Tortoise, hpa *v2.HorizontalPodAutoscaler, deployment *v1.Deployment, now time.Time) (*v1beta1.Tortoise, error) { +func (s *Service) updateHPARecommendation(ctx context.Context, tortoise *v1beta2.Tortoise, hpa *v2.HorizontalPodAutoscaler, deployment *v1.Deployment, now time.Time) (*v1beta2.Tortoise, error) { var err error tortoise, err = s.updateHPATargetUtilizationRecommendations(ctx, tortoise, hpa, deployment) if err != nil { @@ -182,7 +182,7 @@ func (s *Service) updateHPARecommendation(ctx context.Context, tortoise *v1beta1 return tortoise, nil } -func (s *Service) UpdateRecommendations(ctx context.Context, tortoise *v1beta1.Tortoise, hpa *v2.HorizontalPodAutoscaler, deployment *v1.Deployment, now time.Time) (*v1beta1.Tortoise, error) { +func (s *Service) UpdateRecommendations(ctx context.Context, tortoise *v1beta2.Tortoise, hpa *v2.HorizontalPodAutoscaler, deployment *v1.Deployment, now time.Time) (*v1beta2.Tortoise, error) { var err error tortoise, err = s.updateHPARecommendation(ctx, tortoise, hpa, deployment, now) if err != nil { @@ -196,7 +196,7 @@ func (s *Service) UpdateRecommendations(ctx context.Context, tortoise *v1beta1.T return tortoise, nil } -func (s *Service) updateHPAMinMaxReplicasRecommendations(tortoise *v1beta1.Tortoise, deployment *v1.Deployment, now time.Time) (*v1beta1.Tortoise, error) { +func (s *Service) updateHPAMinMaxReplicasRecommendations(tortoise *v1beta2.Tortoise, deployment *v1.Deployment, now time.Time) (*v1beta2.Tortoise, error) { currentReplicaNum := float64(deployment.Status.Replicas) min, err := s.updateMaxMinReplicasRecommendation(int32(math.Ceil(currentReplicaNum*s.minReplicasFactor)), tortoise.Status.Recommendations.Horizontal.MinReplicas, now, s.minimumMinReplicas) if err != nil { @@ -213,7 +213,7 @@ func (s *Service) updateHPAMinMaxReplicasRecommendations(tortoise *v1beta1.Torto } // updateMaxMinReplicasRecommendation replaces value if the value is higher than the current value. -func (s *Service) updateMaxMinReplicasRecommendation(value int32, recommendations []v1beta1.ReplicasRecommendation, now time.Time, minimum int32) ([]v1beta1.ReplicasRecommendation, error) { +func (s *Service) updateMaxMinReplicasRecommendation(value int32, recommendations []v1beta2.ReplicasRecommendation, now time.Time, minimum int32) ([]v1beta2.ReplicasRecommendation, error) { // find the corresponding recommendations. index := -1 for i, r := range recommendations { @@ -242,7 +242,7 @@ func (s *Service) updateMaxMinReplicasRecommendation(value int32, recommendation return recommendations, nil } -func (s *Service) updateHPATargetUtilizationRecommendations(ctx context.Context, tortoise *v1beta1.Tortoise, hpa *v2.HorizontalPodAutoscaler, deployment *v1.Deployment) (*v1beta1.Tortoise, error) { +func (s *Service) updateHPATargetUtilizationRecommendations(ctx context.Context, tortoise *v1beta2.Tortoise, hpa *v2.HorizontalPodAutoscaler, deployment *v1.Deployment) (*v1beta2.Tortoise, error) { logger := log.FromContext(ctx) requestMap := map[string]map[corev1.ResourceName]resource.Quantity{} for _, c := range deployment.Spec.Template.Spec.Containers { @@ -260,7 +260,7 @@ func (s *Service) updateHPATargetUtilizationRecommendations(ctx context.Context, } } - newHPATargetUtilizationRecommendationPerContainer := []v1beta1.HPATargetUtilizationRecommendationPerContainer{} + newHPATargetUtilizationRecommendationPerContainer := []v1beta2.HPATargetUtilizationRecommendationPerContainer{} for _, r := range tortoise.Spec.ResourcePolicy { targetMap := map[corev1.ResourceName]int32{} reqmap, ok := requestMap[r.ContainerName] @@ -269,7 +269,7 @@ func (s *Service) updateHPATargetUtilizationRecommendations(ctx context.Context, continue } for k, p := range r.AutoscalingPolicy { - if p != v1beta1.AutoscalingTypeHorizontal { + if p != v1beta2.AutoscalingTypeHorizontal { // nothing to do. continue } @@ -309,7 +309,7 @@ func (s *Service) updateHPATargetUtilizationRecommendations(ctx context.Context, } logger.Info("HPA target utilization recommendation is created", "current target utilization", targetValue, "recommended target utilization", targetMap[k], "upper usage", upperUsage, "container name", r.ContainerName, "resource name", k) } - newHPATargetUtilizationRecommendationPerContainer = append(newHPATargetUtilizationRecommendationPerContainer, v1beta1.HPATargetUtilizationRecommendationPerContainer{ + newHPATargetUtilizationRecommendationPerContainer = append(newHPATargetUtilizationRecommendationPerContainer, v1beta2.HPATargetUtilizationRecommendationPerContainer{ ContainerName: r.ContainerName, TargetUtilization: targetMap, }) diff --git a/pkg/recommender/recommender_test.go b/pkg/recommender/recommender_test.go index a8620b5f..3b79d62b 100644 --- a/pkg/recommender/recommender_test.go +++ b/pkg/recommender/recommender_test.go @@ -14,49 +14,49 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/pointer" - "github.com/mercari/tortoise/api/v1beta1" + "github.com/mercari/tortoise/api/v1beta2" ) func TestUpdateRecommendation(t *testing.T) { type args struct { - tortoise *v1beta1.Tortoise + tortoise *v1beta2.Tortoise hpa *v2.HorizontalPodAutoscaler deployment *v1.Deployment } tests := []struct { name string args args - want *v1beta1.Tortoise + want *v1beta2.Tortoise wantErr bool }{ { name: "HPA has the container resource metrics", args: args{ - tortoise: &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ + tortoise: &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, - corev1.ResourceCPU: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, + corev1.ResourceCPU: v1beta2.AutoscalingTypeVertical, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - ContainerRecommendationFromVPA: []v1beta1.ContainerRecommendationFromVPA{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "app", - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceMemory: { Quantity: resource.MustParse("4Gi"), }, @@ -67,7 +67,7 @@ func TestUpdateRecommendation(t *testing.T) { }, { ContainerName: "istio-proxy", - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceMemory: { Quantity: resource.MustParse("0.6Gi"), }, @@ -152,29 +152,29 @@ func TestUpdateRecommendation(t *testing.T) { }, }, }, - want: &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ + want: &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, - corev1.ResourceCPU: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, + corev1.ResourceCPU: v1beta2.AutoscalingTypeVertical, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - TargetUtilizations: []v1beta1.HPATargetUtilizationRecommendationPerContainer{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + TargetUtilizations: []v1beta2.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[corev1.ResourceName]int32{ @@ -190,11 +190,11 @@ func TestUpdateRecommendation(t *testing.T) { }, }, }, - Conditions: v1beta1.Conditions{ - ContainerRecommendationFromVPA: []v1beta1.ContainerRecommendationFromVPA{ + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "app", - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceMemory: { Quantity: resource.MustParse("4Gi"), }, @@ -205,7 +205,7 @@ func TestUpdateRecommendation(t *testing.T) { }, { ContainerName: "istio-proxy", - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceMemory: { Quantity: resource.MustParse("0.6Gi"), }, @@ -222,31 +222,31 @@ func TestUpdateRecommendation(t *testing.T) { { name: "Tortoise has some AutoscalingTypeOff policy", args: args{ - tortoise: &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ + tortoise: &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeOff, - corev1.ResourceCPU: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeOff, + corev1.ResourceCPU: v1beta2.AutoscalingTypeVertical, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - ContainerRecommendationFromVPA: []v1beta1.ContainerRecommendationFromVPA{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "app", - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceMemory: { Quantity: resource.MustParse("4Gi"), }, @@ -257,7 +257,7 @@ func TestUpdateRecommendation(t *testing.T) { }, { ContainerName: "istio-proxy", - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceMemory: { Quantity: resource.MustParse("0.6Gi"), }, @@ -332,29 +332,29 @@ func TestUpdateRecommendation(t *testing.T) { }, }, }, - want: &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ + want: &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeOff, - corev1.ResourceCPU: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeOff, + corev1.ResourceCPU: v1beta2.AutoscalingTypeVertical, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - TargetUtilizations: []v1beta1.HPATargetUtilizationRecommendationPerContainer{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + TargetUtilizations: []v1beta2.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[corev1.ResourceName]int32{}, @@ -368,11 +368,11 @@ func TestUpdateRecommendation(t *testing.T) { }, }, }, - Conditions: v1beta1.Conditions{ - ContainerRecommendationFromVPA: []v1beta1.ContainerRecommendationFromVPA{ + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "app", - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceMemory: { Quantity: resource.MustParse("4Gi"), }, @@ -383,7 +383,7 @@ func TestUpdateRecommendation(t *testing.T) { }, { ContainerName: "istio-proxy", - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceMemory: { Quantity: resource.MustParse("0.6Gi"), }, @@ -400,31 +400,31 @@ func TestUpdateRecommendation(t *testing.T) { { name: "HPA should have the container resource metrics, but doesn't", args: args{ - tortoise: &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ + tortoise: &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, - corev1.ResourceCPU: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, + corev1.ResourceCPU: v1beta2.AutoscalingTypeVertical, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - ContainerRecommendationFromVPA: []v1beta1.ContainerRecommendationFromVPA{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "app", - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceMemory: { Quantity: resource.MustParse("4Gi"), }, @@ -435,7 +435,7 @@ func TestUpdateRecommendation(t *testing.T) { }, { ContainerName: "istio-proxy", - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceMemory: { Quantity: resource.MustParse("0.6Gi"), }, @@ -543,24 +543,24 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { t.Fatal(err) } type args struct { - tortoise *v1beta1.Tortoise + tortoise *v1beta2.Tortoise deployment *v1.Deployment now time.Time } tests := []struct { name string args args - want *v1beta1.Tortoise + want *v1beta2.Tortoise wantErr bool }{ { name: "Basic case", args: args{ - tortoise: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + tortoise: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -570,7 +570,7 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { WeekDay: pointer.String(time.Sunday.String()), }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -591,11 +591,11 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { }, now: time.Date(2023, 3, 19, 0, 0, 0, 0, jst), }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -605,7 +605,7 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { WeekDay: pointer.String(time.Sunday.String()), }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -624,12 +624,12 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { { name: "No recommendation slot", args: args{ - tortoise: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{}, - MaxReplicas: []v1beta1.ReplicasRecommendation{}, + tortoise: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{}, + MaxReplicas: []v1beta2.ReplicasRecommendation{}, }, }, }, @@ -641,12 +641,12 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { }, now: time.Date(2023, 3, 19, 0, 0, 0, 0, jst), }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{}, - MaxReplicas: []v1beta1.ReplicasRecommendation{}, + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{}, + MaxReplicas: []v1beta2.ReplicasRecommendation{}, }, }, }, @@ -656,11 +656,11 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { { name: "Lower recommendation value", args: args{ - tortoise: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + tortoise: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -670,7 +670,7 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { WeekDay: pointer.String(time.Sunday.String()), }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -691,11 +691,11 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { }, now: time.Date(2023, 3, 19, 0, 0, 0, 0, jst), }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -706,7 +706,7 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { WeekDay: pointer.String(time.Sunday.String()), }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -726,11 +726,11 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { { name: "Same recommendation value", args: args{ - tortoise: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + tortoise: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -740,7 +740,7 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { WeekDay: pointer.String(time.Sunday.String()), }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -761,11 +761,11 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { }, now: time.Date(2023, 3, 19, 0, 0, 0, 0, jst), }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -775,7 +775,7 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { WeekDay: pointer.String(time.Sunday.String()), }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -794,11 +794,11 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { { name: "minimum MinReplicas and minimum MaxReplicas", args: args{ - tortoise: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + tortoise: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -808,7 +808,7 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { WeekDay: pointer.String(time.Sunday.String()), }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -829,11 +829,11 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { }, now: time.Date(2023, 3, 19, 0, 0, 0, 0, jst), }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -843,7 +843,7 @@ func Test_updateHPAMinMaxReplicasRecommendations(t *testing.T) { WeekDay: pointer.String(time.Sunday.String()), }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 1, @@ -882,7 +882,7 @@ func TestService_UpdateVPARecommendation(t *testing.T) { suggestedResourceSizeAtMax corev1.ResourceList } type args struct { - tortoise *v1beta1.Tortoise + tortoise *v1beta2.Tortoise deployment *v1.Deployment hpa *v2.HorizontalPodAutoscaler } @@ -890,7 +890,7 @@ func TestService_UpdateVPARecommendation(t *testing.T) { name string fields fields args args - want *v1beta1.Tortoise + want *v1beta2.Tortoise wantErr bool }{ { @@ -900,7 +900,7 @@ func TestService_UpdateVPARecommendation(t *testing.T) { suggestedResourceSizeAtMax: createResourceList("1000m", "1Gi"), }, args: args{ - tortoise: createTortoiseWithCondition(map[corev1.ResourceName]v1beta1.ResourceQuantity{ + tortoise: createTortoiseWithCondition(map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: { Quantity: resource.MustParse("500m"), }, @@ -920,7 +920,7 @@ func TestService_UpdateVPARecommendation(t *testing.T) { suggestedResourceSizeAtMax: createResourceList("1000m", "1Gi"), }, args: args{ - tortoise: createTortoiseWithCondition(map[corev1.ResourceName]v1beta1.ResourceQuantity{ + tortoise: createTortoiseWithCondition(map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: { Quantity: resource.MustParse("1500m"), }, @@ -941,7 +941,7 @@ func TestService_UpdateVPARecommendation(t *testing.T) { minimumMinReplicas: 3, }, args: args{ - tortoise: createTortoiseWithCondition(map[corev1.ResourceName]v1beta1.ResourceQuantity{ + tortoise: createTortoiseWithCondition(map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: { Quantity: resource.MustParse("120m"), }, @@ -961,7 +961,7 @@ func TestService_UpdateVPARecommendation(t *testing.T) { suggestedResourceSizeAtMax: createResourceList("1000m", "1Gi"), }, args: args{ - tortoise: createVerticalTortoiseWithCondition(map[corev1.ResourceName]v1beta1.ResourceQuantity{ + tortoise: createVerticalTortoiseWithCondition(map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: { Quantity: resource.MustParse("120m"), }, @@ -982,7 +982,7 @@ func TestService_UpdateVPARecommendation(t *testing.T) { }, args: args{ tortoise: createTortoiseWithMultipleContainersWithCondition( - map[corev1.ResourceName]v1beta1.ResourceQuantity{ + map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: { Quantity: resource.MustParse("80m"), }, @@ -990,7 +990,7 @@ func TestService_UpdateVPARecommendation(t *testing.T) { Quantity: resource.MustParse("9Gi"), }, }, - map[corev1.ResourceName]v1beta1.ResourceQuantity{ + map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: { Quantity: resource.MustParse("800m"), }, @@ -1062,7 +1062,7 @@ func TestService_UpdateVPARecommendation(t *testing.T) { t.Errorf("updateVPARecommendation() error = %v, wantErr %v", err, tt.wantErr) return } - if d := cmp.Diff(got, tt.want, cmpopts.IgnoreTypes(metav1.Time{}, v1beta1.Conditions{})); d != "" { + if d := cmp.Diff(got, tt.want, cmpopts.IgnoreTypes(metav1.Time{}, v1beta2.Conditions{})); d != "" { t.Errorf("updateVPARecommendation() diff = %s", d) } }) @@ -1076,15 +1076,15 @@ func createResourceList(cpu, memory string) corev1.ResourceList { corev1.ResourceMemory: resource.MustParse(memory), } } -func createVerticalTortoise() *v1beta1.Tortoise { - return &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ +func createVerticalTortoise() *v1beta2.Tortoise { + return &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "test-container", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceCPU: v1beta1.AutoscalingTypeVertical, - corev1.ResourceMemory: v1beta1.AutoscalingTypeVertical, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceCPU: v1beta2.AutoscalingTypeVertical, + corev1.ResourceMemory: v1beta2.AutoscalingTypeVertical, }, MinAllocatedResources: createResourceList("100m", "100Mi"), }, @@ -1092,9 +1092,9 @@ func createVerticalTortoise() *v1beta1.Tortoise { }, } } -func createVerticalTortoiseWithCondition(vpaRecommendation map[corev1.ResourceName]v1beta1.ResourceQuantity) *v1beta1.Tortoise { +func createVerticalTortoiseWithCondition(vpaRecommendation map[corev1.ResourceName]v1beta2.ResourceQuantity) *v1beta2.Tortoise { tortoise := createVerticalTortoise() - tortoise.Status.Conditions.ContainerRecommendationFromVPA = []v1beta1.ContainerRecommendationFromVPA{ + tortoise.Status.Conditions.ContainerRecommendationFromVPA = []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "test-container", Recommendation: vpaRecommendation, @@ -1102,15 +1102,15 @@ func createVerticalTortoiseWithCondition(vpaRecommendation map[corev1.ResourceNa } return tortoise } -func createTortoise() *v1beta1.Tortoise { - return &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ +func createTortoise() *v1beta2.Tortoise { + return &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "test-container", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, - corev1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, + corev1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, }, MinAllocatedResources: createResourceList("100m", "100Mi"), }, @@ -1139,23 +1139,23 @@ func createDeployment(replicas int32, cpu, memory string) *v1.Deployment { }, } } -func createTortoiseWithMultipleContainers() *v1beta1.Tortoise { - return &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ +func createTortoiseWithMultipleContainers() *v1beta2.Tortoise { + return &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "test-container", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, - corev1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, + corev1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, }, MinAllocatedResources: createResourceList("100m", "100Mi"), }, { ContainerName: "test-container2", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, - corev1.ResourceMemory: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, + corev1.ResourceMemory: v1beta2.AutoscalingTypeHorizontal, }, MinAllocatedResources: createResourceList("100m", "100Mi"), }, @@ -1191,9 +1191,9 @@ func createMultipleContainersDeployment(replicas int32, cpu1, cpu2, memory1, mem } } -func createTortoiseWithMultipleContainersWithCondition(vpaRecommendation1, vpaRecommendation2 map[corev1.ResourceName]v1beta1.ResourceQuantity) *v1beta1.Tortoise { +func createTortoiseWithMultipleContainersWithCondition(vpaRecommendation1, vpaRecommendation2 map[corev1.ResourceName]v1beta2.ResourceQuantity) *v1beta2.Tortoise { tortoise := createTortoiseWithMultipleContainers() - tortoise.Status.Conditions.ContainerRecommendationFromVPA = []v1beta1.ContainerRecommendationFromVPA{ + tortoise.Status.Conditions.ContainerRecommendationFromVPA = []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "test-container", Recommendation: vpaRecommendation1, @@ -1206,9 +1206,9 @@ func createTortoiseWithMultipleContainersWithCondition(vpaRecommendation1, vpaRe return tortoise } -func createTortoiseWithCondition(vpaRecommendation map[corev1.ResourceName]v1beta1.ResourceQuantity) *v1beta1.Tortoise { +func createTortoiseWithCondition(vpaRecommendation map[corev1.ResourceName]v1beta2.ResourceQuantity) *v1beta2.Tortoise { tortoise := createTortoise() - tortoise.Status.Conditions.ContainerRecommendationFromVPA = []v1beta1.ContainerRecommendationFromVPA{ + tortoise.Status.Conditions.ContainerRecommendationFromVPA = []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "test-container", Recommendation: vpaRecommendation, @@ -1217,11 +1217,11 @@ func createTortoiseWithCondition(vpaRecommendation map[corev1.ResourceName]v1bet return tortoise } -func createTortoiseWithVPARecommendation(cpu, memory string) *v1beta1.Tortoise { +func createTortoiseWithVPARecommendation(cpu, memory string) *v1beta2.Tortoise { tortoise := createTortoise() - tortoise.Status.Recommendations = v1beta1.Recommendations{ - Vertical: v1beta1.VerticalRecommendations{ - ContainerResourceRecommendation: []v1beta1.RecommendedContainerResources{ + tortoise.Status.Recommendations = v1beta2.Recommendations{ + Vertical: v1beta2.VerticalRecommendations{ + ContainerResourceRecommendation: []v1beta2.RecommendedContainerResources{ { ContainerName: "test-container", RecommendedResource: createResourceList(cpu, memory), @@ -1232,11 +1232,11 @@ func createTortoiseWithVPARecommendation(cpu, memory string) *v1beta1.Tortoise { return tortoise } -func createVerticalTortoiseWithVPARecommendation(cpu, memory string) *v1beta1.Tortoise { +func createVerticalTortoiseWithVPARecommendation(cpu, memory string) *v1beta2.Tortoise { tortoise := createVerticalTortoise() - tortoise.Status.Recommendations = v1beta1.Recommendations{ - Vertical: v1beta1.VerticalRecommendations{ - ContainerResourceRecommendation: []v1beta1.RecommendedContainerResources{ + tortoise.Status.Recommendations = v1beta2.Recommendations{ + Vertical: v1beta2.VerticalRecommendations{ + ContainerResourceRecommendation: []v1beta2.RecommendedContainerResources{ { ContainerName: "test-container", RecommendedResource: createResourceList(cpu, memory), @@ -1246,11 +1246,11 @@ func createVerticalTortoiseWithVPARecommendation(cpu, memory string) *v1beta1.To } return tortoise } -func createTortoiseWithMultipleContainersWithVPARecommendation(cpu1, cpu2, memory1, memory2 string) *v1beta1.Tortoise { +func createTortoiseWithMultipleContainersWithVPARecommendation(cpu1, cpu2, memory1, memory2 string) *v1beta2.Tortoise { tortoise := createTortoiseWithMultipleContainers() - tortoise.Status.Recommendations = v1beta1.Recommendations{ - Vertical: v1beta1.VerticalRecommendations{ - ContainerResourceRecommendation: []v1beta1.RecommendedContainerResources{ + tortoise.Status.Recommendations = v1beta2.Recommendations{ + Vertical: v1beta2.VerticalRecommendations{ + ContainerResourceRecommendation: []v1beta2.RecommendedContainerResources{ { ContainerName: "test-container", RecommendedResource: createResourceList(cpu1, memory1), diff --git a/pkg/tortoise/tortoise.go b/pkg/tortoise/tortoise.go index 1aa45bed..c7f0e8c0 100644 --- a/pkg/tortoise/tortoise.go +++ b/pkg/tortoise/tortoise.go @@ -20,7 +20,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/log" - "github.com/mercari/tortoise/api/v1beta1" + "github.com/mercari/tortoise/api/v1beta2" ) const tortoiseFinalizer = "tortoise.autoscaling.mercari.com/finalizer" @@ -59,8 +59,8 @@ func New(c client.Client, recorder record.EventRecorder, rangeOfMinMaxReplicasRe }, nil } -func (s *Service) ShouldReconcileTortoiseNow(tortoise *v1beta1.Tortoise, now time.Time) (bool, time.Duration) { - if tortoise.Spec.UpdateMode == v1beta1.UpdateModeEmergency && tortoise.Status.TortoisePhase != v1beta1.TortoisePhaseEmergency { +func (s *Service) ShouldReconcileTortoiseNow(tortoise *v1beta2.Tortoise, now time.Time) (bool, time.Duration) { + if tortoise.Spec.UpdateMode == v1beta2.UpdateModeEmergency && tortoise.Status.TortoisePhase != v1beta2.TortoisePhaseEmergency { // Tortoise which is emergency mode, but hasn't been handled by the controller yet. It should be updated ASAP. return true, 0 } @@ -75,7 +75,7 @@ func (s *Service) ShouldReconcileTortoiseNow(tortoise *v1beta1.Tortoise, now tim return false, lastTime.Add(s.tortoiseUpdateInterval).Sub(now) } -func (s *Service) UpdateTortoisePhase(tortoise *v1beta1.Tortoise, dm *appv1.Deployment, now time.Time) *v1beta1.Tortoise { +func (s *Service) UpdateTortoisePhase(tortoise *v1beta2.Tortoise, dm *appv1.Deployment, now time.Time) *v1beta2.Tortoise { switch tortoise.Status.TortoisePhase { case "": tortoise = s.initializeTortoise(tortoise, dm, now) @@ -85,41 +85,41 @@ func (s *Service) UpdateTortoisePhase(tortoise *v1beta1.Tortoise, dm *appv1.Depl } s.recorder.Event(tortoise, corev1.EventTypeNormal, "Initialized", fmt.Sprintf("Tortoise is initialized and starts to gather data to make recommendations. It will take %s to finish gathering data and then tortoise starts to work actually", r)) - case v1beta1.TortoisePhaseInitializing: + case v1beta2.TortoisePhaseInitializing: // change it to GatheringData anyway. Later the controller may change it back to initialize if VPA isn't ready. - tortoise.Status.TortoisePhase = v1beta1.TortoisePhaseGatheringData - case v1beta1.TortoisePhaseGatheringData: + tortoise.Status.TortoisePhase = v1beta2.TortoisePhaseGatheringData + case v1beta2.TortoisePhaseGatheringData: tortoise = s.changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(tortoise, now) - if tortoise.Status.TortoisePhase == v1beta1.TortoisePhaseWorking { + if tortoise.Status.TortoisePhase == v1beta2.TortoisePhaseWorking { s.recorder.Event(tortoise, corev1.EventTypeNormal, "Working", "Tortoise finishes gathering data and it starts to work on autoscaling") } - if tortoise.Status.TortoisePhase == v1beta1.TortoisePhasePartlyWorking { + if tortoise.Status.TortoisePhase == v1beta2.TortoisePhasePartlyWorking { s.recorder.Event(tortoise, corev1.EventTypeNormal, "PartlyWorking", "Tortoise finishes gathering data in some metrics and it starts to work on autoscaling for those metrics. But some metrics are still gathering data") } - case v1beta1.TortoisePhasePartlyWorking: + case v1beta2.TortoisePhasePartlyWorking: tortoise = s.changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(tortoise, now) - if tortoise.Status.TortoisePhase == v1beta1.TortoisePhaseWorking { + if tortoise.Status.TortoisePhase == v1beta2.TortoisePhaseWorking { s.recorder.Event(tortoise, corev1.EventTypeNormal, "Working", "Tortoise finishes gathering data and it starts to work on autoscaling") } - case v1beta1.TortoisePhaseEmergency: - if tortoise.Spec.UpdateMode != v1beta1.UpdateModeEmergency { + case v1beta2.TortoisePhaseEmergency: + if tortoise.Spec.UpdateMode != v1beta2.UpdateModeEmergency { // Emergency mode is turned off. s.recorder.Event(tortoise, corev1.EventTypeNormal, "Working", "Emergency mode is turned off. Tortoise starts to work on autoscaling normally") - tortoise.Status.TortoisePhase = v1beta1.TortoisePhaseEmergency + tortoise.Status.TortoisePhase = v1beta2.TortoisePhaseEmergency } } - if tortoise.Spec.UpdateMode == v1beta1.UpdateModeEmergency { - if tortoise.Status.TortoisePhase != v1beta1.TortoisePhaseEmergency { + if tortoise.Spec.UpdateMode == v1beta2.UpdateModeEmergency { + if tortoise.Status.TortoisePhase != v1beta2.TortoisePhaseEmergency { s.recorder.Event(tortoise, corev1.EventTypeNormal, "Emergency", "Tortoise is in Emergency mode") - tortoise.Status.TortoisePhase = v1beta1.TortoisePhaseEmergency + tortoise.Status.TortoisePhase = v1beta2.TortoisePhaseEmergency } } return tortoise } -func (s *Service) changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(tortoise *v1beta1.Tortoise, now time.Time) *v1beta1.Tortoise { +func (s *Service) changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(tortoise *v1beta2.Tortoise, now time.Time) *v1beta2.Tortoise { for _, r := range tortoise.Status.Recommendations.Horizontal.MinReplicas { if r.Value == 0 { return tortoise @@ -138,11 +138,11 @@ func (s *Service) changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(tort someAreWorking := false for i, c := range tortoise.Status.ContainerResourcePhases { for rn, p := range c.ResourcePhases { - if p.Phase == v1beta1.ContainerResourcePhaseOff { + if p.Phase == v1beta2.ContainerResourcePhaseOff { // ignore continue } - if p.Phase == v1beta1.ContainerResourcePhaseWorking { + if p.Phase == v1beta2.ContainerResourcePhaseWorking { someAreWorking = true continue } @@ -151,8 +151,8 @@ func (s *Service) changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(tort someAreGathering = true } else { // It's finish gathering data. - tortoise.Status.ContainerResourcePhases[i].ResourcePhases[rn] = v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseWorking, + tortoise.Status.ContainerResourcePhases[i].ResourcePhases[rn] = v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseWorking, LastTransitionTime: metav1.NewTime(now), } someAreWorking = true @@ -162,29 +162,29 @@ func (s *Service) changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(tort if someAreGathering && someAreWorking { // Some are working, but some are still gathering data. - tortoise.Status.TortoisePhase = v1beta1.TortoisePhasePartlyWorking + tortoise.Status.TortoisePhase = v1beta2.TortoisePhasePartlyWorking } else if !someAreGathering && someAreWorking { // All are working. - tortoise.Status.TortoisePhase = v1beta1.TortoisePhaseWorking + tortoise.Status.TortoisePhase = v1beta2.TortoisePhaseWorking } return tortoise } -func (s *Service) initializeMinMaxReplicas(tortoise *v1beta1.Tortoise) *v1beta1.Tortoise { - recommendations := []v1beta1.ReplicasRecommendation{} +func (s *Service) initializeMinMaxReplicas(tortoise *v1beta2.Tortoise) *v1beta2.Tortoise { + recommendations := []v1beta2.ReplicasRecommendation{} from := 0 to := s.rangeOfMinMaxReplicasRecommendationHour weekDay := time.Sunday for { if s.minMaxReplicasRoutine == "daily" { - recommendations = append(recommendations, v1beta1.ReplicasRecommendation{ + recommendations = append(recommendations, v1beta2.ReplicasRecommendation{ From: from, To: to, TimeZone: s.timeZone.String(), }) } else if s.minMaxReplicasRoutine == "weekly" { - recommendations = append(recommendations, v1beta1.ReplicasRecommendation{ + recommendations = append(recommendations, v1beta2.ReplicasRecommendation{ From: from, To: to, TimeZone: s.timeZone.String(), @@ -211,42 +211,42 @@ func (s *Service) initializeMinMaxReplicas(tortoise *v1beta1.Tortoise) *v1beta1. return tortoise } -func (s *Service) initializeTortoise(tortoise *v1beta1.Tortoise, dm *appv1.Deployment, now time.Time) *v1beta1.Tortoise { +func (s *Service) initializeTortoise(tortoise *v1beta2.Tortoise, dm *appv1.Deployment, now time.Time) *v1beta2.Tortoise { tortoise = s.initializeMinMaxReplicas(tortoise) - tortoise.Status.TortoisePhase = v1beta1.TortoisePhaseInitializing + tortoise.Status.TortoisePhase = v1beta2.TortoisePhaseInitializing - tortoise.Status.Conditions.ContainerRecommendationFromVPA = make([]v1beta1.ContainerRecommendationFromVPA, len(dm.Spec.Template.Spec.Containers)) + tortoise.Status.Conditions.ContainerRecommendationFromVPA = make([]v1beta2.ContainerRecommendationFromVPA, len(dm.Spec.Template.Spec.Containers)) for i, c := range dm.Spec.Template.Spec.Containers { - tortoise.Status.Conditions.ContainerRecommendationFromVPA[i] = v1beta1.ContainerRecommendationFromVPA{ + tortoise.Status.Conditions.ContainerRecommendationFromVPA[i] = v1beta2.ContainerRecommendationFromVPA{ ContainerName: c.Name, - Recommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + Recommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: {}, corev1.ResourceMemory: {}, }, - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: {}, corev1.ResourceMemory: {}, }, } } - tortoise.Status.Targets.Deployment = dm.Name + tortoise.Status.Targets.ScaleTargetRef = tortoise.Spec.TargetRefs.ScaleTargetRef for _, p := range tortoise.Spec.ResourcePolicy { - phase := v1beta1.ContainerResourcePhases{ + phase := v1beta2.ContainerResourcePhases{ ContainerName: p.ContainerName, - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{}, + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{}, } for rn, policy := range p.AutoscalingPolicy { - if policy == v1beta1.AutoscalingTypeOff { - phase.ResourcePhases[rn] = v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseOff, + if policy == v1beta2.AutoscalingTypeOff { + phase.ResourcePhases[rn] = v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseOff, LastTransitionTime: metav1.NewTime(now), } continue } - phase.ResourcePhases[rn] = v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseGatheringData, + phase.ResourcePhases[rn] = v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.NewTime(now), } } @@ -256,7 +256,7 @@ func (s *Service) initializeTortoise(tortoise *v1beta1.Tortoise, dm *appv1.Deplo return tortoise.DeepCopy() } -func (s *Service) UpdateUpperRecommendation(tortoise *v1beta1.Tortoise, vpa *v1.VerticalPodAutoscaler) *v1beta1.Tortoise { +func (s *Service) UpdateUpperRecommendation(tortoise *v1beta2.Tortoise, vpa *v1.VerticalPodAutoscaler) *v1beta2.Tortoise { upperMap := make(map[string]map[corev1.ResourceName]resource.Quantity, len(vpa.Status.Recommendation.ContainerRecommendations)) for _, c := range vpa.Status.Recommendation.ContainerRecommendations { upperMap[c.ContainerName] = make(map[corev1.ResourceName]resource.Quantity, len(c.UpperBound)) @@ -279,7 +279,7 @@ func (s *Service) UpdateUpperRecommendation(tortoise *v1beta1.Tortoise, vpa *v1. currentTargetFromVPA := targetMap[r.ContainerName][rn] currentMaxRecommendation := max.Quantity - rq := v1beta1.ResourceQuantity{ + rq := v1beta2.ResourceQuantity{ Quantity: currentTargetFromVPA, UpdatedAt: metav1.Now(), } @@ -306,21 +306,21 @@ func (s *Service) UpdateUpperRecommendation(tortoise *v1beta1.Tortoise, vpa *v1. return tortoise } -func (s *Service) GetTortoise(ctx context.Context, namespacedName types.NamespacedName) (*v1beta1.Tortoise, error) { - t := &v1beta1.Tortoise{} +func (s *Service) GetTortoise(ctx context.Context, namespacedName types.NamespacedName) (*v1beta2.Tortoise, error) { + t := &v1beta2.Tortoise{} if err := s.c.Get(ctx, namespacedName, t); err != nil { return nil, fmt.Errorf("failed to get tortoise: %w", err) } return t, nil } -func (s *Service) AddFinalizer(ctx context.Context, tortoise *v1beta1.Tortoise) error { +func (s *Service) AddFinalizer(ctx context.Context, tortoise *v1beta2.Tortoise) error { if controllerutil.ContainsFinalizer(tortoise, tortoiseFinalizer) { return nil } updateFn := func() error { - retTortoise := &v1beta1.Tortoise{} + retTortoise := &v1beta2.Tortoise{} err := s.c.Get(ctx, client.ObjectKeyFromObject(tortoise), retTortoise) if err != nil { return err @@ -337,13 +337,13 @@ func (s *Service) AddFinalizer(ctx context.Context, tortoise *v1beta1.Tortoise) return nil } -func (s *Service) RemoveFinalizer(ctx context.Context, tortoise *v1beta1.Tortoise) error { +func (s *Service) RemoveFinalizer(ctx context.Context, tortoise *v1beta2.Tortoise) error { if !controllerutil.ContainsFinalizer(tortoise, tortoiseFinalizer) { return nil } updateFn := func() error { - retTortoise := &v1beta1.Tortoise{} + retTortoise := &v1beta2.Tortoise{} err := s.c.Get(ctx, client.ObjectKeyFromObject(tortoise), retTortoise) if err != nil { return err @@ -358,12 +358,12 @@ func (s *Service) RemoveFinalizer(ctx context.Context, tortoise *v1beta1.Tortois return nil } -func (s *Service) UpdateTortoiseStatus(ctx context.Context, originalTortoise *v1beta1.Tortoise, now time.Time, timeRecord bool) (*v1beta1.Tortoise, error) { +func (s *Service) UpdateTortoiseStatus(ctx context.Context, originalTortoise *v1beta2.Tortoise, now time.Time, timeRecord bool) (*v1beta2.Tortoise, error) { logger := log.FromContext(ctx) logger.V(4).Info("update tortoise status", "tortoise", klog.KObj(originalTortoise)) - retTortoise := &v1beta1.Tortoise{} + retTortoise := &v1beta2.Tortoise{} updateFn := func() error { - retTortoise = &v1beta1.Tortoise{} + retTortoise = &v1beta2.Tortoise{} err := s.c.Get(ctx, client.ObjectKeyFromObject(originalTortoise), retTortoise) if err != nil { return fmt.Errorf("get tortoise to update status: %w", err) @@ -390,18 +390,18 @@ func (s *Service) UpdateTortoiseStatus(ctx context.Context, originalTortoise *v1 return originalTortoise, nil } -func (s *Service) updateLastTimeUpdateTortoise(tortoise *v1beta1.Tortoise, now time.Time) { +func (s *Service) updateLastTimeUpdateTortoise(tortoise *v1beta2.Tortoise, now time.Time) { s.mu.Lock() defer s.mu.Unlock() s.lastTimeUpdateTortoise[client.ObjectKeyFromObject(tortoise)] = now } -func (s *Service) RecordReconciliationFailure(t *v1beta1.Tortoise, err error, now time.Time) *v1beta1.Tortoise { +func (s *Service) RecordReconciliationFailure(t *v1beta2.Tortoise, err error, now time.Time) *v1beta2.Tortoise { if err != nil { s.recorder.Event(t, "Warning", "ReconcileError", err.Error()) for i := range t.Status.Conditions.TortoiseConditions { - if t.Status.Conditions.TortoiseConditions[i].Type == v1beta1.TortoiseConditionTypeFailedToReconcile { + if t.Status.Conditions.TortoiseConditions[i].Type == v1beta2.TortoiseConditionTypeFailedToReconcile { // TODO: have a clear reason and utilize it to have a better reconciliation next. // For example, in some cases, the reconciliation may keep failing until people fix some problems manually. t.Status.Conditions.TortoiseConditions[i].Reason = "ReconcileError" @@ -413,8 +413,8 @@ func (s *Service) RecordReconciliationFailure(t *v1beta1.Tortoise, err error, no } } // add as a new condition if not found. - t.Status.Conditions.TortoiseConditions = append(t.Status.Conditions.TortoiseConditions, v1beta1.TortoiseCondition{ - Type: v1beta1.TortoiseConditionTypeFailedToReconcile, + t.Status.Conditions.TortoiseConditions = append(t.Status.Conditions.TortoiseConditions, v1beta2.TortoiseCondition{ + Type: v1beta2.TortoiseConditionTypeFailedToReconcile, Status: corev1.ConditionTrue, Reason: "ReconcileError", Message: err.Error(), @@ -425,7 +425,7 @@ func (s *Service) RecordReconciliationFailure(t *v1beta1.Tortoise, err error, no } for i := range t.Status.Conditions.TortoiseConditions { - if t.Status.Conditions.TortoiseConditions[i].Type == v1beta1.TortoiseConditionTypeFailedToReconcile { + if t.Status.Conditions.TortoiseConditions[i].Type == v1beta2.TortoiseConditionTypeFailedToReconcile { t.Status.Conditions.TortoiseConditions[i].Reason = "" t.Status.Conditions.TortoiseConditions[i].Message = "" t.Status.Conditions.TortoiseConditions[i].Status = corev1.ConditionFalse diff --git a/pkg/tortoise/tortoise_test.go b/pkg/tortoise/tortoise_test.go index 1cdb16ac..294a2608 100644 --- a/pkg/tortoise/tortoise_test.go +++ b/pkg/tortoise/tortoise_test.go @@ -20,25 +20,25 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/mercari/tortoise/api/v1beta1" + "github.com/mercari/tortoise/api/v1beta2" ) func TestService_updateUpperRecommendation(t *testing.T) { tests := []struct { name string - tortoise *v1beta1.Tortoise + tortoise *v1beta2.Tortoise vpa *v1.VerticalPodAutoscaler - want *v1beta1.Tortoise + want *v1beta2.Tortoise }{ { name: "success: the current recommendation on tortoise is less than the one on the current VPA", - tortoise: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - ContainerRecommendationFromVPA: []v1beta1.ContainerRecommendationFromVPA{ + tortoise: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "app", - Recommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + Recommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ "cpu": { Quantity: resource.MustParse("1"), }, @@ -46,7 +46,7 @@ func TestService_updateUpperRecommendation(t *testing.T) { Quantity: resource.MustParse("1"), }, }, - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ "cpu": { Quantity: resource.MustParse("5"), }, @@ -82,13 +82,13 @@ func TestService_updateUpperRecommendation(t *testing.T) { }, }, }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - ContainerRecommendationFromVPA: []v1beta1.ContainerRecommendationFromVPA{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "app", - Recommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + Recommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ "cpu": { Quantity: resource.MustParse("5"), }, @@ -96,7 +96,7 @@ func TestService_updateUpperRecommendation(t *testing.T) { Quantity: resource.MustParse("8"), }, }, - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ "cpu": { Quantity: resource.MustParse("5"), }, @@ -112,13 +112,13 @@ func TestService_updateUpperRecommendation(t *testing.T) { }, { name: "success: the current recommendation on tortoise is more than the upper bound on the current VPA", - tortoise: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - ContainerRecommendationFromVPA: []v1beta1.ContainerRecommendationFromVPA{ + tortoise: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "app", - Recommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + Recommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ "cpu": { Quantity: resource.MustParse("1"), }, @@ -126,7 +126,7 @@ func TestService_updateUpperRecommendation(t *testing.T) { Quantity: resource.MustParse("1"), }, }, - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ "cpu": { Quantity: resource.MustParse("5"), }, @@ -162,13 +162,13 @@ func TestService_updateUpperRecommendation(t *testing.T) { }, }, }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - ContainerRecommendationFromVPA: []v1beta1.ContainerRecommendationFromVPA{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "app", - Recommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + Recommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ "cpu": { Quantity: resource.MustParse("2"), }, @@ -176,7 +176,7 @@ func TestService_updateUpperRecommendation(t *testing.T) { Quantity: resource.MustParse("2"), }, }, - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ "cpu": { Quantity: resource.MustParse("5"), }, @@ -216,9 +216,9 @@ func TestService_InitializeTortoise(t *testing.T) { tests := []struct { name string fields fields - tortoise *v1beta1.Tortoise + tortoise *v1beta2.Tortoise deployment *appv1.Deployment - want *v1beta1.Tortoise + want *v1beta2.Tortoise }{ { name: "weekly minMaxReplicasRoutine", @@ -227,26 +227,26 @@ func TestService_InitializeTortoise(t *testing.T) { minMaxReplicasRoutine: "weekly", timeZone: jst, }, - tortoise: &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ + tortoise: &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeOff, - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeOff, + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: v1beta1.TortoiseStatus{}, + Status: v1beta2.TortoiseStatus{}, }, deployment: &appv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ @@ -267,81 +267,80 @@ func TestService_InitializeTortoise(t *testing.T) { }, }, }, - want: &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ + want: &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeOff, - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeOff, + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: v1beta1.TortoiseStatus{ - TortoisePhase: v1beta1.TortoisePhaseInitializing, - Targets: v1beta1.TargetsStatus{Deployment: "deployment"}, - Conditions: v1beta1.Conditions{ - ContainerRecommendationFromVPA: []v1beta1.ContainerRecommendationFromVPA{ + Status: v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhaseInitializing, + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "app", - Recommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + Recommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: {}, corev1.ResourceMemory: {}, }, - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: {}, corev1.ResourceMemory: {}, }, }, { ContainerName: "istio", - Recommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + Recommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: {}, corev1.ResourceMemory: {}, }, - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: {}, corev1.ResourceMemory: {}, }, }, }, }, - ContainerResourcePhases: []v1beta1.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{ - corev1.ResourceMemory: v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseGatheringData, + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{ + corev1.ResourceMemory: v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseGatheringData, }, - corev1.ResourceCPU: v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseGatheringData, + corev1.ResourceCPU: v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseGatheringData, }, }, }, { ContainerName: "istio", - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{ - corev1.ResourceMemory: v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseOff, + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{ + corev1.ResourceMemory: v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseOff, }, - corev1.ResourceCPU: v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseGatheringData, + corev1.ResourceCPU: v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseGatheringData, }, }, }, }, - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -469,7 +468,7 @@ func TestService_InitializeTortoise(t *testing.T) { TimeZone: timeZone, }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -609,19 +608,19 @@ func TestService_InitializeTortoise(t *testing.T) { rangeOfMinMaxReplicasRecommendationHour: 8, timeZone: jst, }, - tortoise: &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ + tortoise: &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: v1beta1.TortoiseStatus{}, + Status: v1beta2.TortoiseStatus{}, }, deployment: &appv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ @@ -639,52 +638,51 @@ func TestService_InitializeTortoise(t *testing.T) { }, }, }, - want: &v1beta1.Tortoise{ - Spec: v1beta1.TortoiseSpec{ - ResourcePolicy: []v1beta1.ContainerResourcePolicy{ + want: &v1beta2.Tortoise{ + Spec: v1beta2.TortoiseSpec{ + ResourcePolicy: []v1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[corev1.ResourceName]v1beta1.AutoscalingType{ - corev1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - corev1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[corev1.ResourceName]v1beta2.AutoscalingType{ + corev1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + corev1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: v1beta1.TortoiseStatus{ - TortoisePhase: v1beta1.TortoisePhaseInitializing, - Targets: v1beta1.TargetsStatus{Deployment: "deployment"}, - Conditions: v1beta1.Conditions{ - ContainerRecommendationFromVPA: []v1beta1.ContainerRecommendationFromVPA{ + Status: v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhaseInitializing, + Conditions: v1beta2.Conditions{ + ContainerRecommendationFromVPA: []v1beta2.ContainerRecommendationFromVPA{ { ContainerName: "app", - Recommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + Recommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: {}, corev1.ResourceMemory: {}, }, - MaxRecommendation: map[corev1.ResourceName]v1beta1.ResourceQuantity{ + MaxRecommendation: map[corev1.ResourceName]v1beta2.ResourceQuantity{ corev1.ResourceCPU: {}, corev1.ResourceMemory: {}, }, }, }, }, - ContainerResourcePhases: []v1beta1.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{ - corev1.ResourceCPU: v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseGatheringData, + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{ + corev1.ResourceCPU: v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseGatheringData, }, - corev1.ResourceMemory: v1beta1.ResourcePhase{ - Phase: v1beta1.ContainerResourcePhaseGatheringData, + corev1.ResourceMemory: v1beta2.ResourcePhase{ + Phase: v1beta2.ContainerResourcePhaseGatheringData, }, }, }, }, - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -701,7 +699,7 @@ func TestService_InitializeTortoise(t *testing.T) { TimeZone: timeZone, }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -744,7 +742,7 @@ func TestService_ShouldReconcileTortoiseNow(t *testing.T) { tests := []struct { name string lastTimeUpdateTortoise map[client.ObjectKey]time.Time - tortoise *v1beta1.Tortoise + tortoise *v1beta2.Tortoise want bool wantDuration time.Duration }{ @@ -753,13 +751,13 @@ func TestService_ShouldReconcileTortoiseNow(t *testing.T) { lastTimeUpdateTortoise: map[client.ObjectKey]time.Time{ client.ObjectKey{Name: "t2", Namespace: "default"}: now.Add(-1 * time.Second), }, - tortoise: &v1beta1.Tortoise{ + tortoise: &v1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "t", Namespace: "default", }, - Spec: v1beta1.TortoiseSpec{ - UpdateMode: v1beta1.UpdateModeAuto, + Spec: v1beta2.TortoiseSpec{ + UpdateMode: v1beta2.UpdateModeAuto, }, }, want: true, @@ -769,13 +767,13 @@ func TestService_ShouldReconcileTortoiseNow(t *testing.T) { lastTimeUpdateTortoise: map[client.ObjectKey]time.Time{ client.ObjectKey{Name: "t", Namespace: "default"}: now.Add(-1 * time.Second), }, - tortoise: &v1beta1.Tortoise{ + tortoise: &v1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "t", Namespace: "default", }, - Spec: v1beta1.TortoiseSpec{ - UpdateMode: v1beta1.UpdateModeAuto, + Spec: v1beta2.TortoiseSpec{ + UpdateMode: v1beta2.UpdateModeAuto, }, }, want: false, @@ -786,13 +784,13 @@ func TestService_ShouldReconcileTortoiseNow(t *testing.T) { lastTimeUpdateTortoise: map[client.ObjectKey]time.Time{ client.ObjectKey{Name: "t", Namespace: "default"}: now.Add(-1 * time.Second), }, - tortoise: &v1beta1.Tortoise{ + tortoise: &v1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "t", Namespace: "default", }, - Spec: v1beta1.TortoiseSpec{ - UpdateMode: v1beta1.UpdateModeEmergency, + Spec: v1beta2.TortoiseSpec{ + UpdateMode: v1beta2.UpdateModeEmergency, }, }, want: true, @@ -802,16 +800,16 @@ func TestService_ShouldReconcileTortoiseNow(t *testing.T) { lastTimeUpdateTortoise: map[client.ObjectKey]time.Time{ client.ObjectKey{Name: "t", Namespace: "default"}: now.Add(-1 * time.Second), }, - tortoise: &v1beta1.Tortoise{ + tortoise: &v1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "t", Namespace: "default", }, - Spec: v1beta1.TortoiseSpec{ - UpdateMode: v1beta1.UpdateModeEmergency, + Spec: v1beta2.TortoiseSpec{ + UpdateMode: v1beta2.UpdateModeEmergency, }, - Status: v1beta1.TortoiseStatus{ - TortoisePhase: v1beta1.TortoisePhaseEmergency, + Status: v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhaseEmergency, }, }, want: false, @@ -837,25 +835,25 @@ func TestService_ShouldReconcileTortoiseNow(t *testing.T) { func TestService_UpdateTortoiseStatus(t *testing.T) { now := time.Now() type args struct { - t *v1beta1.Tortoise + t *v1beta2.Tortoise now time.Time } tests := []struct { name string - originalTortoise *v1beta1.Tortoise + originalTortoise *v1beta2.Tortoise args args wantLastTimeUpdateTortoise map[client.ObjectKey]time.Time }{ { name: "success", - originalTortoise: &v1beta1.Tortoise{ + originalTortoise: &v1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{Name: "t", Namespace: "test"}, }, args: args{ - t: &v1beta1.Tortoise{ + t: &v1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{Name: "t", Namespace: "test"}, - Status: v1beta1.TortoiseStatus{ - TortoisePhase: v1beta1.TortoisePhaseInitializing, + Status: v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhaseInitializing, }, }, now: now, @@ -868,7 +866,7 @@ func TestService_UpdateTortoiseStatus(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { scheme := runtime.NewScheme() - err := v1beta1.AddToScheme(scheme) + err := v1beta2.AddToScheme(scheme) if err != nil { t.Fatalf("failed to add to scheme: %v", err) } @@ -893,23 +891,23 @@ func TestService_UpdateTortoiseStatus(t *testing.T) { func TestService_RecordReconciliationFailure(t *testing.T) { now := time.Now() type args struct { - t *v1beta1.Tortoise + t *v1beta2.Tortoise err error } tests := []struct { name string args args - want *v1beta1.Tortoise + want *v1beta2.Tortoise }{ { name: "success reconciliation", args: args{ - t: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - TortoiseConditions: []v1beta1.TortoiseCondition{ + t: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + TortoiseConditions: []v1beta2.TortoiseCondition{ { - Type: v1beta1.TortoiseConditionTypeFailedToReconcile, + Type: v1beta2.TortoiseConditionTypeFailedToReconcile, Status: corev1.ConditionTrue, Message: "failed to reconcile", Reason: "ReconcileError", @@ -922,12 +920,12 @@ func TestService_RecordReconciliationFailure(t *testing.T) { }, err: nil, }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - TortoiseConditions: []v1beta1.TortoiseCondition{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + TortoiseConditions: []v1beta2.TortoiseCondition{ { - Type: v1beta1.TortoiseConditionTypeFailedToReconcile, + Type: v1beta2.TortoiseConditionTypeFailedToReconcile, Status: corev1.ConditionFalse, Message: "", Reason: "", @@ -942,10 +940,10 @@ func TestService_RecordReconciliationFailure(t *testing.T) { { name: "failed reconciliation and tortoise doens't have TortoiseConditionTypeFailedToReconcile", args: args{ - t: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - TortoiseConditions: []v1beta1.TortoiseCondition{ + t: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + TortoiseConditions: []v1beta2.TortoiseCondition{ // TortoiseConditionTypeFailedToReconcile isn't recorded yet. }, }, @@ -953,12 +951,12 @@ func TestService_RecordReconciliationFailure(t *testing.T) { }, err: errors.New("failed to reconcile"), }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - TortoiseConditions: []v1beta1.TortoiseCondition{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + TortoiseConditions: []v1beta2.TortoiseCondition{ { - Type: v1beta1.TortoiseConditionTypeFailedToReconcile, + Type: v1beta2.TortoiseConditionTypeFailedToReconcile, Status: corev1.ConditionTrue, Message: "failed to reconcile", Reason: "ReconcileError", @@ -973,12 +971,12 @@ func TestService_RecordReconciliationFailure(t *testing.T) { { name: "failed reconciliation and tortoise has TortoiseConditionTypeFailedToReconcile", args: args{ - t: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - TortoiseConditions: []v1beta1.TortoiseCondition{ + t: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + TortoiseConditions: []v1beta2.TortoiseCondition{ { - Type: v1beta1.TortoiseConditionTypeFailedToReconcile, + Type: v1beta2.TortoiseConditionTypeFailedToReconcile, Status: corev1.ConditionFalse, Message: "", Reason: "", @@ -991,12 +989,12 @@ func TestService_RecordReconciliationFailure(t *testing.T) { }, err: errors.New("failed to reconcile"), }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - Conditions: v1beta1.Conditions{ - TortoiseConditions: []v1beta1.TortoiseCondition{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + Conditions: v1beta2.Conditions{ + TortoiseConditions: []v1beta2.TortoiseCondition{ { - Type: v1beta1.TortoiseConditionTypeFailedToReconcile, + Type: v1beta2.TortoiseConditionTypeFailedToReconcile, Status: corev1.ConditionTrue, Message: "failed to reconcile", Reason: "ReconcileError", @@ -1026,17 +1024,17 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te now := time.Now() tests := []struct { name string - tortoise *v1beta1.Tortoise - want *v1beta1.Tortoise + tortoise *v1beta2.Tortoise + want *v1beta2.Tortoise }{ { name: "minReplicas/maxReplicas recommendation is not yet gathered", - tortoise: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - TortoisePhase: v1beta1.TortoisePhaseGatheringData, - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + tortoise: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhaseGatheringData, + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1056,7 +1054,7 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te // empty }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1080,12 +1078,12 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te }, }, }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - TortoisePhase: v1beta1.TortoisePhaseGatheringData, - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhaseGatheringData, + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1105,7 +1103,7 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te // empty }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1132,12 +1130,12 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te }, { name: "some container resource need to gather more data", - tortoise: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - TortoisePhase: v1beta1.TortoisePhaseGatheringData, - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + tortoise: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhaseGatheringData, + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1157,7 +1155,7 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te Value: 3, }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1179,16 +1177,16 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te }, }, }, - ContainerResourcePhases: []v1beta1.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{ + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{ corev1.ResourceCPU: { - Phase: v1beta1.ContainerResourcePhaseGatheringData, + Phase: v1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.NewTime(now.Add(-24 * 1 * time.Hour)), }, corev1.ResourceMemory: { - Phase: v1beta1.ContainerResourcePhaseGatheringData, + Phase: v1beta2.ContainerResourcePhaseGatheringData, // finish gathering LastTransitionTime: metav1.NewTime(now.Add(-24 * 8 * time.Hour)), }, @@ -1196,13 +1194,13 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te }, { ContainerName: "istio-proxy", - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{ + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{ corev1.ResourceCPU: { - Phase: v1beta1.ContainerResourcePhaseGatheringData, + Phase: v1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.NewTime(now.Add(-1 * time.Minute)), }, corev1.ResourceMemory: { - Phase: v1beta1.ContainerResourcePhaseGatheringData, + Phase: v1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.NewTime(now.Add(-1 * time.Minute)), }, }, @@ -1210,12 +1208,12 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te }, }, }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - TortoisePhase: v1beta1.TortoisePhasePartlyWorking, - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhasePartlyWorking, + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1235,7 +1233,7 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te Value: 3, }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1257,29 +1255,29 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te }, }, }, - ContainerResourcePhases: []v1beta1.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{ + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{ corev1.ResourceCPU: { - Phase: v1beta1.ContainerResourcePhaseGatheringData, + Phase: v1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.NewTime(now.Add(-24 * 1 * time.Hour)), }, corev1.ResourceMemory: { - Phase: v1beta1.ContainerResourcePhaseWorking, + Phase: v1beta2.ContainerResourcePhaseWorking, LastTransitionTime: metav1.NewTime(now), }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{ + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{ corev1.ResourceCPU: { - Phase: v1beta1.ContainerResourcePhaseGatheringData, + Phase: v1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.NewTime(now.Add(-1 * time.Minute)), }, corev1.ResourceMemory: { - Phase: v1beta1.ContainerResourcePhaseGatheringData, + Phase: v1beta2.ContainerResourcePhaseGatheringData, LastTransitionTime: metav1.NewTime(now.Add(-1 * time.Minute)), }, }, @@ -1290,12 +1288,12 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te }, { name: "all container resource gathered the data", - tortoise: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - TortoisePhase: v1beta1.TortoisePhaseGatheringData, - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + tortoise: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhaseGatheringData, + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1315,7 +1313,7 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te Value: 3, }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1337,15 +1335,15 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te }, }, }, - ContainerResourcePhases: []v1beta1.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{ + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{ corev1.ResourceCPU: { - Phase: v1beta1.ContainerResourcePhaseWorking, + Phase: v1beta2.ContainerResourcePhaseWorking, }, corev1.ResourceMemory: { - Phase: v1beta1.ContainerResourcePhaseGatheringData, + Phase: v1beta2.ContainerResourcePhaseGatheringData, // finish gathering LastTransitionTime: metav1.NewTime(now.Add(-24 * 8 * time.Hour)), }, @@ -1353,26 +1351,26 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te }, { ContainerName: "istio-proxy", - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{ + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{ corev1.ResourceCPU: { - Phase: v1beta1.ContainerResourcePhaseWorking, + Phase: v1beta2.ContainerResourcePhaseWorking, LastTransitionTime: metav1.NewTime(now.Add(-24 * 2 * time.Hour)), }, corev1.ResourceMemory: { // off is ignored - Phase: v1beta1.ContainerResourcePhaseOff, + Phase: v1beta2.ContainerResourcePhaseOff, }, }, }, }, }, }, - want: &v1beta1.Tortoise{ - Status: v1beta1.TortoiseStatus{ - TortoisePhase: v1beta1.TortoisePhaseWorking, - Recommendations: v1beta1.Recommendations{ - Horizontal: v1beta1.HorizontalRecommendations{ - MinReplicas: []v1beta1.ReplicasRecommendation{ + want: &v1beta2.Tortoise{ + Status: v1beta2.TortoiseStatus{ + TortoisePhase: v1beta2.TortoisePhaseWorking, + Recommendations: v1beta2.Recommendations{ + Horizontal: v1beta2.HorizontalRecommendations{ + MinReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1392,7 +1390,7 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te Value: 3, }, }, - MaxReplicas: []v1beta1.ReplicasRecommendation{ + MaxReplicas: []v1beta2.ReplicasRecommendation{ { From: 0, To: 8, @@ -1414,28 +1412,28 @@ func TestService_changeTortoisePhaseWorkingIfTortoiseFinishedGatheringData(t *te }, }, }, - ContainerResourcePhases: []v1beta1.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{ + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{ corev1.ResourceCPU: { - Phase: v1beta1.ContainerResourcePhaseWorking, + Phase: v1beta2.ContainerResourcePhaseWorking, }, corev1.ResourceMemory: { - Phase: v1beta1.ContainerResourcePhaseWorking, + Phase: v1beta2.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[corev1.ResourceName]v1beta1.ResourcePhase{ + ResourcePhases: map[corev1.ResourceName]v1beta2.ResourcePhase{ corev1.ResourceCPU: { - Phase: v1beta1.ContainerResourcePhaseWorking, + Phase: v1beta2.ContainerResourcePhaseWorking, LastTransitionTime: metav1.NewTime(now.Add(-24 * 2 * time.Hour)), }, corev1.ResourceMemory: { // off is ignored - Phase: v1beta1.ContainerResourcePhaseOff, + Phase: v1beta2.ContainerResourcePhaseOff, }, }, }, diff --git a/pkg/utils/tortoise_builder.go b/pkg/utils/tortoise_builder.go index c39c0497..8ec5d6cb 100644 --- a/pkg/utils/tortoise_builder.go +++ b/pkg/utils/tortoise_builder.go @@ -1,16 +1,16 @@ package utils import ( - "github.com/mercari/tortoise/api/v1beta1" + "github.com/mercari/tortoise/api/v1beta2" ) type TortoiseBuilder struct { - tortoise *v1beta1.Tortoise + tortoise *v1beta2.Tortoise } func NewTortoiseBuilder() *TortoiseBuilder { return &TortoiseBuilder{ - tortoise: &v1beta1.Tortoise{}, + tortoise: &v1beta2.Tortoise{}, } } @@ -24,45 +24,45 @@ func (b *TortoiseBuilder) SetNamespace(namespace string) *TortoiseBuilder { return b } -func (b *TortoiseBuilder) SetTargetRefs(targetRefs v1beta1.TargetRefs) *TortoiseBuilder { +func (b *TortoiseBuilder) SetTargetRefs(targetRefs v1beta2.TargetRefs) *TortoiseBuilder { b.tortoise.Spec.TargetRefs = targetRefs return b } -func (b *TortoiseBuilder) SetDeletionPolicy(policy v1beta1.DeletionPolicy) *TortoiseBuilder { +func (b *TortoiseBuilder) SetDeletionPolicy(policy v1beta2.DeletionPolicy) *TortoiseBuilder { b.tortoise.Spec.DeletionPolicy = policy return b } -func (b *TortoiseBuilder) SetUpdateMode(updateMode v1beta1.UpdateMode) *TortoiseBuilder { +func (b *TortoiseBuilder) SetUpdateMode(updateMode v1beta2.UpdateMode) *TortoiseBuilder { b.tortoise.Spec.UpdateMode = updateMode return b } -func (b *TortoiseBuilder) AddResourcePolicy(resourcePolicy v1beta1.ContainerResourcePolicy) *TortoiseBuilder { +func (b *TortoiseBuilder) AddResourcePolicy(resourcePolicy v1beta2.ContainerResourcePolicy) *TortoiseBuilder { b.tortoise.Spec.ResourcePolicy = append(b.tortoise.Spec.ResourcePolicy, resourcePolicy) return b } -func (b *TortoiseBuilder) SetTortoisePhase(phase v1beta1.TortoisePhase) *TortoiseBuilder { +func (b *TortoiseBuilder) SetTortoisePhase(phase v1beta2.TortoisePhase) *TortoiseBuilder { b.tortoise.Status.TortoisePhase = phase return b } -func (b *TortoiseBuilder) AddCondition(condition v1beta1.ContainerRecommendationFromVPA) *TortoiseBuilder { +func (b *TortoiseBuilder) AddCondition(condition v1beta2.ContainerRecommendationFromVPA) *TortoiseBuilder { b.tortoise.Status.Conditions.ContainerRecommendationFromVPA = append(b.tortoise.Status.Conditions.ContainerRecommendationFromVPA, condition) return b } -func (b *TortoiseBuilder) SetRecommendations(recommendations v1beta1.Recommendations) *TortoiseBuilder { +func (b *TortoiseBuilder) SetRecommendations(recommendations v1beta2.Recommendations) *TortoiseBuilder { b.tortoise.Status.Recommendations = recommendations return b } -func (b *TortoiseBuilder) SetTargetsStatus(targetsStatus v1beta1.TargetsStatus) *TortoiseBuilder { +func (b *TortoiseBuilder) SetTargetsStatus(targetsStatus v1beta2.TargetsStatus) *TortoiseBuilder { b.tortoise.Status.Targets = targetsStatus return b } -func (b *TortoiseBuilder) Build() *v1beta1.Tortoise { +func (b *TortoiseBuilder) Build() *v1beta2.Tortoise { return b.tortoise } diff --git a/pkg/vpa/service.go b/pkg/vpa/service.go index e5a96571..8ddebf1e 100644 --- a/pkg/vpa/service.go +++ b/pkg/vpa/service.go @@ -16,7 +16,7 @@ import ( "k8s.io/client-go/tools/record" "k8s.io/client-go/util/retry" - autoscalingv1beta1 "github.com/mercari/tortoise/api/v1beta1" + autoscalingv1beta2 "github.com/mercari/tortoise/api/v1beta2" "github.com/mercari/tortoise/pkg/annotation" "github.com/mercari/tortoise/pkg/metrics" ) @@ -46,8 +46,8 @@ func TortoiseUpdaterVPAName(tortoiseName string) string { return TortoiseUpdaterVPANamePrefix + tortoiseName } -func (c *Service) DeleteTortoiseMonitorVPA(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise) error { - if tortoise.Spec.DeletionPolicy == autoscalingv1beta1.DeletionPolicyNoDelete { +func (c *Service) DeleteTortoiseMonitorVPA(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise) error { + if tortoise.Spec.DeletionPolicy == autoscalingv1beta2.DeletionPolicyNoDelete { return nil } @@ -72,8 +72,8 @@ func (c *Service) DeleteTortoiseMonitorVPA(ctx context.Context, tortoise *autosc return nil } -func (c *Service) DeleteTortoiseUpdaterVPA(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise) error { - if tortoise.Spec.DeletionPolicy == autoscalingv1beta1.DeletionPolicyNoDelete { +func (c *Service) DeleteTortoiseUpdaterVPA(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise) error { + if tortoise.Spec.DeletionPolicy == autoscalingv1beta2.DeletionPolicyNoDelete { return nil } @@ -98,7 +98,7 @@ func (c *Service) DeleteTortoiseUpdaterVPA(ctx context.Context, tortoise *autosc return nil } -func (c *Service) CreateTortoiseUpdaterVPA(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise) (*v1.VerticalPodAutoscaler, *autoscalingv1beta1.Tortoise, error) { +func (c *Service) CreateTortoiseUpdaterVPA(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise) (*v1.VerticalPodAutoscaler, *autoscalingv1beta2.Tortoise, error) { auto := v1.UpdateModeAuto vpa := &v1.VerticalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{ @@ -135,9 +135,9 @@ func (c *Service) CreateTortoiseUpdaterVPA(ctx context.Context, tortoise *autosc } vpa.Spec.ResourcePolicy.ContainerPolicies = crp - tortoise.Status.Targets.VerticalPodAutoscalers = append(tortoise.Status.Targets.VerticalPodAutoscalers, autoscalingv1beta1.TargetStatusVerticalPodAutoscaler{ + tortoise.Status.Targets.VerticalPodAutoscalers = append(tortoise.Status.Targets.VerticalPodAutoscalers, autoscalingv1beta2.TargetStatusVerticalPodAutoscaler{ Name: vpa.Name, - Role: autoscalingv1beta1.VerticalPodAutoscalerRoleUpdater, + Role: autoscalingv1beta2.VerticalPodAutoscalerRoleUpdater, }) vpa, err := c.c.AutoscalingV1().VerticalPodAutoscalers(vpa.Namespace).Create(ctx, vpa, metav1.CreateOptions{}) if err != nil { @@ -149,7 +149,7 @@ func (c *Service) CreateTortoiseUpdaterVPA(ctx context.Context, tortoise *autosc return vpa, tortoise, nil } -func (c *Service) CreateTortoiseMonitorVPA(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise) (*v1.VerticalPodAutoscaler, *autoscalingv1beta1.Tortoise, error) { +func (c *Service) CreateTortoiseMonitorVPA(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise) (*v1.VerticalPodAutoscaler, *autoscalingv1beta2.Tortoise, error) { off := v1.UpdateModeOff vpa := &v1.VerticalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{ @@ -181,9 +181,9 @@ func (c *Service) CreateTortoiseMonitorVPA(ctx context.Context, tortoise *autosc } vpa.Spec.ResourcePolicy.ContainerPolicies = crp - tortoise.Status.Targets.VerticalPodAutoscalers = append(tortoise.Status.Targets.VerticalPodAutoscalers, autoscalingv1beta1.TargetStatusVerticalPodAutoscaler{ + tortoise.Status.Targets.VerticalPodAutoscalers = append(tortoise.Status.Targets.VerticalPodAutoscalers, autoscalingv1beta2.TargetStatusVerticalPodAutoscaler{ Name: vpa.Name, - Role: autoscalingv1beta1.VerticalPodAutoscalerRoleMonitor, + Role: autoscalingv1beta2.VerticalPodAutoscalerRoleMonitor, }) vpa, err := c.c.AutoscalingV1().VerticalPodAutoscalers(vpa.Namespace).Create(ctx, vpa, metav1.CreateOptions{}) @@ -196,7 +196,7 @@ func (c *Service) CreateTortoiseMonitorVPA(ctx context.Context, tortoise *autosc return vpa, tortoise, nil } -func (c *Service) UpdateVPAFromTortoiseRecommendation(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise) (*v1.VerticalPodAutoscaler, error) { +func (c *Service) UpdateVPAFromTortoiseRecommendation(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise) (*v1.VerticalPodAutoscaler, error) { retVPA := &v1.VerticalPodAutoscaler{} // we only want to record metric once in every reconcile loop. @@ -233,7 +233,7 @@ func (c *Service) UpdateVPAFromTortoiseRecommendation(ctx context.Context, torto } vpa.Status.Recommendation.ContainerRecommendations = newRecommendations retVPA = vpa - if tortoise.Spec.UpdateMode == autoscalingv1beta1.UpdateModeOff { + if tortoise.Spec.UpdateMode == autoscalingv1beta2.UpdateModeOff { // don't update status if update mode is off. (= dryrun) return nil } @@ -245,14 +245,14 @@ func (c *Service) UpdateVPAFromTortoiseRecommendation(ctx context.Context, torto return retVPA, fmt.Errorf("update VPA status: %w", err) } - if tortoise.Spec.UpdateMode != autoscalingv1beta1.UpdateModeOff { + if tortoise.Spec.UpdateMode != autoscalingv1beta2.UpdateModeOff { c.recorder.Event(tortoise, corev1.EventTypeNormal, "VPAUpdated", fmt.Sprintf("VPA %s/%s is updated by the recommendation. The Pods should also be updated with new resources soon by VPA if needed", retVPA.Namespace, retVPA.Name)) } return retVPA, nil } -func (c *Service) GetTortoiseUpdaterVPA(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise) (*v1.VerticalPodAutoscaler, error) { +func (c *Service) GetTortoiseUpdaterVPA(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise) (*v1.VerticalPodAutoscaler, error) { vpa, err := c.c.AutoscalingV1().VerticalPodAutoscalers(tortoise.Namespace).Get(ctx, TortoiseUpdaterVPAName(tortoise.Name), metav1.GetOptions{}) if err != nil { return nil, fmt.Errorf("failed to get updater vpa on tortoise: %w", err) @@ -260,7 +260,7 @@ func (c *Service) GetTortoiseUpdaterVPA(ctx context.Context, tortoise *autoscali return vpa, nil } -func (c *Service) GetTortoiseMonitorVPA(ctx context.Context, tortoise *autoscalingv1beta1.Tortoise) (*v1.VerticalPodAutoscaler, bool, error) { +func (c *Service) GetTortoiseMonitorVPA(ctx context.Context, tortoise *autoscalingv1beta2.Tortoise) (*v1.VerticalPodAutoscaler, bool, error) { vpa, err := c.c.AutoscalingV1().VerticalPodAutoscalers(tortoise.Namespace).Get(ctx, TortoiseMonitorVPAName(tortoise.Name), metav1.GetOptions{}) if err != nil { return nil, false, fmt.Errorf("failed to get updater vpa on tortoise: %w", err) @@ -275,11 +275,11 @@ func (c *Service) GetTortoiseMonitorVPA(ctx context.Context, tortoise *autoscali return vpa, false, nil } -func MakeAllVerticalContainerResourcePhaseWorking(tortoise *autoscalingv1beta1.Tortoise, now time.Time) *autoscalingv1beta1.Tortoise { +func MakeAllVerticalContainerResourcePhaseWorking(tortoise *autoscalingv1beta2.Tortoise, now time.Time) *autoscalingv1beta2.Tortoise { verticalResourceAndContainer := sets.New[resourceNameAndContainerName]() for _, p := range tortoise.Spec.ResourcePolicy { for rn, ap := range p.AutoscalingPolicy { - if ap == autoscalingv1beta1.AutoscalingTypeVertical { + if ap == autoscalingv1beta2.AutoscalingTypeVertical { verticalResourceAndContainer.Insert(resourceNameAndContainerName{rn, p.ContainerName}) } } @@ -289,8 +289,8 @@ func MakeAllVerticalContainerResourcePhaseWorking(tortoise *autoscalingv1beta1.T for _, d := range verticalResourceAndContainer.UnsortedList() { for i, p := range tortoise.Status.ContainerResourcePhases { if p.ContainerName == d.containerName { - tortoise.Status.ContainerResourcePhases[i].ResourcePhases[d.rn] = autoscalingv1beta1.ResourcePhase{ - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + tortoise.Status.ContainerResourcePhases[i].ResourcePhases[d.rn] = autoscalingv1beta2.ResourcePhase{ + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, LastTransitionTime: metav1.NewTime(now), } found = true @@ -298,11 +298,11 @@ func MakeAllVerticalContainerResourcePhaseWorking(tortoise *autoscalingv1beta1.T } } if !found { - tortoise.Status.ContainerResourcePhases = append(tortoise.Status.ContainerResourcePhases, autoscalingv1beta1.ContainerResourcePhases{ + tortoise.Status.ContainerResourcePhases = append(tortoise.Status.ContainerResourcePhases, autoscalingv1beta2.ContainerResourcePhases{ ContainerName: d.containerName, - ResourcePhases: map[corev1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[corev1.ResourceName]autoscalingv1beta2.ResourcePhase{ d.rn: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, LastTransitionTime: metav1.NewTime(now), }, }, diff --git a/pkg/vpa/service_test.go b/pkg/vpa/service_test.go index dc0c9273..4d152d06 100644 --- a/pkg/vpa/service_test.go +++ b/pkg/vpa/service_test.go @@ -9,66 +9,66 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/mercari/tortoise/api/v1beta1" - autoscalingv1beta1 "github.com/mercari/tortoise/api/v1beta1" + "github.com/mercari/tortoise/api/v1beta2" + autoscalingv1beta2 "github.com/mercari/tortoise/api/v1beta2" ) func TestMakeAllVerticalContainerResourcePhaseRunning(t *testing.T) { type args struct { - tortoise *autoscalingv1beta1.Tortoise + tortoise *autoscalingv1beta2.Tortoise } tests := []struct { name string args args - want *autoscalingv1beta1.Tortoise + want *autoscalingv1beta2.Tortoise }{ { name: "modified correctly", args: args{ - tortoise: &autoscalingv1beta1.Tortoise{ + tortoise: &autoscalingv1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - ContainerResourcePhases: []autoscalingv1beta1.ContainerResourcePhases{ + Status: autoscalingv1beta2.TortoiseStatus{ + ContainerResourcePhases: []autoscalingv1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseGatheringData, + Phase: autoscalingv1beta2.ContainerResourcePhaseGatheringData, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseGatheringData, + Phase: autoscalingv1beta2.ContainerResourcePhaseGatheringData, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseGatheringData, + Phase: autoscalingv1beta2.ContainerResourcePhaseGatheringData, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseGatheringData, + Phase: autoscalingv1beta2.ContainerResourcePhaseGatheringData, }, }, }, @@ -76,50 +76,50 @@ func TestMakeAllVerticalContainerResourcePhaseRunning(t *testing.T) { }, }, }, - want: &autoscalingv1beta1.Tortoise{ + want: &autoscalingv1beta2.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta1.TortoiseSpec{ - ResourcePolicy: []autoscalingv1beta1.ContainerResourcePolicy{ + Spec: autoscalingv1beta2.TortoiseSpec{ + ResourcePolicy: []autoscalingv1beta2.ContainerResourcePolicy{ { ContainerName: "app", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, { ContainerName: "istio-proxy", - AutoscalingPolicy: map[v1.ResourceName]v1beta1.AutoscalingType{ - v1.ResourceMemory: v1beta1.AutoscalingTypeVertical, - v1.ResourceCPU: v1beta1.AutoscalingTypeHorizontal, + AutoscalingPolicy: map[v1.ResourceName]v1beta2.AutoscalingType{ + v1.ResourceMemory: v1beta2.AutoscalingTypeVertical, + v1.ResourceCPU: v1beta2.AutoscalingTypeHorizontal, }, }, }, }, - Status: autoscalingv1beta1.TortoiseStatus{ - ContainerResourcePhases: []autoscalingv1beta1.ContainerResourcePhases{ + Status: autoscalingv1beta2.TortoiseStatus{ + ContainerResourcePhases: []autoscalingv1beta2.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseGatheringData, + Phase: autoscalingv1beta2.ContainerResourcePhaseGatheringData, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta1.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]autoscalingv1beta2.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta1.ContainerResourcePhaseGatheringData, + Phase: autoscalingv1beta2.ContainerResourcePhaseGatheringData, }, v1.ResourceMemory: { - Phase: autoscalingv1beta1.ContainerResourcePhaseWorking, + Phase: autoscalingv1beta2.ContainerResourcePhaseWorking, }, }, },