Skip to content

Commit 8adb70e

Browse files
JorTurFerzroubalikEldarrinAndy WardEugeneLugovtsov
authored
Prepare release v2.10.1 (#4449)Co-authored-by: Jorge Turrado Ferrero <[email protected]> Co-authored-by: Andy Ward <[email protected]> Co-authored-by: Tom Kerkhove <[email protected]> Co-authored-by: Zbynek Roubalik <[email protected]> Co-authored-by: Eldarrin <[email protected]> Co-authored-by: Eugene Lugovtsov <[email protected]> fix(aws-sqs): Respect scaleOnInFlight value (#4358) fix odd number of arguments passed as key-value pairs for logging (#4369) fix: Azure Pipelines Scaler uses correct endpoint when demands are set (#4387) (#4401) fix: respect all required demands in azure pipeline scaler (#4405) fix: Allow to remove the finalizer even if the ScaledObject isn't valid (#4397)
* Drop a transitive dependency on bou.ke/monkey (#4366) Signed-off-by: Zbynek Roubalik <[email protected]> Signed-off-by: Jorge Turrado <[email protected]> * fix(aws-sqs): Respect `scaleOnInFlight` value (#4358) Signed-off-by: Jorge Turrado <[email protected]> Signed-off-by: Jorge Turrado <[email protected]> * chore: update supported versions in the welcome message (#4360) Signed-off-by: Jorge Turrado <[email protected]> * fix odd number of arguments passed as key-value pairs for logging (#4369) Signed-off-by: Zbynek Roubalik <[email protected]> Signed-off-by: Jorge Turrado <[email protected]> * fix: Azure Pipelines Scaler uses correct endpoint when demands are set (#4387) (#4401) Co-authored-by: Jorge Turrado Ferrero <[email protected]> Co-authored-by: Andy Ward <[email protected]> Signed-off-by: Jorge Turrado <[email protected]> * fix: respect all required demands in azure pipeline scaler (#4405) Signed-off-by: Jorge Turrado <[email protected]> * fix: Allow to remove the finalizer even if the ScaledObject isn't valid (#4397) Co-authored-by: Tom Kerkhove <[email protected]> Signed-off-by: Jorge Turrado <[email protected]> * update changelog Signed-off-by: Jorge Turrado <[email protected]> --------- Signed-off-by: Zbynek Roubalik <[email protected]> Signed-off-by: Jorge Turrado <[email protected]> Signed-off-by: Jorge Turrado <[email protected]> Co-authored-by: Zbynek Roubalik <[email protected]> Co-authored-by: Eldarrin <[email protected]> Co-authored-by: Andy Ward <[email protected]> Co-authored-by: Eugene Lugovtsov <[email protected]> Co-authored-by: Tom Kerkhove <[email protected]>
1 parent ee28bf6 commit 8adb70e

15 files changed

+869
-68
lines changed

.golangci.yml

+20
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ issues:
107107
- path: mongo_scaler.go
108108
linters:
109109
- dupl
110+
# Exclude gci check for //+kubebuilder:scaffold:imports comments. Waiting to
111+
# resolve https://github.com/kedacore/keda/issues/4379
112+
- path: cmd/operator/main.go
113+
linters:
114+
- gci
115+
- path: cmd/webhooks/main.go
116+
linters:
117+
- gci
118+
- path: controllers/keda/suite_test.go
119+
linters:
120+
- gci
121+
- path: apis/keda/v1alpha1/scaledobject_webhook_test.go
122+
linters:
123+
- gci
124+
# Exclude for azure_pipelines_scaler, reason:
125+
# pkg/scalers/azure_pipelines_scaler.go:408:10: badCond: `countDemands == len(demandsInJob) && countDemands == len(demandsInScaler)` condition is suspicious (gocritic)
126+
- path: azure_pipelines_scaler.go
127+
linters:
128+
- gocritic
129+
110130

111131
linters-settings:
112132
funlen:

BUILD.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,8 @@ Follow these instructions if you want to debug the KEDA webhook using VS Code.
287287
clientConfig:
288288
url: "https://${YOUR_URL}/validate-keda-sh-v1alpha1-scaledobject"
289289
```
290-
**Note:** You could need to define also the key `caBundle` with the CA bundle encoded in base64 if the cluster can get it during the manifest apply (this happens with localtunnel for instance)
290+
**Note:** You need to define also the key `caBundle` with the CA bundle encoded in base64. This `caBundle` is the pem file from the CA used to sign the certificate. Remember to disable the `caBundle` inyection to avoid unintended rewrites of your `caBundle` (by KEDA operator or by any other 3rd party)
291+
291292

292293
4. Deploy CRDs and KEDA into `keda` namespace
293294
```bash

CHANGELOG.md

+15
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ To learn more about active deprecations, we recommend checking [GitHub Discussio
1616
## History
1717

1818
- [Unreleased](#unreleased)
19+
- [v2.10.1](#v2101)
1920
- [v2.10.0](#v2100)
2021
- [v2.9.3](#v293)
2122
- [v2.9.2](#v292)
@@ -67,6 +68,20 @@ To learn more about active deprecations, we recommend checking [GitHub Discussio
6768

6869
- TODO ([#XXX](https://github.com/kedacore/keda/issue/XXX))
6970

71+
## v2.10.1
72+
73+
### Fixes
74+
75+
- **Admission Webhooks**: Allow to remove the finalizer even if the ScaledObject isn't valid ([#4396](https://github.com/kedacore/keda/issue/4396))
76+
- **AWS SQS Scaler**: Respect `scaleOnInFlight` value ([#4276](https://github.com/kedacore/keda/issue/4276))
77+
- **Azure Pipelines**: Fix for disallowing `$top` on query when using `meta.parentID` method ([#4397])
78+
- **Azure Pipelines**: Respect all required demands ([#4404](https://github.com/kedacore/keda/issues/4404))
79+
80+
### Other
81+
82+
- **General**: Drop a transitive dependency on bou.ke/monkey ([#4364](https://github.com/kedacore/keda/issues/4364))
83+
- **General**: Fix odd number of arguments passed as key-value pairs for logging ([#4368](https://github.com/kedacore/keda/issues/4368))
84+
7085
## v2.10.0
7186

7287
### New

apis/keda/v1alpha1/scaledobject_webhook.go

+17
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,30 @@ func (so *ScaledObject) ValidateCreate() error {
6262
func (so *ScaledObject) ValidateUpdate(old runtime.Object) error {
6363
val, _ := json.MarshalIndent(so, "", " ")
6464
scaledobjectlog.V(1).Info(fmt.Sprintf("validating scaledobject update for %s", string(val)))
65+
66+
if isRemovingFinalizer(so, old) {
67+
scaledobjectlog.V(1).Info("finalizer removal, skipping validation")
68+
return nil
69+
}
70+
6571
return validateWorkload(so, "update")
6672
}
6773

6874
func (so *ScaledObject) ValidateDelete() error {
6975
return nil
7076
}
7177

78+
func isRemovingFinalizer(so *ScaledObject, old runtime.Object) bool {
79+
oldSo := old.(*ScaledObject)
80+
81+
soSpec, _ := json.MarshalIndent(so.Spec, "", " ")
82+
oldSoSpec, _ := json.MarshalIndent(oldSo.Spec, "", " ")
83+
soSpecString := string(soSpec)
84+
oldSoSpecString := string(oldSoSpec)
85+
86+
return len(so.ObjectMeta.Finalizers) == 0 && len(oldSo.ObjectMeta.Finalizers) == 1 && soSpecString == oldSoSpecString
87+
}
88+
7289
func validateWorkload(so *ScaledObject, action string) error {
7390
prommetrics.RecordScaledObjectValidatingTotal(so.Namespace, action)
7491
err := verifyCPUMemoryScalers(so, action)

apis/keda/v1alpha1/scaledobject_webhook_test.go

+164-29
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,9 @@ var _ = It("should validate the so creation when there isn't any hpa", func() {
154154
err := k8sClient.Create(context.Background(), namespace)
155155
Expect(err).ToNot(HaveOccurred())
156156

157-
err = k8sClient.Create(context.Background(), so)
158-
Expect(err).ToNot(HaveOccurred())
157+
Eventually(func() error {
158+
return k8sClient.Create(context.Background(), so)
159+
}).ShouldNot(HaveOccurred())
159160
})
160161

161162
var _ = It("should validate the so creation when there are other SO for other workloads", func() {
@@ -171,8 +172,9 @@ var _ = It("should validate the so creation when there are other SO for other wo
171172
err = k8sClient.Create(context.Background(), so1)
172173
Expect(err).ToNot(HaveOccurred())
173174

174-
err = k8sClient.Create(context.Background(), so2)
175-
Expect(err).ToNot(HaveOccurred())
175+
Eventually(func() error {
176+
return k8sClient.Create(context.Background(), so2)
177+
}).ShouldNot(HaveOccurred())
176178
})
177179

178180
var _ = It("should validate the so creation when there are other HPA for other workloads", func() {
@@ -188,8 +190,9 @@ var _ = It("should validate the so creation when there are other HPA for other w
188190
err = k8sClient.Create(context.Background(), hpa)
189191
Expect(err).ToNot(HaveOccurred())
190192

191-
err = k8sClient.Create(context.Background(), so)
192-
Expect(err).ToNot(HaveOccurred())
193+
Eventually(func() error {
194+
return k8sClient.Create(context.Background(), so)
195+
}).ShouldNot(HaveOccurred())
193196
})
194197

195198
var _ = It("should validate the so creation when it's own hpa is already generated", func() {
@@ -206,8 +209,9 @@ var _ = It("should validate the so creation when it's own hpa is already generat
206209
err = k8sClient.Create(context.Background(), hpa)
207210
Expect(err).ToNot(HaveOccurred())
208211

209-
err = k8sClient.Create(context.Background(), so)
210-
Expect(err).ToNot(HaveOccurred())
212+
Eventually(func() error {
213+
return k8sClient.Create(context.Background(), so)
214+
}).ShouldNot(HaveOccurred())
211215
})
212216

213217
var _ = It("should validate the so update when it's own hpa is already generated", func() {
@@ -228,8 +232,9 @@ var _ = It("should validate the so update when it's own hpa is already generated
228232
Expect(err).ToNot(HaveOccurred())
229233

230234
so.Spec.MaxReplicaCount = pointer.Int32(7)
231-
err = k8sClient.Update(context.Background(), so)
232-
Expect(err).ToNot(HaveOccurred())
235+
Eventually(func() error {
236+
return k8sClient.Update(context.Background(), so)
237+
}).ShouldNot(HaveOccurred())
233238
})
234239

235240
var _ = It("shouldn't validate the so creation when there is another unmanaged hpa", func() {
@@ -246,8 +251,9 @@ var _ = It("shouldn't validate the so creation when there is another unmanaged h
246251
err = k8sClient.Create(context.Background(), hpa)
247252
Expect(err).ToNot(HaveOccurred())
248253

249-
err = k8sClient.Create(context.Background(), so)
250-
Expect(err).To(HaveOccurred())
254+
Eventually(func() error {
255+
return k8sClient.Create(context.Background(), so)
256+
}).Should(HaveOccurred())
251257
})
252258

253259
var _ = It("shouldn't validate the so creation when there is another so", func() {
@@ -264,8 +270,9 @@ var _ = It("shouldn't validate the so creation when there is another so", func()
264270
err = k8sClient.Create(context.Background(), so2)
265271
Expect(err).ToNot(HaveOccurred())
266272

267-
err = k8sClient.Create(context.Background(), so)
268-
Expect(err).To(HaveOccurred())
273+
Eventually(func() error {
274+
return k8sClient.Create(context.Background(), so)
275+
}).Should(HaveOccurred())
269276
})
270277

271278
var _ = It("shouldn't validate the so creation when there is another hpa with custom apis", func() {
@@ -282,8 +289,9 @@ var _ = It("shouldn't validate the so creation when there is another hpa with cu
282289
err = k8sClient.Create(context.Background(), hpa)
283290
Expect(err).ToNot(HaveOccurred())
284291

285-
err = k8sClient.Create(context.Background(), so)
286-
Expect(err).To(HaveOccurred())
292+
Eventually(func() error {
293+
return k8sClient.Create(context.Background(), so)
294+
}).Should(HaveOccurred())
287295
})
288296

289297
var _ = It("should validate the so creation with cpu and memory when deployment has requests", func() {
@@ -299,8 +307,9 @@ var _ = It("should validate the so creation with cpu and memory when deployment
299307
err = k8sClient.Create(context.Background(), workload)
300308
Expect(err).ToNot(HaveOccurred())
301309

302-
err = k8sClient.Create(context.Background(), so)
303-
Expect(err).ToNot(HaveOccurred())
310+
Eventually(func() error {
311+
return k8sClient.Create(context.Background(), so)
312+
}).ShouldNot(HaveOccurred())
304313
})
305314

306315
var _ = It("shouldn't validate the so creation with cpu and memory when deployment hasn't got memory request", func() {
@@ -316,8 +325,9 @@ var _ = It("shouldn't validate the so creation with cpu and memory when deployme
316325
err = k8sClient.Create(context.Background(), workload)
317326
Expect(err).ToNot(HaveOccurred())
318327

319-
err = k8sClient.Create(context.Background(), so)
320-
Expect(err).To(HaveOccurred())
328+
Eventually(func() error {
329+
return k8sClient.Create(context.Background(), so)
330+
}).Should(HaveOccurred())
321331
})
322332

323333
var _ = It("shouldn't validate the so creation with cpu and memory when deployment hasn't got cpu request", func() {
@@ -333,8 +343,9 @@ var _ = It("shouldn't validate the so creation with cpu and memory when deployme
333343
err = k8sClient.Create(context.Background(), workload)
334344
Expect(err).ToNot(HaveOccurred())
335345

336-
err = k8sClient.Create(context.Background(), so)
337-
Expect(err).To(HaveOccurred())
346+
Eventually(func() error {
347+
return k8sClient.Create(context.Background(), so)
348+
}).Should(HaveOccurred())
338349
})
339350

340351
var _ = It("should validate the so creation with cpu and memory when statefulset has requests", func() {
@@ -350,8 +361,9 @@ var _ = It("should validate the so creation with cpu and memory when statefulset
350361
err = k8sClient.Create(context.Background(), workload)
351362
Expect(err).ToNot(HaveOccurred())
352363

353-
err = k8sClient.Create(context.Background(), so)
354-
Expect(err).ToNot(HaveOccurred())
364+
Eventually(func() error {
365+
return k8sClient.Create(context.Background(), so)
366+
}).ShouldNot(HaveOccurred())
355367
})
356368

357369
var _ = It("shouldn't validate the so creation with cpu and memory when statefulset hasn't got memory request", func() {
@@ -367,8 +379,9 @@ var _ = It("shouldn't validate the so creation with cpu and memory when stateful
367379
err = k8sClient.Create(context.Background(), workload)
368380
Expect(err).ToNot(HaveOccurred())
369381

370-
err = k8sClient.Create(context.Background(), so)
371-
Expect(err).To(HaveOccurred())
382+
Eventually(func() error {
383+
return k8sClient.Create(context.Background(), so)
384+
}).Should(HaveOccurred())
372385
})
373386

374387
var _ = It("shouldn't validate the so creation with cpu and memory when statefulset hasn't got cpu request", func() {
@@ -384,8 +397,9 @@ var _ = It("shouldn't validate the so creation with cpu and memory when stateful
384397
err = k8sClient.Create(context.Background(), workload)
385398
Expect(err).ToNot(HaveOccurred())
386399

387-
err = k8sClient.Create(context.Background(), so)
388-
Expect(err).To(HaveOccurred())
400+
Eventually(func() error {
401+
return k8sClient.Create(context.Background(), so)
402+
}).Should(HaveOccurred())
389403
})
390404

391405
var _ = It("should validate the so creation without cpu and memory when custom resources", func() {
@@ -397,8 +411,88 @@ var _ = It("should validate the so creation without cpu and memory when custom r
397411
err := k8sClient.Create(context.Background(), namespace)
398412
Expect(err).ToNot(HaveOccurred())
399413

400-
err = k8sClient.Create(context.Background(), so)
414+
Eventually(func() error {
415+
return k8sClient.Create(context.Background(), so)
416+
}).ShouldNot(HaveOccurred())
417+
})
418+
419+
var _ = It("should validate so creation when all requirements are met for scaling to zero with cpu scaler", func() {
420+
namespaceName := "scale-to-zero-good"
421+
namespace := createNamespace(namespaceName)
422+
workload := createDeployment(namespaceName, true, false)
423+
424+
so := createScaledObjectSTZ(soName, namespaceName, workloadName, 0, 5, true)
425+
426+
err := k8sClient.Create(context.Background(), namespace)
427+
Expect(err).ToNot(HaveOccurred())
428+
429+
err = k8sClient.Create(context.Background(), workload)
430+
Expect(err).ToNot(HaveOccurred())
431+
432+
Eventually(func() error {
433+
return k8sClient.Create(context.Background(), so)
434+
}).ShouldNot(HaveOccurred())
435+
})
436+
437+
var _ = It("shouldn't validate so creation with cpu scaler requirements not being met for scaling to 0", func() {
438+
namespaceName := "scale-to-zero-min-replicas-bad"
439+
namespace := createNamespace(namespaceName)
440+
workload := createDeployment(namespaceName, true, false)
441+
442+
so := createScaledObjectSTZ(soName, namespaceName, workloadName, 0, 5, false)
443+
444+
err := k8sClient.Create(context.Background(), namespace)
445+
Expect(err).ToNot(HaveOccurred())
446+
err = k8sClient.Create(context.Background(), workload)
447+
Expect(err).ToNot(HaveOccurred())
448+
Eventually(func() error {
449+
return k8sClient.Create(context.Background(), so)
450+
}).Should(HaveOccurred())
451+
})
452+
453+
var _ = It("should validate so creation when min replicas is > 0 with only cpu scaler given", func() {
454+
namespaceName := "scale-to-zero-no-external-trigger-good"
455+
namespace := createNamespace(namespaceName)
456+
workload := createDeployment(namespaceName, true, false)
457+
458+
so := createScaledObjectSTZ(soName, namespaceName, workloadName, 1, 5, false)
459+
460+
err := k8sClient.Create(context.Background(), namespace)
461+
Expect(err).ToNot(HaveOccurred())
462+
err = k8sClient.Create(context.Background(), workload)
463+
Expect(err).ToNot(HaveOccurred())
464+
Eventually(func() error {
465+
return k8sClient.Create(context.Background(), so)
466+
}).ShouldNot(HaveOccurred())
467+
468+
})
469+
470+
var _ = It("should validate the so update if it's removing the finalizer even if it's invalid", func() {
471+
472+
namespaceName := "removing-finalizers"
473+
namespace := createNamespace(namespaceName)
474+
workload := createDeployment(namespaceName, true, true)
475+
so := createScaledObject(soName, namespaceName, workloadName, "apps/v1", "Deployment", true)
476+
so.ObjectMeta.Finalizers = append(so.ObjectMeta.Finalizers, "finalizer")
477+
478+
err := k8sClient.Create(context.Background(), namespace)
401479
Expect(err).ToNot(HaveOccurred())
480+
481+
err = k8sClient.Create(context.Background(), workload)
482+
Expect(err).ToNot(HaveOccurred())
483+
484+
Eventually(func() error {
485+
return k8sClient.Create(context.Background(), so)
486+
}).ShouldNot(HaveOccurred())
487+
488+
workload.Spec.Template.Spec.Containers[0].Resources.Requests = nil
489+
err = k8sClient.Update(context.Background(), workload)
490+
Expect(err).ToNot(HaveOccurred())
491+
492+
so.ObjectMeta.Finalizers = []string{}
493+
Eventually(func() error {
494+
return k8sClient.Update(context.Background(), so)
495+
}).ShouldNot(HaveOccurred())
402496
})
403497

404498
var _ = AfterSuite(func() {
@@ -595,3 +689,44 @@ func createStatefulSet(namespace string, hasCPU, hasMemory bool) *appsv1.Statefu
595689
},
596690
}
597691
}
692+
693+
func createScaledObjectSTZ(name string, namespace string, targetName string, minReplicas int32, maxReplicas int32, hasExternalTrigger bool) *ScaledObject {
694+
triggers := []ScaleTriggers{
695+
{
696+
Type: "cpu",
697+
Metadata: map[string]string{
698+
"value": "10",
699+
},
700+
},
701+
}
702+
if hasExternalTrigger {
703+
kubeWorkloadTrigger := ScaleTriggers{
704+
Type: "kubernetes-workload",
705+
Metadata: map[string]string{
706+
"podSelector": "pod=workload-test",
707+
"value": "1",
708+
},
709+
}
710+
triggers = append(triggers, kubeWorkloadTrigger)
711+
}
712+
return &ScaledObject{
713+
ObjectMeta: metav1.ObjectMeta{
714+
Name: name,
715+
Namespace: namespace,
716+
UID: types.UID(name),
717+
},
718+
TypeMeta: metav1.TypeMeta{
719+
Kind: "ScaledObject",
720+
APIVersion: "keda.sh",
721+
},
722+
Spec: ScaledObjectSpec{
723+
ScaleTargetRef: &ScaleTarget{
724+
Name: targetName,
725+
},
726+
MinReplicaCount: pointer.Int32(minReplicas),
727+
MaxReplicaCount: pointer.Int32(maxReplicas),
728+
CooldownPeriod: pointer.Int32(1),
729+
Triggers: triggers,
730+
},
731+
}
732+
}

0 commit comments

Comments
 (0)