Reflect expected replica count to the output of kubectl scale

This commit is contained in:
Arda Güçlü 2026-02-11 15:12:44 +03:00
parent 8b09f925a7
commit ccd53e4eeb
6 changed files with 164 additions and 38 deletions

View file

@ -24,6 +24,7 @@ import (
"k8s.io/klog/v2"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericiooptions"
@ -238,13 +239,22 @@ func (o *ScaleOptions) RunScale() error {
for _, info := range infos {
mapping := info.ResourceMapping()
if o.dryRunStrategy == cmdutil.DryRunClient {
if err = updateReplicas(info, int64(o.Replicas)); err != nil {
return err
}
if err := o.PrintObj(info.Object, o.Out); err != nil {
return err
}
continue
}
if err := o.scaler.Scale(info.Namespace, info.Name, uint(o.Replicas), precondition, retry, waitForReplicas, mapping.Resource, o.dryRunStrategy == cmdutil.DryRunServer); err != nil {
actualSize := new(int32)
if err := o.scaler.Scale(info.Namespace, info.Name, uint(o.Replicas), actualSize, precondition, retry, waitForReplicas, mapping.Resource, o.dryRunStrategy == cmdutil.DryRunServer); err != nil {
return err
}
if err = updateReplicas(info, int64(*actualSize)); err != nil {
return err
}
@ -279,3 +289,23 @@ func scaler(f cmdutil.Factory) (scale.Scaler, error) {
return scale.NewScaler(scalesGetter), nil
}
// updateReplicas updates spec.replicas for built-in scalable types.
// replicas needs to be in int64, as SetNestedField only supports this type (and float64).
func updateReplicas(info *resource.Info, replicas int64) error {
unstructuredObj, ok := info.Object.(*unstructured.Unstructured)
if !ok {
return nil
}
// Only update for built-in types where spec.replicas is guaranteed:
// - apps group: Deployment, ReplicaSet, StatefulSet
// - core group: ReplicationController
// Skip other groups (e.g., CRDs) as they may define replicas at a different path.
gvk := unstructuredObj.GroupVersionKind()
if gvk.Group != "apps" && gvk.Group != "" {
return nil
}
return unstructured.SetNestedField(unstructuredObj.Object, replicas, "spec", "replicas")
}

View file

@ -39,10 +39,10 @@ type Scaler interface {
// retries in the event of resource version mismatch (if retry is not nil),
// and optionally waits until the status of the resource matches newSize (if wait is not nil)
// TODO: Make the implementation of this watch-based (#56075) once #31345 is fixed.
Scale(namespace, name string, newSize uint, preconditions *ScalePrecondition, retry, wait *RetryParams, gvr schema.GroupVersionResource, dryRun bool) error
Scale(namespace, name string, newSize uint, actualSize *int32, preconditions *ScalePrecondition, retry, wait *RetryParams, gvr schema.GroupVersionResource, dryRun bool) error
// ScaleSimple does a simple one-shot attempt at scaling - not useful on its own, but
// a necessary building block for Scale
ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint, gvr schema.GroupVersionResource, dryRun bool) (updatedResourceVersion string, err error)
ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint, gvr schema.GroupVersionResource, dryRun bool) (updatedResourceVersion string, actualSize int32, err error)
}
// NewScaler get a scaler for a given resource
@ -81,12 +81,15 @@ func NewRetryParams(interval, timeout time.Duration) *RetryParams {
}
// ScaleCondition is a closure around Scale that facilitates retries via util.wait
func ScaleCondition(r Scaler, precondition *ScalePrecondition, namespace, name string, count uint, updatedResourceVersion *string, gvr schema.GroupVersionResource, dryRun bool) wait.ConditionWithContextFunc {
func ScaleCondition(r Scaler, precondition *ScalePrecondition, namespace, name string, count uint, updatedResourceVersion *string, actualSize *int32, gvr schema.GroupVersionResource, dryRun bool) wait.ConditionWithContextFunc {
return func(context.Context) (bool, error) {
rv, err := r.ScaleSimple(namespace, name, precondition, count, gvr, dryRun)
rv, size, err := r.ScaleSimple(namespace, name, precondition, count, gvr, dryRun)
if updatedResourceVersion != nil {
*updatedResourceVersion = rv
}
if actualSize != nil {
*actualSize = size
}
// Retry only on update conflicts.
if apierrors.IsConflict(err) {
return false, nil
@ -117,14 +120,14 @@ type genericScaler struct {
var _ Scaler = &genericScaler{}
// ScaleSimple updates a scale of a given resource. It returns the resourceVersion of the scale if the update was successful.
func (s *genericScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint, gvr schema.GroupVersionResource, dryRun bool) (updatedResourceVersion string, err error) {
func (s *genericScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint, gvr schema.GroupVersionResource, dryRun bool) (updatedResourceVersion string, actualSize int32, err error) {
if preconditions != nil {
scale, err := s.scaleNamespacer.Scales(namespace).Get(context.TODO(), gvr.GroupResource(), name, metav1.GetOptions{})
if err != nil {
return "", err
return "", 0, err
}
if err = preconditions.validate(scale); err != nil {
return "", err
return "", 0, err
}
scale.Spec.Replicas = int32(newSize)
updateOptions := metav1.UpdateOptions{}
@ -133,9 +136,9 @@ func (s *genericScaler) ScaleSimple(namespace, name string, preconditions *Scale
}
updatedScale, err := s.scaleNamespacer.Scales(namespace).Update(context.TODO(), gvr.GroupResource(), scale, updateOptions)
if err != nil {
return "", err
return "", 0, err
}
return updatedScale.ResourceVersion, nil
return updatedScale.ResourceVersion, updatedScale.Spec.Replicas, nil
}
// objectForReplicas is used for encoding scale patch
@ -151,7 +154,7 @@ func (s *genericScaler) ScaleSimple(namespace, name string, preconditions *Scale
}
patch, err := json.Marshal(&spec)
if err != nil {
return "", err
return "", 0, err
}
patchOptions := metav1.PatchOptions{}
if dryRun {
@ -159,19 +162,19 @@ func (s *genericScaler) ScaleSimple(namespace, name string, preconditions *Scale
}
updatedScale, err := s.scaleNamespacer.Scales(namespace).Patch(context.TODO(), gvr, name, types.MergePatchType, patch, patchOptions)
if err != nil {
return "", err
return "", 0, err
}
return updatedScale.ResourceVersion, nil
return updatedScale.ResourceVersion, updatedScale.Spec.Replicas, nil
}
// Scale updates a scale of a given resource to a new size, with optional precondition check (if preconditions is not nil),
// optional retries (if retry is not nil), and then optionally waits for the status to reach desired count.
func (s *genericScaler) Scale(namespace, resourceName string, newSize uint, preconditions *ScalePrecondition, retry, waitForReplicas *RetryParams, gvr schema.GroupVersionResource, dryRun bool) error {
func (s *genericScaler) Scale(namespace, resourceName string, newSize uint, actualSize *int32, preconditions *ScalePrecondition, retry, waitForReplicas *RetryParams, gvr schema.GroupVersionResource, dryRun bool) error {
if retry == nil {
// make it try only once, immediately
retry = &RetryParams{Interval: time.Millisecond, Timeout: time.Millisecond}
}
cond := ScaleCondition(s, preconditions, namespace, resourceName, newSize, nil, gvr, dryRun)
cond := ScaleCondition(s, preconditions, namespace, resourceName, newSize, nil, actualSize, gvr, dryRun)
if err := wait.PollUntilContextTimeout(context.Background(), retry.Interval, retry.Timeout, true, cond); err != nil {
return err
}

View file

@ -69,7 +69,8 @@ func TestReplicationControllerScaleRetry(t *testing.T) {
name := "foo-v1"
namespace := metav1.NamespaceDefault
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, rcgvr, false)
actualSize := new(int32)
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, actualSize, rcgvr, false)
pass, err := scaleFunc(context.Background())
if pass {
t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
@ -78,7 +79,7 @@ func TestReplicationControllerScaleRetry(t *testing.T) {
t.Errorf("Did not expect an error on update conflict failure, got %v", err)
}
preconditions := ScalePrecondition{3, ""}
scaleFunc = ScaleCondition(scaler, &preconditions, namespace, name, count, nil, rcgvr, false)
scaleFunc = ScaleCondition(scaler, &preconditions, namespace, name, count, nil, actualSize, rcgvr, false)
_, err = scaleFunc(context.Background())
if err == nil {
t.Errorf("Expected error on precondition failure")
@ -105,7 +106,7 @@ func TestReplicationControllerScaleInvalid(t *testing.T) {
name := "foo-v1"
namespace := "default"
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, rcgvr, false)
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, nil, rcgvr, false)
pass, err := scaleFunc(context.Background())
if pass {
t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
@ -130,11 +131,15 @@ func TestReplicationControllerScale(t *testing.T) {
scaler := NewScaler(scaleClient)
count := uint(3)
name := "foo-v1"
err := scaler.Scale("default", name, count, nil, nil, nil, rcgvr, false)
actualSize := new(int32)
err := scaler.Scale("default", name, count, actualSize, nil, nil, nil, rcgvr, false)
if err != nil {
t.Fatalf("unexpected error occurred = %v while scaling the resource", err)
}
if *actualSize != 3 {
t.Errorf("expected actualSize to be 3, got %d", *actualSize)
}
actions := scaleClient.Actions()
if len(actions) != len(scaleClientExpectedAction) {
t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
@ -153,7 +158,7 @@ func TestReplicationControllerScaleFailsPreconditions(t *testing.T) {
preconditions := ScalePrecondition{2, ""}
count := uint(3)
name := "foo"
err := scaler.Scale("default", name, count, &preconditions, nil, nil, rcgvr, false)
err := scaler.Scale("default", name, count, nil, &preconditions, nil, nil, rcgvr, false)
if err == nil {
t.Fatal("expected to get an error but none was returned")
}
@ -179,7 +184,7 @@ func TestDeploymentScaleRetry(t *testing.T) {
name := "foo"
namespace := "default"
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, deploygvr, false)
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, nil, deploygvr, false)
pass, err := scaleFunc(context.Background())
if pass != false {
t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
@ -188,7 +193,7 @@ func TestDeploymentScaleRetry(t *testing.T) {
t.Errorf("Did not expect an error on update failure, got %v", err)
}
preconditions := &ScalePrecondition{3, ""}
scaleFunc = ScaleCondition(scaler, preconditions, namespace, name, count, nil, deploygvr, false)
scaleFunc = ScaleCondition(scaler, preconditions, namespace, name, count, nil, nil, deploygvr, false)
_, err = scaleFunc(context.Background())
if err == nil {
t.Error("Expected error on precondition failure")
@ -210,10 +215,14 @@ func TestDeploymentScale(t *testing.T) {
scaler := NewScaler(scaleClient)
count := uint(3)
name := "foo"
err := scaler.Scale("default", name, count, nil, nil, nil, deploygvr, false)
actualSize := new(int32)
err := scaler.Scale("default", name, count, actualSize, nil, nil, nil, deploygvr, false)
if err != nil {
t.Fatal(err)
}
if *actualSize != 3 {
t.Errorf("expected actualSize to be 3, got %d", *actualSize)
}
actions := scaleClient.Actions()
if len(actions) != len(scaleClientExpectedAction) {
t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
@ -236,7 +245,7 @@ func TestDeploymentScaleInvalid(t *testing.T) {
name := "foo"
namespace := "default"
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, deploygvr, false)
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, nil, deploygvr, false)
pass, err := scaleFunc(context.Background())
if pass {
t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
@ -262,7 +271,7 @@ func TestDeploymentScaleFailsPreconditions(t *testing.T) {
preconditions := ScalePrecondition{2, ""}
count := uint(3)
name := "foo"
err := scaler.Scale("default", name, count, &preconditions, nil, nil, deploygvr, false)
err := scaler.Scale("default", name, count, nil, &preconditions, nil, nil, deploygvr, false)
if err == nil {
t.Fatal("exptected to get an error but none was returned")
}
@ -283,10 +292,14 @@ func TestStatefulSetScale(t *testing.T) {
scaler := NewScaler(scaleClient)
count := uint(3)
name := "foo"
err := scaler.Scale("default", name, count, nil, nil, nil, stsgvr, false)
actualSize := new(int32)
err := scaler.Scale("default", name, count, actualSize, nil, nil, nil, stsgvr, false)
if err != nil {
t.Fatal(err)
}
if *actualSize != 3 {
t.Errorf("expected actualSize to be 3, got %d", *actualSize)
}
actions := scaleClient.Actions()
if len(actions) != len(scaleClientExpectedAction) {
t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
@ -309,7 +322,7 @@ func TestStatefulSetScaleRetry(t *testing.T) {
name := "foo"
namespace := "default"
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, stsgvr, false)
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, nil, stsgvr, false)
pass, err := scaleFunc(context.Background())
if pass != false {
t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
@ -318,7 +331,7 @@ func TestStatefulSetScaleRetry(t *testing.T) {
t.Errorf("Did not expect an error on update failure, got %v", err)
}
preconditions := &ScalePrecondition{3, ""}
scaleFunc = ScaleCondition(scaler, preconditions, namespace, name, count, nil, stsgvr, false)
scaleFunc = ScaleCondition(scaler, preconditions, namespace, name, count, nil, nil, stsgvr, false)
_, err = scaleFunc(context.Background())
if err == nil {
t.Error("Expected error on precondition failure")
@ -345,7 +358,7 @@ func TestStatefulSetScaleInvalid(t *testing.T) {
name := "foo"
namespace := "default"
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, stsgvr, false)
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, nil, stsgvr, false)
pass, err := scaleFunc(context.Background())
if pass {
t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
@ -371,7 +384,7 @@ func TestStatefulSetScaleFailsPreconditions(t *testing.T) {
preconditions := ScalePrecondition{2, ""}
count := uint(3)
name := "foo"
err := scaler.Scale("default", name, count, &preconditions, nil, nil, stsgvr, false)
err := scaler.Scale("default", name, count, nil, &preconditions, nil, nil, stsgvr, false)
if err == nil {
t.Fatal("expected to get an error but none was returned")
}
@ -392,10 +405,14 @@ func TestReplicaSetScale(t *testing.T) {
scaler := NewScaler(scaleClient)
count := uint(3)
name := "foo"
err := scaler.Scale("default", name, count, nil, nil, nil, rsgvr, false)
actualSize := new(int32)
err := scaler.Scale("default", name, count, actualSize, nil, nil, nil, rsgvr, false)
if err != nil {
t.Fatal(err)
}
if *actualSize != 3 {
t.Errorf("expected actualSize to be 3, got %d", *actualSize)
}
actions := scaleClient.Actions()
if len(actions) != len(scaleClientExpectedAction) {
t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
@ -418,7 +435,7 @@ func TestReplicaSetScaleRetry(t *testing.T) {
name := "foo"
namespace := "default"
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, rsgvr, false)
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, nil, rsgvr, false)
pass, err := scaleFunc(context.Background())
if pass != false {
t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
@ -427,7 +444,7 @@ func TestReplicaSetScaleRetry(t *testing.T) {
t.Errorf("Did not expect an error on update failure, got %v", err)
}
preconditions := &ScalePrecondition{3, ""}
scaleFunc = ScaleCondition(scaler, preconditions, namespace, name, count, nil, rsgvr, false)
scaleFunc = ScaleCondition(scaler, preconditions, namespace, name, count, nil, nil, rsgvr, false)
_, err = scaleFunc(context.Background())
if err == nil {
t.Error("Expected error on precondition failure")
@ -454,7 +471,7 @@ func TestReplicaSetScaleInvalid(t *testing.T) {
name := "foo"
namespace := "default"
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, rsgvr, false)
scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, nil, rsgvr, false)
pass, err := scaleFunc(context.Background())
if pass {
t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
@ -480,7 +497,7 @@ func TestReplicaSetsGetterFailsPreconditions(t *testing.T) {
preconditions := ScalePrecondition{2, ""}
count := uint(3)
name := "foo"
err := scaler.Scale("default", name, count, &preconditions, nil, nil, rsgvr, false)
err := scaler.Scale("default", name, count, nil, &preconditions, nil, nil, rsgvr, false)
if err == nil {
t.Fatal("expected to get an error but non was returned")
}
@ -576,7 +593,7 @@ func TestGenericScaleSimple(t *testing.T) {
t.Run(fmt.Sprintf("running scenario %d: %s", index+1, scenario.name), func(t *testing.T) {
target := NewScaler(scenario.scaleGetter)
resVersion, err := target.ScaleSimple("default", scenario.resName, scenario.precondition, uint(scenario.newSize), scenario.targetGVR, false)
resVersion, actualSize, err := target.ScaleSimple("default", scenario.resName, scenario.precondition, uint(scenario.newSize), scenario.targetGVR, false)
if scenario.expectError && err == nil {
t.Fatal("expected an error but was not returned")
@ -584,6 +601,9 @@ func TestGenericScaleSimple(t *testing.T) {
if !scenario.expectError && err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !scenario.expectError && actualSize != int32(scenario.newSize) {
t.Errorf("expected actualSize to be %d, got %d", scenario.newSize, actualSize)
}
if resVersion != "" {
t.Fatalf("unexpected resource version returned = %s, wanted = %s", resVersion, "")
}
@ -666,7 +686,8 @@ func TestGenericScale(t *testing.T) {
t.Run(scenario.name, func(t *testing.T) {
target := NewScaler(scenario.scaleGetter)
err := target.Scale("default", scenario.resName, uint(scenario.newSize), scenario.precondition, nil, scenario.waitForReplicas, scenario.targetGVR, false)
actualSize := new(int32)
err := target.Scale("default", scenario.resName, uint(scenario.newSize), actualSize, scenario.precondition, nil, scenario.waitForReplicas, scenario.targetGVR, false)
if scenario.expectError && err == nil {
t.Fatal("expected an error but was not returned")
@ -674,6 +695,9 @@ func TestGenericScale(t *testing.T) {
if !scenario.expectError && err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !scenario.expectError && *actualSize != int32(scenario.newSize) {
t.Errorf("expected actualSize to be %d, got %d", scenario.newSize, *actualSize)
}
})
}

View file

@ -57,6 +57,7 @@ source "${KUBE_ROOT}/test/cmd/request-timeout.sh"
source "${KUBE_ROOT}/test/cmd/results.sh"
source "${KUBE_ROOT}/test/cmd/run.sh"
source "${KUBE_ROOT}/test/cmd/save-config.sh"
source "${KUBE_ROOT}/test/cmd/scale.sh"
source "${KUBE_ROOT}/test/cmd/storage.sh"
source "${KUBE_ROOT}/test/cmd/template-output.sh"
source "${KUBE_ROOT}/test/cmd/version.sh"
@ -1064,5 +1065,11 @@ runTests() {
record_command run_kuberc_tests
###########
# Scale #
###########
record_command run_kubectl_scale_tests
cleanup_tests
}

62
test/cmd/scale.sh Normal file
View file

@ -0,0 +1,62 @@
#!/usr/bin/env bash
# Copyright The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
run_kubectl_scale_tests() {
set -o nounset
set -o errexit
kube::log::status "Testing kubectl scale"
create_and_use_new_namespace
kube::log::status "Testing kubectl scale output for Deployment"
kubectl create deployment test-scale-deploy --image=busybox
output_message=$(kubectl scale deployment test-scale-deploy --replicas=2 --dry-run=client -o yaml)
kube::test::if_has_string "${output_message}" 'replicas: 2'
kube::test::get_object_assert 'deployment test-scale-deploy' '{{.spec.replicas}}' '1'
output_message=$(kubectl scale deployment test-scale-deploy --replicas=3 --dry-run=server -o yaml)
kube::test::if_has_string "${output_message}" 'replicas: 3'
kube::test::get_object_assert 'deployment test-scale-deploy' '{{.spec.replicas}}' '1'
output_message=$(kubectl scale deployment test-scale-deploy --replicas=2 -o yaml)
kube::test::if_has_string "${output_message}" 'replicas: 2'
kube::test::get_object_assert 'deployment test-scale-deploy' '{{.spec.replicas}}' '2'
kubectl delete deployment test-scale-deploy
kube::log::status "Testing kubectl scale output for ReplicaSet"
kubectl create -f hack/testdata/frontend-replicaset.yaml
output_message=$(kubectl scale -f hack/testdata/frontend-replicaset.yaml --replicas=2 -o yaml)
kube::test::if_has_string "${output_message}" 'replicas: 2'
kubectl delete rs frontend
kube::log::status "Testing kubectl scale output for ReplicationController"
kubectl create -f hack/testdata/frontend-controller.yaml
output_message=$(kubectl scale rc frontend --replicas=3 -o yaml)
kube::test::if_has_string "${output_message}" 'replicas: 3'
kubectl delete rc frontend
kube::log::status "Testing kubectl scale output for StatefulSet"
kubectl create -f hack/testdata/rollingupdate-statefulset.yaml
output_message=$(kubectl scale statefulset nginx --replicas=2 -o yaml)
kube::test::if_has_string "${output_message}" 'replicas: 2'
kubectl delete statefulset nginx
set +o nounset
set +o errexit
}

View file

@ -50,7 +50,7 @@ func ScaleResourceWithRetries(scalesGetter scaleclient.ScalesGetter, namespace,
ResourceVersion: "",
}
waitForReplicas := scale.NewRetryParams(waitRetryInterval, waitRetryTimeout)
cond := RetryErrorCondition(scale.ScaleCondition(scaler, preconditions, namespace, name, size, nil, gvr, false))
cond := RetryErrorCondition(scale.ScaleCondition(scaler, preconditions, namespace, name, size, nil, nil, gvr, false))
err := wait.PollUntilContextTimeout(context.Background(), updateRetryInterval, updateRetryTimeout, true, cond)
if err == nil {
err = scale.WaitForScaleHasDesiredReplicas(scalesGetter, gvr.GroupResource(), name, namespace, size, waitForReplicas)