Skip to content

Commit

Permalink
fix(scaledobject): reconcile hpa on label or annotations change
Browse files Browse the repository at this point in the history
Signed-off-by: Grégory SANCHEZ <gregory.sanchez@icloud.com>
  • Loading branch information
chubchubsancho committed Feb 5, 2024
1 parent 6d326c8 commit 9c3703e
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Here is an overview of all new **experimental** features:

### Fixes

- **General**: Fix reconcile HPA when ScaledObject annotations or labels is updated ([#5468](https://github.com/kedacore/keda/issues/5468))
- **Prometheus Scaler**: Fix for missing AWS region from metadata ([#5419](https://github.com/kedacore/keda/issues/5419))

### Deprecations
Expand Down
2 changes: 2 additions & 0 deletions controllers/keda/scaledobject_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ func (r *ScaledObjectReconciler) SetupWithManager(mgr ctrl.Manager, options cont
kedacontrollerutil.PausedReplicasPredicate{},
kedacontrollerutil.ScaleObjectReadyConditionPredicate{},
predicate.GenerationChangedPredicate{},
predicate.LabelChangedPredicate{},
predicate.AnnotationChangedPredicate{},
),
)).
// Trigger a reconcile only when the HPA spec,label or annotation changes.
Expand Down
134 changes: 134 additions & 0 deletions controllers/keda/scaledobject_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1396,6 +1396,140 @@ var _ = Describe("ScaledObjectController", func() {
}).Should(BeNil())
})

// Fix issue 5468
It("reconciles hpa when scaledobject annotation is changed", func() {
var (
deploymentName = "scaledobject-annotation-change"
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",
Annotations: map[string]string{
"annotation-email": "email@example.com",
"annotation-url": "https://example.com",
},
},
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())

// And validate that hpa is created.
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())

// Add a new annotation to the so and update
so.ObjectMeta.Annotations = map[string]string{"new-annotation": "new-annotation-value"}
err = k8sClient.Update(context.Background(), so)
Expect(err).ToNot(HaveOccurred())

// hpa should be reconciled and should contain this new annotation
Eventually(func() bool {
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("keda-hpa-%s", soName), Namespace: "default"}, hpa)
if err != nil {
return false
}
// Check if the annotation is present
if _, ok := hpa.ObjectMeta.Annotations["new-annotation"]; ok {
return true
}
return false
}, 5*time.Second).Should(BeTrue())
})

It("reconciles hpa when scaledobject labels is changed", func() {
var (
deploymentName = "scaledobject-label-change"
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",
Labels: map[string]string{
"awesome-label": "my-label",
},
},
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())

// And validate that hpa is created.
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())

// Add a new label to the so and update
so.ObjectMeta.Labels = map[string]string{"new-label": "new-label-value"}
err = k8sClient.Update(context.Background(), so)
Expect(err).ToNot(HaveOccurred())

// hpa should be reconciled and should contain this new label
Eventually(func() bool {
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("keda-hpa-%s", soName), Namespace: "default"}, hpa)
if err != nil {
return false
}
// Check if the label is present
if _, ok := hpa.ObjectMeta.Labels["new-label"]; ok {
return true
}
return false
}, 5*time.Second).Should(BeTrue())
})

})

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

0 comments on commit 9c3703e

Please sign in to comment.