From d1e495931cac73f3c9027202515afcb3389ee966 Mon Sep 17 00:00:00 2001 From: Kensei Nakada Date: Wed, 27 Mar 2024 20:19:06 +0900 Subject: [PATCH] implement MaxAllocatedResources and MaxReplicas in Tortoise --- api/v1beta3/tortoise_types.go | 13 +- api/v1beta3/zz_generated.deepcopy.go | 12 + .../autoscaling.mercari.com_tortoises.yaml | 34 +- .../after/deployment.yaml | 24 + .../after/hpa.yaml | 44 + .../after/tortoise.yaml | 110 ++ .../after/vpa-Monitor.yaml | 29 + .../before/deployment.yaml | 22 + .../before/hpa.yaml | 49 + .../before/tortoise.yaml | 71 + .../before/vpa-Monitor.yaml | 32 + controllers/tortoise_controller_test.go | 3 + ...ion_tortoises.autoscaling.mercari.com.yaml | 15 +- ...ion_tortoises.autoscaling.mercari.com.yaml | 15 +- pkg/hpa/service.go | 4 + pkg/hpa/service_test.go | 1322 ++++++++++------- pkg/recommender/recommender.go | 36 +- pkg/recommender/recommender_test.go | 156 +- 18 files changed, 1438 insertions(+), 553 deletions(-) create mode 100644 controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/deployment.yaml create mode 100644 controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/hpa.yaml create mode 100644 controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/tortoise.yaml create mode 100644 controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/vpa-Monitor.yaml create mode 100644 controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/deployment.yaml create mode 100644 controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/hpa.yaml create mode 100644 controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/tortoise.yaml create mode 100644 controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/vpa-Monitor.yaml diff --git a/api/v1beta3/tortoise_types.go b/api/v1beta3/tortoise_types.go index f1daa410..ce164e12 100644 --- a/api/v1beta3/tortoise_types.go +++ b/api/v1beta3/tortoise_types.go @@ -86,6 +86,10 @@ type TortoiseSpec struct { // The AutoscalingPolicy field is mutable; you can modify it at any time, whether from an empty state to populated or vice versa. // +optional AutoscalingPolicy []ContainerAutoscalingPolicy `json:"autoscalingPolicy,omitempty" protobuf:"bytes,5,opt,name=autoscalingPolicy"` + // MaxReplicas is the maximum number of MaxReplicas that Tortoise will give to HPA. + // If nil, Tortoise uses the cluster wide default value, which can be configured via the admin config. + // +optional + MaxReplicas *int32 `json:"maxReplicas,omitempty" protobuf:"bytes,6,opt,name=maxReplicas"` } type ContainerAutoscalingPolicy struct { @@ -100,7 +104,8 @@ 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. + // Tortoise never set the resources request on the container less than MinAllocatedResources. + // If nil, Tortoise uses the cluster wide default value, which can be configured via the admin config. // // If empty, tortoise may reduce the resource request to the value which is suggested from VPA. // Given the VPA suggests values based on the historical resource usage, @@ -108,6 +113,12 @@ type ContainerResourcePolicy struct { // for example, when maybe your application change will result in consuming resources more than the past. // +optional MinAllocatedResources v1.ResourceList `json:"minAllocatedResources,omitempty" protobuf:"bytes,2,opt,name=minAllocatedResources"` + + // MaxAllocatedResources is the maximum amount of resources which is given to the container. + // Tortoise never set the resources request on the container more than MaxAllocatedResources. + // If nil, Tortoise uses the cluster wide default value, which can be configured via the admin config. + // +optional + MaxAllocatedResources v1.ResourceList `json:"maxAllocatedResources,omitempty" protobuf:"bytes,3,opt,name=maxAllocatedResources"` } // +kubebuilder:validation:Enum=DeleteAll;NoDelete diff --git a/api/v1beta3/zz_generated.deepcopy.go b/api/v1beta3/zz_generated.deepcopy.go index d581c02c..2b6b2740 100644 --- a/api/v1beta3/zz_generated.deepcopy.go +++ b/api/v1beta3/zz_generated.deepcopy.go @@ -153,6 +153,13 @@ func (in *ContainerResourcePolicy) DeepCopyInto(out *ContainerResourcePolicy) { (*out)[key] = val.DeepCopy() } } + if in.MaxAllocatedResources != nil { + in, out := &in.MaxAllocatedResources, &out.MaxAllocatedResources + *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 ContainerResourcePolicy. @@ -504,6 +511,11 @@ func (in *TortoiseSpec) DeepCopyInto(out *TortoiseSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.MaxReplicas != nil { + in, out := &in.MaxReplicas, &out.MaxReplicas + *out = new(int32) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TortoiseSpec. diff --git a/config/crd/bases/autoscaling.mercari.com_tortoises.yaml b/config/crd/bases/autoscaling.mercari.com_tortoises.yaml index 8591b22f..09195403 100644 --- a/config/crd/bases/autoscaling.mercari.com_tortoises.yaml +++ b/config/crd/bases/autoscaling.mercari.com_tortoises.yaml @@ -103,6 +103,12 @@ spec: - DeleteAll - NoDelete type: string + maxReplicas: + description: MaxReplicas is the maximum number of MaxReplicas that + Tortoise will give to HPA. If nil, Tortoise uses the cluster wide + default value, which can be configured via the admin config. + format: int32 + type: integer resourcePolicy: description: ResourcePolicy contains the policy how each resource is updated. @@ -111,6 +117,19 @@ spec: containerName: description: ContainerName is the name of target container. type: string + maxAllocatedResources: + 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: MaxAllocatedResources is the maximum amount of + resources which is given to the container. Tortoise never + set the resources request on the container more than MaxAllocatedResources. + If nil, Tortoise uses the cluster wide default value, which + can be configured via the admin config. + type: object minAllocatedResources: additionalProperties: anyOf: @@ -120,13 +139,14 @@ spec: 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. Given the VPA suggests - values based on the historical resource usage, you have no - choice but to use MinAllocatedResources to pre-scaling your - Pods, for example, when maybe your application change will - result in consuming resources more than the past." + set the resources request on the container less than MinAllocatedResources. + If nil, Tortoise uses the cluster wide default value, which + can be configured via the admin config. \n If empty, tortoise + may reduce the resource request to the value which is suggested + from VPA. Given the VPA suggests values based on the historical + resource usage, you have no choice but to use MinAllocatedResources + to pre-scaling your Pods, for example, when maybe your application + change will result in consuming resources more than the past." type: object required: - containerName diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/deployment.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/deployment.yaml new file mode 100644 index 00000000..1f8bac7a --- /dev/null +++ b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/deployment.yaml @@ -0,0 +1,24 @@ +metadata: + name: mercari-app + namespace: default +spec: + selector: + matchLabels: + app: mercari + strategy: {} + template: + metadata: + annotations: + kubectl.kubernetes.io/restartedAt: "2023-01-01T00:00:00Z" + creationTimestamp: null + labels: + app: mercari + spec: + containers: + - image: awesome-mercari-app-image + name: app + resources: + requests: + cpu: "4" + memory: 4Gi +status: {} diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/hpa.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/hpa.yaml new file mode 100644 index 00000000..b8db9d51 --- /dev/null +++ b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/hpa.yaml @@ -0,0 +1,44 @@ +metadata: + annotations: + tortoise.autoscaling.mercari.com/managed-by-tortoise: "true" + name: tortoise-hpa-mercari + namespace: default +spec: + behavior: + scaleDown: + policies: + - periodSeconds: 90 + type: Percent + value: 2 + selectPolicy: Max + scaleUp: + policies: + - periodSeconds: 60 + type: Percent + value: 100 + selectPolicy: Max + stabilizationWindowSeconds: 0 + maxReplicas: 10 + metrics: + - external: + metric: + name: hoge-kept-metric + target: + type: Value + value: "1" + type: External + - containerResource: + container: app + name: cpu + target: + averageUtilization: 75 + type: Utilization + type: ContainerResource + minReplicas: 5 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: mercari-app +status: + currentMetrics: null + desiredReplicas: 0 diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/tortoise.yaml new file mode 100644 index 00000000..a8e2611a --- /dev/null +++ b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/tortoise.yaml @@ -0,0 +1,110 @@ +metadata: + finalizers: + - tortoise.autoscaling.mercari.com/finalizer + name: mercari + namespace: default +spec: + maxReplicas: 10 + resourcePolicy: + - containerName: app + maxAllocatedResources: + cpu: "1" + memory: 1Gi + targetRefs: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: mercari-app +status: + autoscalingPolicy: + - containerName: app + policy: + cpu: Horizontal + memory: Vertical + conditions: + containerRecommendationFromVPA: + - containerName: app + maxRecommendation: + cpu: + quantity: "3" + updatedAt: "2023-01-01T00:00:00Z" + memory: + quantity: 3Gi + updatedAt: "2023-01-01T00:00:00Z" + recommendation: + cpu: + quantity: "3" + updatedAt: "2023-01-01T00:00:00Z" + memory: + quantity: 3Gi + updatedAt: "2023-01-01T00:00:00Z" + containerResourceRequests: + - containerName: app + resource: + cpu: "1" + memory: 1Gi + tortoiseConditions: + - lastTransitionTime: "2023-01-01T00:00:00Z" + lastUpdateTime: "2023-01-01T00:00:00Z" + message: the current number of replicas is not bigger than the preferred max + replica number + reason: ScaledUpBasedOnPreferredMaxReplicas + status: "False" + type: ScaledUpBasedOnPreferredMaxReplicas + - lastTransitionTime: "2023-01-01T00:00:00Z" + lastUpdateTime: "2023-01-01T00:00:00Z" + message: HPA target utilization is updated + reason: HPATargetUtilizationUpdated + status: "True" + type: HPATargetUtilizationUpdated + - lastTransitionTime: "2023-01-01T00:00:00Z" + lastUpdateTime: "2023-01-01T00:00:00Z" + message: The recommendation is provided + status: "True" + type: VerticalRecommendationUpdated + - lastTransitionTime: "2023-01-01T00:00:00Z" + lastUpdateTime: "2023-01-01T00:00:00Z" + status: "False" + type: FailedToReconcile + containerResourcePhases: + - containerName: app + resourcePhases: + cpu: + lastTransitionTime: null + phase: Working + memory: + lastTransitionTime: "2023-01-01T00:00:00Z" + phase: Working + recommendations: + horizontal: + maxReplicas: + - from: 0 + timezone: Local + to: 24 + updatedAt: "2023-01-01T00:00:00Z" + value: 20 + minReplicas: + - from: 0 + timezone: Local + to: 24 + updatedAt: "2023-01-01T00:00:00Z" + value: 5 + targetUtilizations: + - containerName: app + targetUtilization: + cpu: 75 + vertical: + containerResourceRecommendation: + - RecommendedResource: + cpu: "1" + memory: 1Gi + containerName: app + targets: + horizontalPodAutoscaler: tortoise-hpa-mercari + scaleTargetRef: + kind: "" + name: "" + verticalPodAutoscalers: + - name: tortoise-monitor-mercari + role: Monitor + tortoisePhase: Working diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/vpa-Monitor.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/vpa-Monitor.yaml new file mode 100644 index 00000000..6648998b --- /dev/null +++ b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/after/vpa-Monitor.yaml @@ -0,0 +1,29 @@ +metadata: + annotations: + tortoise.autoscaling.mercari.com/managed-by-tortoise: "true" + name: tortoise-monitor-mercari + namespace: default +spec: + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: mercari-app + updatePolicy: + updateMode: "Off" +status: + conditions: + - lastTransitionTime: null + status: "True" + type: RecommendationProvided + recommendation: + containerRecommendations: + - containerName: app + lowerBound: + cpu: "3" + memory: 3Gi + target: + cpu: "3" + memory: 3Gi + upperBound: + cpu: "5" + memory: 5Gi diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/deployment.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/deployment.yaml new file mode 100644 index 00000000..22809372 --- /dev/null +++ b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/deployment.yaml @@ -0,0 +1,22 @@ +metadata: + name: mercari-app + namespace: default +spec: + selector: + matchLabels: + app: mercari + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: mercari + spec: + containers: + - image: awesome-mercari-app-image + name: app + resources: + requests: + cpu: "4" + memory: 4Gi + replicas: 10 diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/hpa.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/hpa.yaml new file mode 100644 index 00000000..8f992d7e --- /dev/null +++ b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/hpa.yaml @@ -0,0 +1,49 @@ +metadata: + annotations: + tortoise.autoscaling.mercari.com/managed-by-tortoise: "true" + name: tortoise-hpa-mercari + namespace: default +spec: + behavior: + scaleDown: + policies: + - periodSeconds: 90 + type: Percent + value: 2 + selectPolicy: Max + scaleUp: + policies: + - periodSeconds: 60 + type: Percent + value: 100 + selectPolicy: Max + stabilizationWindowSeconds: 0 + maxReplicas: 100 + metrics: + - external: + metric: + name: hoge-kept-metric + target: + type: Value + value: "1" + type: External + - external: + metric: + name: hoge-exclude-metric + target: + type: Value + value: "1" + type: External + - containerResource: + container: app + name: cpu + target: + averageUtilization: 50 + type: Utilization + type: ContainerResource + minReplicas: 1 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: mercari-app + diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/tortoise.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/tortoise.yaml new file mode 100644 index 00000000..6b879e4d --- /dev/null +++ b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/tortoise.yaml @@ -0,0 +1,71 @@ +metadata: + name: mercari + namespace: default +spec: + maxReplicas: 10 + resourcePolicy: + - containerName: app + maxAllocatedResources: + cpu: 1 + memory: 1Gi + targetRefs: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: mercari-app +status: + autoscalingPolicy: + - policy: + cpu: Horizontal + memory: Vertical + containerName: app + conditions: + containerRecommendationFromVPA: + - containerName: app + maxRecommendation: + cpu: + quantity: "0" + updatedAt: null + memory: + quantity: "0" + updatedAt: null + recommendation: + cpu: + quantity: "0" + updatedAt: null + memory: + quantity: "0" + updatedAt: null + recommendations: + horizontal: + maxReplicas: + - from: 0 + timezone: Local + to: 24 + updatedAt: "2023-10-06T01:01:24Z" + value: 15 + minReplicas: + - from: 0 + timezone: Local + to: 24 + updatedAt: "2023-10-06T01:01:24Z" + value: 3 + targetUtilizations: + - containerName: app + targetUtilization: + cpu: 50 + vertical: + containerResourceRecommendation: null + targets: + horizontalPodAutoscaler: tortoise-hpa-mercari + verticalPodAutoscalers: + - name: tortoise-monitor-mercari + role: Monitor + tortoisePhase: Working + containerResourcePhases: + - containerName: "app" + resourcePhases: + cpu: + phase: Working + memory: + phase: Working \ No newline at end of file diff --git a/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/vpa-Monitor.yaml b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/vpa-Monitor.yaml new file mode 100644 index 00000000..f4dfa94f --- /dev/null +++ b/controllers/testdata/reconcile-for-the-single-container-pod-too-big/before/vpa-Monitor.yaml @@ -0,0 +1,32 @@ +metadata: + annotations: + tortoise.autoscaling.mercari.com/managed-by-tortoise: "true" + name: tortoise-monitor-mercari + namespace: default +spec: + autoscalingPolicy: + containerPolicies: + - containerName: app + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: mercari-app + updatePolicy: + updateMode: "Off" +status: + conditions: + - lastTransitionTime: null + status: "True" + type: RecommendationProvided + recommendation: + containerRecommendations: + - containerName: app + lowerBound: + cpu: "3" + memory: 3Gi + target: + cpu: "3" + memory: 3Gi + upperBound: + cpu: "5" + memory: 5Gi diff --git a/controllers/tortoise_controller_test.go b/controllers/tortoise_controller_test.go index 0464de9b..38ad1468 100644 --- a/controllers/tortoise_controller_test.go +++ b/controllers/tortoise_controller_test.go @@ -404,6 +404,9 @@ var _ = Describe("Test TortoiseController", func() { It("TortoisePhaseWorking", func() { runTest(filepath.Join("testdata", "reconcile-for-the-single-container-pod-working")) }) + It("TortoisePhaseWorking (too big rescommendation)", func() { + runTest(filepath.Join("testdata", "reconcile-for-the-single-container-pod-too-big")) + }) It("TortoisePhaseWorking (PartlyWorking)", func() { runTest(filepath.Join("testdata", "reconcile-for-the-single-container-pod-partly-working")) }) 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 cfb5245e..3c6287c4 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 @@ -73,6 +73,10 @@ spec: - DeleteAll - NoDelete type: string + maxReplicas: + description: MaxReplicas is the maximum number of MaxReplicas that Tortoise will give to HPA. If nil, Tortoise uses the cluster wide default value, which can be configured via the admin config. + format: int32 + type: integer resourcePolicy: description: ResourcePolicy contains the policy how each resource is updated. items: @@ -80,6 +84,15 @@ spec: containerName: description: ContainerName is the name of target container. type: string + maxAllocatedResources: + 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: MaxAllocatedResources is the maximum amount of resources which is given to the container. Tortoise never set the resources request on the container more than MaxAllocatedResources. If nil, Tortoise uses the cluster wide default value, which can be configured via the admin config. + type: object minAllocatedResources: additionalProperties: anyOf: @@ -87,7 +100,7 @@ spec: - 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. Given the VPA suggests values based on the historical resource usage, you have no choice but to use MinAllocatedResources to pre-scaling your Pods, for example, when maybe your application change will result in consuming resources more than the past." + description: "MinAllocatedResources is the minimum amount of resources which is given to the container. Tortoise never set the resources request on the container less than MinAllocatedResources. If nil, Tortoise uses the cluster wide default value, which can be configured via the admin config. \n If empty, tortoise may reduce the resource request to the value which is suggested from VPA. Given the VPA suggests values based on the historical resource usage, you have no choice but to use MinAllocatedResources to pre-scaling your Pods, for example, when maybe your application change will result in consuming resources more than the past." type: object required: - containerName 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 15778c97..56137828 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 @@ -73,6 +73,10 @@ spec: - DeleteAll - NoDelete type: string + maxReplicas: + description: MaxReplicas is the maximum number of MaxReplicas that Tortoise will give to HPA. If nil, Tortoise uses the cluster wide default value, which can be configured via the admin config. + format: int32 + type: integer resourcePolicy: description: ResourcePolicy contains the policy how each resource is updated. items: @@ -80,6 +84,15 @@ spec: containerName: description: ContainerName is the name of target container. type: string + maxAllocatedResources: + 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: MaxAllocatedResources is the maximum amount of resources which is given to the container. Tortoise never set the resources request on the container more than MaxAllocatedResources. If nil, Tortoise uses the cluster wide default value, which can be configured via the admin config. + type: object minAllocatedResources: additionalProperties: anyOf: @@ -87,7 +100,7 @@ spec: - 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. Given the VPA suggests values based on the historical resource usage, you have no choice but to use MinAllocatedResources to pre-scaling your Pods, for example, when maybe your application change will result in consuming resources more than the past." + description: "MinAllocatedResources is the minimum amount of resources which is given to the container. Tortoise never set the resources request on the container less than MinAllocatedResources. If nil, Tortoise uses the cluster wide default value, which can be configured via the admin config. \n If empty, tortoise may reduce the resource request to the value which is suggested from VPA. Given the VPA suggests values based on the historical resource usage, you have no choice but to use MinAllocatedResources to pre-scaling your Pods, for example, when maybe your application change will result in consuming resources more than the past." type: object required: - containerName diff --git a/pkg/hpa/service.go b/pkg/hpa/service.go index f6d589e3..5ce80f44 100644 --- a/pkg/hpa/service.go +++ b/pkg/hpa/service.go @@ -396,6 +396,10 @@ func (c *Service) ChangeHPAFromTortoiseRecommendation(tortoise *autoscalingv1bet return nil, tortoise, fmt.Errorf("get maxReplicas recommendation: %w", err) } + if tortoise.Spec.MaxReplicas != nil && recommendMax > *tortoise.Spec.MaxReplicas { + recommendMax = *tortoise.Spec.MaxReplicas + } + if recommendMax > c.maximumMaxReplica { c.recorder.Event(tortoise, corev1.EventTypeWarning, event.WarningHittingHardMaxReplicaLimit, fmt.Sprintf("MaxReplica (%v) suggested from Tortoise (%s/%s) hits a cluster-wide maximum replica number (%v). It wouldn't be a problem until the replica number actually grows to %v though, you may want to reach out to your cluster admin.", recommendMax, tortoise.Namespace, tortoise.Name, c.maximumMaxReplica, c.maximumMaxReplica)) recommendMax = c.maximumMaxReplica diff --git a/pkg/hpa/service_test.go b/pkg/hpa/service_test.go index 7a975eda..6d046f06 100644 --- a/pkg/hpa/service_test.go +++ b/pkg/hpa/service_test.go @@ -17,7 +17,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/mercari/tortoise/api/v1beta3" - autoscalingv1beta3 "github.com/mercari/tortoise/api/v1beta3" ) func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { @@ -25,7 +24,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { type args struct { ctx context.Context - tortoise *autoscalingv1beta3.Tortoise + tortoise *v1beta3.Tortoise now time.Time } tests := []struct { @@ -34,20 +33,20 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { excludeMetricRegex string initialHPA *v2.HorizontalPodAutoscaler want *v2.HorizontalPodAutoscaler - wantTortoise *autoscalingv1beta3.Tortoise + wantTortoise *v1beta3.Tortoise wantErr bool }{ { name: "Basic test case with container resource metrics", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + tortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -61,10 +60,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Conditions: autoscalingv1beta3.Conditions{ - TortoiseConditions: []autoscalingv1beta3.TortoiseCondition{ + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ { - Type: autoscalingv1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, Status: v1.ConditionTrue, LastUpdateTime: metav1.NewTime(now.Add(-3 * time.Hour)), LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Hour)), @@ -73,30 +72,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -110,7 +109,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -119,7 +118,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -215,13 +214,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + wantTortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -235,10 +234,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Conditions: autoscalingv1beta3.Conditions{ - TortoiseConditions: []autoscalingv1beta3.TortoiseCondition{ + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ { - Type: autoscalingv1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, Status: v1.ConditionTrue, LastUpdateTime: now, LastTransitionTime: now, @@ -247,30 +246,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -284,7 +283,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -293,7 +292,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -312,13 +311,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "exclude external metrics correctly", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + tortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -332,10 +331,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Conditions: autoscalingv1beta3.Conditions{ - TortoiseConditions: []autoscalingv1beta3.TortoiseCondition{ + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ { - Type: autoscalingv1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, Status: v1.ConditionTrue, LastUpdateTime: metav1.NewTime(now.Add(-3 * time.Hour)), LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Hour)), @@ -344,30 +343,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -381,7 +380,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -390,7 +389,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -496,13 +495,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + wantTortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -516,10 +515,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Conditions: autoscalingv1beta3.Conditions{ - TortoiseConditions: []autoscalingv1beta3.TortoiseCondition{ + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ { - Type: autoscalingv1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, Status: v1.ConditionTrue, LastUpdateTime: now, LastTransitionTime: now, @@ -528,30 +527,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -565,7 +564,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -574,7 +573,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -593,13 +592,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "maximum minReplica is applied", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + tortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -613,10 +612,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Conditions: autoscalingv1beta3.Conditions{ - TortoiseConditions: []autoscalingv1beta3.TortoiseCondition{ + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ { - Type: autoscalingv1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, Status: v1.ConditionTrue, LastUpdateTime: metav1.NewTime(now.Add(-3 * time.Hour)), LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Hour)), @@ -625,30 +624,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -662,7 +661,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -671,7 +670,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -757,13 +756,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + wantTortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -777,10 +776,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Conditions: autoscalingv1beta3.Conditions{ - TortoiseConditions: []autoscalingv1beta3.TortoiseCondition{ + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ { - Type: autoscalingv1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, Status: v1.ConditionTrue, LastUpdateTime: now, LastTransitionTime: now, @@ -789,30 +788,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -826,7 +825,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -835,7 +834,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -851,16 +850,16 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { wantErr: false, }, { - name: "maximum maxReplica is applied", + name: "global maximum maxReplica is applied", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + tortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -874,10 +873,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Conditions: autoscalingv1beta3.Conditions{ - TortoiseConditions: []autoscalingv1beta3.TortoiseCondition{ + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ { - Type: autoscalingv1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, Status: v1.ConditionTrue, LastUpdateTime: metav1.NewTime(now.Add(-3 * time.Hour)), LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Hour)), @@ -886,30 +885,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -923,7 +922,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -932,7 +931,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1018,13 +1017,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + wantTortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -1038,10 +1037,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Conditions: autoscalingv1beta3.Conditions{ - TortoiseConditions: []autoscalingv1beta3.TortoiseCondition{ + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ { - Type: autoscalingv1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, Status: v1.ConditionTrue, LastUpdateTime: now, LastTransitionTime: now, @@ -1050,30 +1049,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -1087,7 +1086,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1096,7 +1095,270 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ + { + From: 0, + To: 2, + Value: 3, + UpdatedAt: now, + WeekDay: ptr.To(now.Weekday().String()), + }, + }, + }, + }, + }, + }, + wantErr: false, + }, + { + name: "tortoise maximum maxReplica is applied", + args: args{ + ctx: context.Background(), + tortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, + MaxReplicas: ptrInt32(9999), + }, + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ + { + ContainerName: "app", + Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ + v1.ResourceMemory: v1beta3.AutoscalingTypeHorizontal, + }, + }, + { + ContainerName: "istio-proxy", + Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ + v1.ResourceCPU: v1beta3.AutoscalingTypeHorizontal, + }, + }, + }, + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ + { + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Status: v1.ConditionTrue, + LastUpdateTime: metav1.NewTime(now.Add(-3 * time.Hour)), + LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Hour)), + Reason: "HPATargetUtilizationUpdated", + Message: "HPA target utilization is updated", + }, + }, + }, + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ + { + ContainerName: "app", + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ + v1.ResourceMemory: { + Phase: v1beta3.ContainerResourcePhaseWorking, + }, + }, + }, + { + ContainerName: "istio-proxy", + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ + v1.ResourceCPU: { + Phase: v1beta3.ContainerResourcePhaseWorking, + }, + }, + }, + }, + Targets: v1beta3.TargetsStatus{ + HorizontalPodAutoscaler: "hpa", + }, + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ + { + ContainerName: "app", + TargetUtilization: map[v1.ResourceName]int32{ + v1.ResourceMemory: 90, + }, + }, + { + ContainerName: "istio-proxy", + TargetUtilization: map[v1.ResourceName]int32{ + v1.ResourceCPU: 80, + }, + }, + }, + MaxReplicas: []v1beta3.ReplicasRecommendation{ + { + From: 0, + To: 2, + Value: 999999, // too big + UpdatedAt: now, + WeekDay: ptr.To(now.Weekday().String()), + }, + }, + MinReplicas: []v1beta3.ReplicasRecommendation{ + { + From: 0, + To: 2, + Value: 3, + UpdatedAt: now, + WeekDay: ptr.To(now.Weekday().String()), + }, + }, + }, + }, + }, + }, + now: now.Time, + }, + initialHPA: &v2.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{ + Name: "hpa", + }, + Spec: v2.HorizontalPodAutoscalerSpec{ + MinReplicas: ptrInt32(3), + MaxReplicas: 6, + Metrics: []v2.MetricSpec{ + { + Type: v2.ObjectMetricSourceType, + // should be ignored + }, + { + Type: v2.ContainerResourceMetricSourceType, + ContainerResource: &v2.ContainerResourceMetricSource{ + Name: v1.ResourceMemory, + Target: v2.MetricTarget{ + AverageUtilization: ptr.To[int32](60), + }, + Container: "app", + }, + }, + { + Type: v2.ContainerResourceMetricSourceType, + ContainerResource: &v2.ContainerResourceMetricSource{ + Name: v1.ResourceCPU, + Target: v2.MetricTarget{ + AverageUtilization: ptr.To[int32](50), + }, + Container: "istio-proxy", + }, + }, + }, + }, + }, + want: &v2.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{ + Name: "hpa", + }, + Spec: v2.HorizontalPodAutoscalerSpec{ + Behavior: globalRecommendedHPABehavior.DeepCopy(), + MinReplicas: ptrInt32(3), + MaxReplicas: 9999, // maximum maxReplica + Metrics: []v2.MetricSpec{ + { + Type: v2.ObjectMetricSourceType, + // should be ignored + }, + { + Type: v2.ContainerResourceMetricSourceType, + ContainerResource: &v2.ContainerResourceMetricSource{ + Name: v1.ResourceMemory, + Target: v2.MetricTarget{ + AverageUtilization: ptr.To[int32](90), + }, + Container: "app", + }, + }, + { + Type: v2.ContainerResourceMetricSourceType, + ContainerResource: &v2.ContainerResourceMetricSource{ + Name: v1.ResourceCPU, + Target: v2.MetricTarget{ + AverageUtilization: ptr.To[int32](80), + }, + Container: "istio-proxy", + }, + }, + }, + }, + }, + wantTortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, + MaxReplicas: ptrInt32(9999), + }, + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ + { + ContainerName: "app", + Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ + v1.ResourceMemory: v1beta3.AutoscalingTypeHorizontal, + }, + }, + { + ContainerName: "istio-proxy", + Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ + v1.ResourceCPU: v1beta3.AutoscalingTypeHorizontal, + }, + }, + }, + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ + { + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Status: v1.ConditionTrue, + LastUpdateTime: now, + LastTransitionTime: now, + Reason: "HPATargetUtilizationUpdated", + Message: "HPA target utilization is updated", + }, + }, + }, + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ + { + ContainerName: "app", + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ + v1.ResourceMemory: { + Phase: v1beta3.ContainerResourcePhaseWorking, + }, + }, + }, + { + ContainerName: "istio-proxy", + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ + v1.ResourceCPU: { + Phase: v1beta3.ContainerResourcePhaseWorking, + }, + }, + }, + }, + Targets: v1beta3.TargetsStatus{ + HorizontalPodAutoscaler: "hpa", + }, + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ + { + ContainerName: "app", + TargetUtilization: map[v1.ResourceName]int32{ + v1.ResourceMemory: 90, + }, + }, + { + ContainerName: "istio-proxy", + TargetUtilization: map[v1.ResourceName]int32{ + v1.ResourceCPU: 80, + }, + }, + }, + MaxReplicas: []v1beta3.ReplicasRecommendation{ + { + From: 0, + To: 2, + Value: 999999, + UpdatedAt: now, + WeekDay: ptr.To(now.Weekday().String()), + }, + }, + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1115,13 +1377,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "the change is limited by tortoiseHPATargetUtilizationMaxIncrease", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + tortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -1135,30 +1397,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -1172,7 +1434,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1181,7 +1443,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1273,13 +1535,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "no update preformed when we recently updated it", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + tortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -1293,10 +1555,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Conditions: autoscalingv1beta3.Conditions{ - TortoiseConditions: []autoscalingv1beta3.TortoiseCondition{ + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ { - Type: autoscalingv1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, Status: v1.ConditionTrue, LastUpdateTime: metav1.NewTime(now.Add(-1 * time.Minute)), LastTransitionTime: metav1.NewTime(now.Add(-1 * time.Minute)), @@ -1305,30 +1567,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -1342,7 +1604,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1351,7 +1613,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1437,13 +1699,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + wantTortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -1457,10 +1719,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Conditions: autoscalingv1beta3.Conditions{ - TortoiseConditions: []autoscalingv1beta3.TortoiseCondition{ + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ { - Type: autoscalingv1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, Status: v1.ConditionTrue, LastUpdateTime: now, LastTransitionTime: metav1.NewTime(now.Add(-1 * time.Minute)), @@ -1469,30 +1731,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -1506,7 +1768,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1515,7 +1777,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1534,13 +1796,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "no update preformed when updateMode is Off", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeOff, + tortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeOff, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -1554,30 +1816,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -1591,7 +1853,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1600,7 +1862,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1691,13 +1953,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "no update preformed when all horizontal is unready", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeOff, + tortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeOff, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseGatheringData, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseGatheringData, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -1711,30 +1973,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseGatheringData, + Phase: v1beta3.ContainerResourcePhaseGatheringData, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseGatheringData, + Phase: v1beta3.ContainerResourcePhaseGatheringData, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -1748,7 +2010,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1757,7 +2019,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1848,13 +2110,13 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "no update preformed when ContainerResourcePhases isn't working", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Spec: autoscalingv1beta3.TortoiseSpec{ - UpdateMode: autoscalingv1beta3.UpdateModeAuto, + tortoise: &v1beta3.Tortoise{ + Spec: v1beta3.TortoiseSpec{ + UpdateMode: v1beta3.UpdateModeAuto, }, - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhasePartlyWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhasePartlyWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -1868,30 +2130,30 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseGatheringData, + Phase: v1beta3.ContainerResourcePhaseGatheringData, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -1905,7 +2167,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -1914,7 +2176,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -2006,10 +2268,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "emergency mode", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseEmergency, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + tortoise: &v1beta3.Tortoise{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseEmergency, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -2023,12 +2285,12 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -2042,7 +2304,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -2051,7 +2313,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -2143,10 +2405,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "minReplicas are reduced gradually during BackToNormal", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseBackToNormal, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + tortoise: &v1beta3.Tortoise{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseBackToNormal, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -2160,12 +2422,12 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -2179,7 +2441,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -2188,7 +2450,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -2280,10 +2542,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { name: "BackToNormal finishes when minReplicas reaches the ideal value", args: args{ ctx: context.Background(), - tortoise: &autoscalingv1beta3.Tortoise{ - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseBackToNormal, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + tortoise: &v1beta3.Tortoise{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseBackToNormal, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -2297,12 +2559,12 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -2316,7 +2578,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -2325,7 +2587,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -2411,10 +2673,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ - Status: autoscalingv1beta3.TortoiseStatus{ - TortoisePhase: autoscalingv1beta3.TortoisePhaseWorking, - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + wantTortoise: &v1beta3.Tortoise{ + Status: v1beta3.TortoiseStatus{ + TortoisePhase: v1beta3.TortoisePhaseWorking, + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -2428,10 +2690,10 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Conditions: autoscalingv1beta3.Conditions{ - TortoiseConditions: []autoscalingv1beta3.TortoiseCondition{ + Conditions: v1beta3.Conditions{ + TortoiseConditions: []v1beta3.TortoiseCondition{ { - Type: autoscalingv1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, + Type: v1beta3.TortoiseConditionTypeHPATargetUtilizationUpdated, Status: v1.ConditionTrue, LastUpdateTime: now, LastTransitionTime: now, @@ -2440,12 +2702,12 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, - Recommendations: autoscalingv1beta3.Recommendations{ - Horizontal: autoscalingv1beta3.HorizontalRecommendations{ - TargetUtilizations: []autoscalingv1beta3.HPATargetUtilizationRecommendationPerContainer{ + Recommendations: v1beta3.Recommendations{ + Horizontal: v1beta3.HorizontalRecommendations{ + TargetUtilizations: []v1beta3.HPATargetUtilizationRecommendationPerContainer{ { ContainerName: "app", TargetUtilization: map[v1.ResourceName]int32{ @@ -2459,7 +2721,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { }, }, }, - MaxReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MaxReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -2468,7 +2730,7 @@ func TestClient_UpdateHPAFromTortoiseRecommendation(t *testing.T) { WeekDay: ptr.To(now.Weekday().String()), }, }, - MinReplicas: []autoscalingv1beta3.ReplicasRecommendation{ + MinReplicas: []v1beta3.ReplicasRecommendation{ { From: 0, To: 2, @@ -2514,7 +2776,7 @@ func ptrInt32(i int32) *int32 { func TestService_InitializeHPA(t *testing.T) { type args struct { - tortoise *autoscalingv1beta3.Tortoise + tortoise *v1beta3.Tortoise replicaNum int32 } tests := []struct { @@ -2527,22 +2789,22 @@ func TestService_InitializeHPA(t *testing.T) { { name: "should create new hpa", args: args{ - tortoise: &autoscalingv1beta3.Tortoise{ + tortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", APIVersion: "apps/v1", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -2625,22 +2887,22 @@ func TestService_InitializeHPA(t *testing.T) { { name: "just give annotation to existing hpa", args: args{ - tortoise: &autoscalingv1beta3.Tortoise{ + tortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -2739,7 +3001,7 @@ func TestService_InitializeHPA(t *testing.T) { func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { type args struct { - tortoise *autoscalingv1beta3.Tortoise + tortoise *v1beta3.Tortoise replicaNum int32 } tests := []struct { @@ -2748,28 +3010,28 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { initialHPA *v2.HorizontalPodAutoscaler args args afterHPA *v2.HorizontalPodAutoscaler - wantTortoise *autoscalingv1beta3.Tortoise + wantTortoise *v1beta3.Tortoise wantErr bool }{ { name: "add metrics to existing hpa", args: args{ - tortoise: &autoscalingv1beta3.Tortoise{ + tortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -2785,31 +3047,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "existing-hpa", }, }, @@ -2855,22 +3117,22 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ + wantTortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -2886,31 +3148,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseGatheringData, + Phase: v1beta3.ContainerResourcePhaseGatheringData, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "existing-hpa", }, }, @@ -2969,22 +3231,22 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { { name: "remove metrics from hpa", args: args{ - tortoise: &autoscalingv1beta3.Tortoise{ + tortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -3000,31 +3262,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -3081,22 +3343,22 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ + wantTortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -3112,31 +3374,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -3184,22 +3446,22 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { { name: "when remove all horizontal, hpa would be removed if it's created by Tortoise", args: args{ - tortoise: &autoscalingv1beta3.Tortoise{ + tortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - DeletionPolicy: autoscalingv1beta3.DeletionPolicyDeleteAll, - TargetRefs: autoscalingv1beta3.TargetRefs{ - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + Spec: v1beta3.TortoiseSpec{ + DeletionPolicy: v1beta3.DeletionPolicyDeleteAll, + TargetRefs: v1beta3.TargetRefs{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -3215,31 +3477,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -3296,22 +3558,22 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ + wantTortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - DeletionPolicy: autoscalingv1beta3.DeletionPolicyDeleteAll, - TargetRefs: autoscalingv1beta3.TargetRefs{ - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + Spec: v1beta3.TortoiseSpec{ + DeletionPolicy: v1beta3.DeletionPolicyDeleteAll, + TargetRefs: v1beta3.TargetRefs{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -3327,31 +3589,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -3361,23 +3623,23 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { { name: "when remove all horizontal, hpa would be disabled if it's created by users", args: args{ - tortoise: &autoscalingv1beta3.Tortoise{ + tortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - DeletionPolicy: autoscalingv1beta3.DeletionPolicyDeleteAll, - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + DeletionPolicy: v1beta3.DeletionPolicyDeleteAll, + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -3393,31 +3655,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -3474,23 +3736,23 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ + wantTortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - DeletionPolicy: autoscalingv1beta3.DeletionPolicyDeleteAll, - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + DeletionPolicy: v1beta3.DeletionPolicyDeleteAll, + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -3506,31 +3768,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -3565,22 +3827,22 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { { name: "remove metrics from hpa, but not remove the external metrics", args: args{ - tortoise: &autoscalingv1beta3.Tortoise{ + tortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -3596,31 +3858,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -3685,22 +3947,22 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ + wantTortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -3716,31 +3978,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -3796,22 +4058,22 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { { name: "add metrics to existing hpa (with external metrics)", args: args{ - tortoise: &autoscalingv1beta3.Tortoise{ + tortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -3827,31 +4089,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -3905,22 +4167,22 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ + wantTortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -3936,31 +4198,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseGatheringData, + Phase: v1beta3.ContainerResourcePhaseGatheringData, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -4027,22 +4289,22 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { { name: "Resource type metric is removed", args: args{ - tortoise: &autoscalingv1beta3.Tortoise{ + tortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -4058,31 +4320,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, @@ -4157,22 +4419,22 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - wantTortoise: &autoscalingv1beta3.Tortoise{ + wantTortoise: &v1beta3.Tortoise{ ObjectMeta: metav1.ObjectMeta{ Name: "tortoise", Namespace: "default", }, - Spec: autoscalingv1beta3.TortoiseSpec{ - TargetRefs: autoscalingv1beta3.TargetRefs{ + Spec: v1beta3.TortoiseSpec{ + TargetRefs: v1beta3.TargetRefs{ HorizontalPodAutoscalerName: ptr.To("existing-hpa"), - ScaleTargetRef: autoscalingv1beta3.CrossVersionObjectReference{ + ScaleTargetRef: v1beta3.CrossVersionObjectReference{ Kind: "Deployment", Name: "deployment", }, }, }, - Status: autoscalingv1beta3.TortoiseStatus{ - AutoscalingPolicy: []autoscalingv1beta3.ContainerAutoscalingPolicy{ + Status: v1beta3.TortoiseStatus{ + AutoscalingPolicy: []v1beta3.ContainerAutoscalingPolicy{ { ContainerName: "app", Policy: map[v1.ResourceName]v1beta3.AutoscalingType{ @@ -4188,31 +4450,31 @@ func TestService_UpdateHPASpecFromTortoiseAutoscalingPolicy(t *testing.T) { }, }, }, - ContainerResourcePhases: []autoscalingv1beta3.ContainerResourcePhases{ + ContainerResourcePhases: []v1beta3.ContainerResourcePhases{ { ContainerName: "app", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, { ContainerName: "istio-proxy", - ResourcePhases: map[v1.ResourceName]autoscalingv1beta3.ResourcePhase{ + ResourcePhases: map[v1.ResourceName]v1beta3.ResourcePhase{ v1.ResourceCPU: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, v1.ResourceMemory: { - Phase: autoscalingv1beta3.ContainerResourcePhaseWorking, + Phase: v1beta3.ContainerResourcePhaseWorking, }, }, }, }, - Targets: autoscalingv1beta3.TargetsStatus{ + Targets: v1beta3.TargetsStatus{ HorizontalPodAutoscaler: "hpa", }, }, diff --git a/pkg/recommender/recommender.go b/pkg/recommender/recommender.go index f4fa5708..6cb13143 100644 --- a/pkg/recommender/recommender.go +++ b/pkg/recommender/recommender.go @@ -154,6 +154,12 @@ func (s *Service) updateVPARecommendation(ctx context.Context, tortoise *v1beta3 minAllocatedResourcesMap[r.ContainerName] = r.MinAllocatedResources } + // containerName → MaxAllocatedResources + maxAllocatedResourcesMap := map[string]v1.ResourceList{} + for _, r := range tortoise.Spec.ResourcePolicy { + maxAllocatedResourcesMap[r.ContainerName] = r.MaxAllocatedResources + } + newRecommendations := []v1beta3.RecommendedContainerResources{} for _, r := range tortoise.Status.AutoscalingPolicy { recommendation := v1beta3.RecommendedContainerResources{ @@ -188,7 +194,7 @@ func (s *Service) updateVPARecommendation(ctx context.Context, tortoise *v1beta3 var newSize int64 var reason string var err error - newSize, reason, err = s.calculateBestNewSize(ctx, tortoise, p, r.ContainerName, recom, k, hpa, replicaNum, req, minAllocatedResourcesMap[r.ContainerName], scaledUpBasedOnPreferredMaxReplicas, now) + newSize, reason, err = s.calculateBestNewSize(ctx, tortoise, p, r.ContainerName, recom, k, hpa, replicaNum, req, minAllocatedResourcesMap[r.ContainerName], maxAllocatedResourcesMap[r.ContainerName], scaledUpBasedOnPreferredMaxReplicas) if err != nil { return tortoise, err } @@ -237,9 +243,8 @@ func (s *Service) calculateBestNewSize( hpa *v2.HorizontalPodAutoscaler, replicaNum int32, resourceRequest resource.Quantity, - minAllocatedResources corev1.ResourceList, + minAllocatedResources, maxAllocatedResources corev1.ResourceList, scaledUpBasedOnPreferredMaxReplicas bool, - now time.Time, ) (int64, string, error) { if p == v1beta3.AutoscalingTypeOff { // Just keep the current resource request. @@ -258,7 +263,7 @@ func (s *Service) calculateBestNewSize( // so that we increase the resource request more than actually needed, // which reduces the need of scaling up in the future. idealSize = idealSize * (1 + s.bufferRatioOnVerticalResource) - jastified := s.justifyNewSize(resourceRequest.MilliValue(), int64(idealSize), k, minAllocatedResources, containerName) + jastified := s.justifyNewSize(resourceRequest.MilliValue(), int64(idealSize), k, minAllocatedResources, maxAllocatedResources, containerName) return jastified, fmt.Sprintf("change %v request (%v) (%v → %v) based on VPA suggestion", k, containerName, resourceRequest.MilliValue(), jastified), nil } @@ -268,7 +273,7 @@ func (s *Service) calculateBestNewSize( previousIdealSize := float64(resourceRequest.MilliValue()) / (1 + s.bufferRatioOnVerticalResource) if previousIdealSize*(1-s.bufferRatioOnVerticalResource) > idealSize { // The current ideal size is too small campared to the previous ideal size. - jastified := s.justifyNewSize(resourceRequest.MilliValue(), int64(idealSize), k, minAllocatedResources, containerName) + jastified := s.justifyNewSize(resourceRequest.MilliValue(), int64(idealSize), k, minAllocatedResources, maxAllocatedResources, containerName) return jastified, fmt.Sprintf("change %v request (%v) (%v → %v) based on VPA suggestion", k, containerName, resourceRequest.MilliValue(), jastified), nil } @@ -286,7 +291,7 @@ func (s *Service) calculateBestNewSize( if scaledUpBasedOnPreferredMaxReplicas { // We keep increasing the size until we hit the maxResourceSize. newSize := int64(float64(resourceRequest.MilliValue()) * 1.3) - jastifiedNewSize := s.justifyNewSize(resourceRequest.MilliValue(), newSize, k, minAllocatedResources, containerName) + jastifiedNewSize := s.justifyNewSize(resourceRequest.MilliValue(), newSize, k, minAllocatedResources, maxAllocatedResources, containerName) msg := fmt.Sprintf("the current number of replicas (%v) is bigger than the preferred max replica number in this cluster (%v), so make %v request (%s) bigger (%v → %v)", replicaNum, s.preferredMaxReplicas, k, containerName, resourceRequest.MilliValue(), jastifiedNewSize) return jastifiedNewSize, msg, nil } @@ -303,7 +308,7 @@ func (s *Service) calculateBestNewSize( // We use the recommended resource request if it's smaller than the current resource request. newSize = recommendedResourceRequest.MilliValue() } - jastified := s.justifyNewSize(resourceRequest.MilliValue(), newSize, k, minAllocatedResources, containerName) + jastified := s.justifyNewSize(resourceRequest.MilliValue(), newSize, k, minAllocatedResources, maxAllocatedResources, containerName) return jastified, fmt.Sprintf("the current number of replicas is equal or smaller than the minimum min replica number in this cluster (%v), so make %v request (%v) smaller (%v → %v) based on VPA suggestion", s.minimumMinReplicas, k, containerName, resourceRequest.MilliValue(), jastified), nil } @@ -315,7 +320,7 @@ func (s *Service) calculateBestNewSize( // Also, if the current replica number is equal to the minReplicas, // we don't change the resource request based on the current resource utilization // because even if the resource utilization is low, it's due to the minReplicas. - return s.justifyNewSize(resourceRequest.MilliValue(), resourceRequest.MilliValue(), k, minAllocatedResources, containerName), "nothing to do", nil + return s.justifyNewSize(resourceRequest.MilliValue(), resourceRequest.MilliValue(), k, minAllocatedResources, maxAllocatedResources, containerName), "nothing to do", nil } targetUtilizationValue, err := hpaservice.GetHPATargetValue(ctx, hpa, containerName, k) @@ -334,13 +339,13 @@ func (s *Service) calculateBestNewSize( // And this case, reducing the resource request of container in this kind of weird situation // so that the upper usage will be the target usage. newSize := int64(float64(recommendedResourceRequest.MilliValue()) * 100.0 / float64(targetUtilizationValue)) - jastified := s.justifyNewSize(resourceRequest.MilliValue(), newSize, k, minAllocatedResources, containerName) + jastified := s.justifyNewSize(resourceRequest.MilliValue(), newSize, k, minAllocatedResources, maxAllocatedResources, containerName) return jastified, fmt.Sprintf("the current resource usage (%v, %v%%) is too small and it's due to unbalanced container size, so make %v request (%v) smaller (%v → %v) based on VPA's recommendation and HPA target utilization %v%%", recommendedResourceRequest.MilliValue(), int(upperUtilization), k, containerName, resourceRequest.MilliValue(), jastified, targetUtilizationValue), nil } // Just keep the current resource request. // Only do justification. - return s.justifyNewSize(resourceRequest.MilliValue(), resourceRequest.MilliValue(), k, minAllocatedResources, containerName), "nothing to do", nil + return s.justifyNewSize(resourceRequest.MilliValue(), resourceRequest.MilliValue(), k, minAllocatedResources, maxAllocatedResources, containerName), "nothing to do", nil } func hasHorizontal(tortoise *v1beta3.Tortoise) bool { @@ -377,8 +382,8 @@ func (s *Service) getGlobalMinResourceSize(k corev1.ResourceName, containerName return s.minResourceSizePerContainer["*"][k] } -func (s *Service) justifyNewSize(oldSizeMilli, newSizeMilli int64, k corev1.ResourceName, minAllocatedResources corev1.ResourceList, containerName string) int64 { - max := s.maxResourceSize[k] +func (s *Service) justifyNewSize(oldSizeMilli, newSizeMilli int64, k corev1.ResourceName, minAllocatedResources, maxAllocatedResources corev1.ResourceList, containerName string) int64 { + max := maxAllocatedResources[k] min := minAllocatedResources[k] // Bigger min requirement is used. @@ -387,6 +392,13 @@ func (s *Service) justifyNewSize(oldSizeMilli, newSizeMilli int64, k corev1.Reso min = s.getGlobalMinResourceSize(k, containerName) } + // Smaller max requirement is used. + if max.Cmp(s.maxResourceSize[k]) > 0 || max.IsZero() { + // s.maxResourceSize[k] is smaller than maxAllocatedResources[k] + // OR maxAllocatedResources[k] is unset. + max = s.maxResourceSize[k] + } + // If the new size is too small, which isn't acceptable based on the maxAllowedScalingDownRatio. // We use oldSizeMilli * s.maxAllowedScalingDownRatio as the new size. // diff --git a/pkg/recommender/recommender_test.go b/pkg/recommender/recommender_test.go index 851ae30c..cb2cb0e7 100644 --- a/pkg/recommender/recommender_test.go +++ b/pkg/recommender/recommender_test.go @@ -2195,7 +2195,7 @@ func TestService_UpdateVPARecommendation(t *testing.T) { wantErr: false, }, { - name: "all horizontal: requested resources exceed maxResourceSize", + name: "all horizontal: recommendation exceed the global maxResourceSize", fields: fields{ preferredMaxReplicas: 5, maxCPU: "1000m", @@ -2739,6 +2739,160 @@ func TestService_UpdateVPARecommendation(t *testing.T) { }).Build(), wantErr: false, }, + { + name: "all vertical: use MaxAllocatedResources when VPA recommendation is bigger than MaxAllocatedResources", + fields: fields{ + preferredMaxReplicas: 6, + maxCPU: "1000m", + maxMemory: "1Gi", + }, + args: args{ + hpa: &v2.HorizontalPodAutoscaler{ + Spec: v2.HorizontalPodAutoscalerSpec{ + MinReplicas: ptr.To[int32](1), + Metrics: []v2.MetricSpec{}, + }, + }, + tortoise: utils.NewTortoiseBuilder().AddAutoscalingPolicy(v1beta3.ContainerAutoscalingPolicy{ + ContainerName: "test-container", + Policy: map[corev1.ResourceName]v1beta3.AutoscalingType{ + corev1.ResourceCPU: v1beta3.AutoscalingTypeVertical, + corev1.ResourceMemory: v1beta3.AutoscalingTypeVertical, + }, + }).AddResourcePolicy(v1beta3.ContainerResourcePolicy{ + ContainerName: "test-container", + MaxAllocatedResources: createResourceList("300m", "300Mi"), + }).AddContainerRecommendationFromVPA( + v1beta3.ContainerRecommendationFromVPA{ + ContainerName: "test-container", + MaxRecommendation: map[corev1.ResourceName]v1beta3.ResourceQuantity{ + corev1.ResourceCPU: { + Quantity: resource.MustParse("500m"), // too big + }, + corev1.ResourceMemory: { + Quantity: resource.MustParse("0.5Gi"), // too big + }, + }, + }, + ).AddContainerResourceRequests(v1beta3.ContainerResourceRequests{ + ContainerName: "test-container", + Resource: createResourceList("130m", "130Mi"), + }).Build(), + replicaNum: 3, + }, + want: utils.NewTortoiseBuilder().AddAutoscalingPolicy(v1beta3.ContainerAutoscalingPolicy{ + ContainerName: "test-container", + Policy: map[corev1.ResourceName]v1beta3.AutoscalingType{ + corev1.ResourceCPU: v1beta3.AutoscalingTypeVertical, + corev1.ResourceMemory: v1beta3.AutoscalingTypeVertical, + }, + }).AddResourcePolicy(v1beta3.ContainerResourcePolicy{ + ContainerName: "test-container", + MaxAllocatedResources: createResourceList("300m", "300Mi"), + }).AddContainerRecommendationFromVPA( + v1beta3.ContainerRecommendationFromVPA{ + ContainerName: "test-container", + MaxRecommendation: map[corev1.ResourceName]v1beta3.ResourceQuantity{ + corev1.ResourceCPU: { + Quantity: resource.MustParse("500m"), + }, + corev1.ResourceMemory: { + Quantity: resource.MustParse("0.5Gi"), + }, + }, + }, + ).AddContainerResourceRequests(v1beta3.ContainerResourceRequests{ + ContainerName: "test-container", + Resource: createResourceList("130m", "130Mi"), + }).SetRecommendations(v1beta3.Recommendations{ + Vertical: v1beta3.VerticalRecommendations{ + ContainerResourceRecommendation: []v1beta3.RecommendedContainerResources{ + { + ContainerName: "test-container", + RecommendedResource: createResourceList("300m", "300Mi"), // same as MinAllocatedResources + }, + }, + }, + }).Build(), + wantErr: false, + }, + { + name: "all vertical: use global MaxAllocatedResources when defined MaxAllocatedResources is bigger than global MaxAllocatedResources", + fields: fields{ + preferredMaxReplicas: 6, + maxCPU: "300m", + maxMemory: "300Mi", + }, + args: args{ + hpa: &v2.HorizontalPodAutoscaler{ + Spec: v2.HorizontalPodAutoscalerSpec{ + MinReplicas: ptr.To[int32](1), + Metrics: []v2.MetricSpec{}, + }, + }, + tortoise: utils.NewTortoiseBuilder().AddAutoscalingPolicy(v1beta3.ContainerAutoscalingPolicy{ + ContainerName: "test-container", + Policy: map[corev1.ResourceName]v1beta3.AutoscalingType{ + corev1.ResourceCPU: v1beta3.AutoscalingTypeVertical, + corev1.ResourceMemory: v1beta3.AutoscalingTypeVertical, + }, + }).AddResourcePolicy(v1beta3.ContainerResourcePolicy{ + ContainerName: "test-container", + MaxAllocatedResources: createResourceList("1000m", "1Gi"), + }).AddContainerRecommendationFromVPA( + v1beta3.ContainerRecommendationFromVPA{ + ContainerName: "test-container", + MaxRecommendation: map[corev1.ResourceName]v1beta3.ResourceQuantity{ + corev1.ResourceCPU: { + Quantity: resource.MustParse("500m"), // too big + }, + corev1.ResourceMemory: { + Quantity: resource.MustParse("0.5Gi"), // too big + }, + }, + }, + ).AddContainerResourceRequests(v1beta3.ContainerResourceRequests{ + ContainerName: "test-container", + Resource: createResourceList("130m", "130Mi"), + }).Build(), + replicaNum: 3, + }, + want: utils.NewTortoiseBuilder().AddAutoscalingPolicy(v1beta3.ContainerAutoscalingPolicy{ + ContainerName: "test-container", + Policy: map[corev1.ResourceName]v1beta3.AutoscalingType{ + corev1.ResourceCPU: v1beta3.AutoscalingTypeVertical, + corev1.ResourceMemory: v1beta3.AutoscalingTypeVertical, + }, + }).AddResourcePolicy(v1beta3.ContainerResourcePolicy{ + ContainerName: "test-container", + MaxAllocatedResources: createResourceList("1000m", "1Gi"), + }).AddContainerRecommendationFromVPA( + v1beta3.ContainerRecommendationFromVPA{ + ContainerName: "test-container", + MaxRecommendation: map[corev1.ResourceName]v1beta3.ResourceQuantity{ + corev1.ResourceCPU: { + Quantity: resource.MustParse("500m"), + }, + corev1.ResourceMemory: { + Quantity: resource.MustParse("0.5Gi"), + }, + }, + }, + ).AddContainerResourceRequests(v1beta3.ContainerResourceRequests{ + ContainerName: "test-container", + Resource: createResourceList("130m", "130Mi"), + }).SetRecommendations(v1beta3.Recommendations{ + Vertical: v1beta3.VerticalRecommendations{ + ContainerResourceRecommendation: []v1beta3.RecommendedContainerResources{ + { + ContainerName: "test-container", + RecommendedResource: createResourceList("300m", "300Mi"), // same as MinAllocatedResources + }, + }, + }, + }).Build(), + wantErr: false, + }, { name: "all vertical: use MinAllocatedResources when VPA recommendation is smaller than MinAllocatedResources", fields: fields{