diff --git a/CHANGELOG.md b/CHANGELOG.md index b5d7486c5ea..8204edcbe3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -208,6 +208,7 @@ Here is an overview of all new **experimental** features: ### Fixes +- **General**: Allow ScaledObject.MinReplicaCount to be set to 0 ([#5570](https://github.com/kedacore/keda/issues/5570)) - **General**: Fix CVE-2024-28180 in github.com/go-jose/go-jose/v3 ([#5617](https://github.com/kedacore/keda/pull/5617)) - **General**: Fix fallback logic in formula-based evaluation ([#5666](https://github.com/kedacore/keda/issues/5666)) - **General**: Fix wrong scaler active value and paused value that are pushed to OpenTelemetry ([#5705](https://github.com/kedacore/keda/issues/5705)) diff --git a/apis/keda/v1alpha1/scaledobject_types.go b/apis/keda/v1alpha1/scaledobject_types.go index f73de8e0a69..78b3d125253 100644 --- a/apis/keda/v1alpha1/scaledobject_types.go +++ b/apis/keda/v1alpha1/scaledobject_types.go @@ -78,8 +78,8 @@ const ( // Composite metric name used for scalingModifiers composite metric CompositeMetricName string = "composite-metric" - defaultHPAMinReplicas int32 = 1 - defaultHPAMaxReplicas int32 = 100 + defaultMinReplicas int32 = 0 + defaultMaxReplicas int32 = 100 ) // ScaledObjectSpec is the spec for a ScaledObject resource @@ -233,31 +233,27 @@ func (so *ScaledObject) IsUsingModifiers() bool { return so.Spec.Advanced != nil && !reflect.DeepEqual(so.Spec.Advanced.ScalingModifiers, ScalingModifiers{}) } -// getHPAMinReplicas returns MinReplicas based on definition in ScaledObject or default value if not defined -func (so *ScaledObject) GetHPAMinReplicas() *int32 { - if so.Spec.MinReplicaCount != nil && *so.Spec.MinReplicaCount > 0 { - return so.Spec.MinReplicaCount +// MinReplicaCount returns MinReplicaCount based on definition in ScaledObject or default value if not defined +func (so *ScaledObject) MinReplicaCount() int32 { + if so.Spec.MinReplicaCount != nil { + return *so.Spec.MinReplicaCount } - tmp := defaultHPAMinReplicas - return &tmp + return defaultMinReplicas } -// getHPAMaxReplicas returns MaxReplicas based on definition in ScaledObject or default value if not defined -func (so *ScaledObject) GetHPAMaxReplicas() int32 { +// MaxReplicaCount returns MaxReplicaCount based on definition in ScaledObject or default value if not defined +func (so *ScaledObject) MaxReplicaCount() int32 { if so.Spec.MaxReplicaCount != nil { return *so.Spec.MaxReplicaCount } - return defaultHPAMaxReplicas + return defaultMaxReplicas } // checkReplicaCountBoundsAreValid checks that Idle/Min/Max ReplicaCount defined in ScaledObject are correctly specified // i.e. that Min is not greater than Max or Idle greater or equal to Min func CheckReplicaCountBoundsAreValid(scaledObject *ScaledObject) error { - min := int32(0) - if scaledObject.Spec.MinReplicaCount != nil { - min = *scaledObject.GetHPAMinReplicas() - } - max := scaledObject.GetHPAMaxReplicas() + min := scaledObject.MinReplicaCount() + max := scaledObject.MaxReplicaCount() if min > max { return fmt.Errorf("MinReplicaCount=%d must be less than MaxReplicaCount=%d", min, max) diff --git a/controllers/keda/hpa.go b/controllers/keda/hpa.go index 5fb2c835eb7..cad0752790d 100644 --- a/controllers/keda/hpa.go +++ b/controllers/keda/hpa.go @@ -99,25 +99,24 @@ func (r *ScaledObjectReconciler) newHPAForScaledObject(ctx context.Context, logg labels[key] = value } - minReplicas := scaledObject.GetHPAMinReplicas() - maxReplicas := scaledObject.GetHPAMaxReplicas() + // minReplicas on HPA must be > 0 without HPAScaleToZero feature. + minReplicas := max(scaledObject.MinReplicaCount(), 1) + maxReplicas := scaledObject.MaxReplicaCount() pausedCount, err := executor.GetPausedReplicaCount(scaledObject) if err != nil { return nil, err } if pausedCount != nil { - // MinReplicas on HPA can't be 0 - if *pausedCount == 0 { - *pausedCount = 1 - } - minReplicas = pausedCount - maxReplicas = *pausedCount + // minReplicas on HPA must be > 0 without HPAScaleToZero feature. + replicas := max(*pausedCount, 1) + minReplicas = replicas + maxReplicas = replicas } hpa := &autoscalingv2.HorizontalPodAutoscaler{ Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ - MinReplicas: minReplicas, + MinReplicas: &minReplicas, MaxReplicas: maxReplicas, Metrics: scaledObjectMetricSpecs, Behavior: behavior,