Skip to content

Commit

Permalink
chore: stop scale loop for pause Scaledbject kedacore#4253
Browse files Browse the repository at this point in the history
Signed-off-by: Tobo Atchou <tobo.atchou@gmail.com>
  • Loading branch information
tobotg committed May 17, 2023
1 parent 4030749 commit a8f8641
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ New deprecation(s):
- **General**: Fix odd number of arguments passed as key-value pairs for logging ([#4368](https://github.com/kedacore/keda/issues/4368))
- **General**: Stop logging errors for paused ScaledObject (with "autoscaling.keda.sh/paused-replicas" annotation) by skipping reconciliation loop for the object (stop the scale loop and delete the HPA) ([#4253](https://github.com/kedacore/keda/pull/4253))
- **General**: Automatically scale test clusters in/out to reduce environmental footprint & improve cost-efficiency ([#4456](https://github.com/kedacore/keda/pull/4456))
- **General**: Stop logging errors for paused ScaledObject (with "autoscaling.keda.sh/paused-replicas" annotation) by skipping reconciliation loop for the object (stop the scale loop and delete the HPA) ([#4253](https://github.com/kedacore/keda/pull/4253))

## v2.10.0

Expand Down
95 changes: 95 additions & 0 deletions controllers/keda/scaledobject_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
clientcache "k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/log/zap"

kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1"
Expand Down Expand Up @@ -904,6 +905,100 @@ var _ = Describe("ScaledObjectController", func() {
return k8sClient.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("keda-hpa-%s", soName), Namespace: "default"}, hpa)
}).Should(HaveOccurred())
})

// Fix issue 4253
It("stops scale loop and delete existing hpa when scaledobject is updated to have pause annotation", func() {
// Create the scaling target.
deploymentName := "to-be-paused-name"
soName := "so-" + deploymentName
err := k8sClient.Create(context.Background(), generateDeployment(deploymentName))
Expect(err).ToNot(HaveOccurred())

// Create the ScaledObject without specifying name.
so := &kedav1alpha1.ScaledObject{
ObjectMeta: metav1.ObjectMeta{Name: soName, Namespace: "default"},
Spec: kedav1alpha1.ScaledObjectSpec{
ScaleTargetRef: &kedav1alpha1.ScaleTarget{
Name: deploymentName,
},
Advanced: &kedav1alpha1.AdvancedConfig{
HorizontalPodAutoscalerConfig: &kedav1alpha1.HorizontalPodAutoscalerConfig{},
},
Triggers: []kedav1alpha1.ScaleTriggers{
{
Type: "cron",
Metadata: map[string]string{
"timezone": "UTC",
"start": "0 * * * *",
"end": "1 * * * *",
"desiredReplicas": "1",
},
},
},
},
}
err = k8sClient.Create(context.Background(), so)
Expect(err).ToNot(HaveOccurred())

// Get and confirm the HPA.
hpa := &autoscalingv2.HorizontalPodAutoscaler{}
Eventually(func() error {
return k8sClient.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("keda-hpa-%s", soName), Namespace: "default"}, hpa)
}).ShouldNot(HaveOccurred())
Expect(hpa.Name).To(Equal(fmt.Sprintf("keda-hpa-%s", soName)))

// Pause scaledObject (add annotation)
Eventually(func() error {
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: soName, Namespace: "default"}, so)
Expect(err).ToNot(HaveOccurred())
so.Annotations[kedacontrollerutil.PausedReplicasAnnotation] = "0"
return k8sClient.Update(context.Background(), so)
}).ShouldNot(HaveOccurred())

// wait so's ready condition Ready
Eventually(func() metav1.ConditionStatus {
err := k8sClient.Get(context.Background(), types.NamespacedName{Name: soName, Namespace: "default"}, so)
if err != nil {
return metav1.ConditionUnknown
}
return so.Status.Conditions.GetReadyCondition().Status
}).Should(Equal(metav1.ConditionTrue))

// And validate that old hpa is deleted.
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("keda-hpa-%s", soName), Namespace: "default"}, hpa)
Expect(err).Should(HaveOccurred())
Expect(errors.IsNotFound(err)).To(Equal(true))

//
key, err := clientcache.MetaNamespaceKeyFunc(so)
Expect(err).Should(HaveOccurred())
Expect(key).To(Equal(nil))

// Resume scaledObject (remove annotation)
Eventually(func() error {
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: soName, Namespace: "default"}, so)
Expect(err).ToNot(HaveOccurred())
delete(so.Annotations, kedacontrollerutil.PausedReplicasAnnotation)
return k8sClient.Update(context.Background(), so)
}).ShouldNot(HaveOccurred())

// wait so's ready condition Ready
Eventually(func() metav1.ConditionStatus {
err := k8sClient.Get(context.Background(), types.NamespacedName{Name: soName, Namespace: "default"}, so)
if err != nil {
return metav1.ConditionUnknown
}
return so.Status.Conditions.GetReadyCondition().Status
}).Should(Equal(metav1.ConditionTrue))

// And validate that hpa is created.
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("keda-hpa-%s", soName), Namespace: "default"}, hpa)
Expect(err).ShouldNot(HaveOccurred())

//
_, err = clientcache.MetaNamespaceKeyFunc(so)
Expect(err).ShouldNot(HaveOccurred())
})
})

func generateDeployment(name string) *appsv1.Deployment {
Expand Down

0 comments on commit a8f8641

Please sign in to comment.