Skip to content

Commit

Permalink
Prepare release v2.10.1 (#4449)Co-authored-by: Jorge Turrado Ferrero …
Browse files Browse the repository at this point in the history
…<Jorge_turrado@hotmail.es> Co-authored-by: Andy Ward <mortx@toothless.eldarrin.io> Co-authored-by: Tom Kerkhove <kerkhove.tom@gmail.com> Co-authored-by: Zbynek Roubalik <zroubalik@gmail.com> Co-authored-by: Eldarrin <32762846+Eldarrin@users.noreply.github.com> Co-authored-by: Eugene Lugovtsov <34510252+EugeneLugovtsov@users.noreply.github.com> 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 <zroubalik@gmail.com>
Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>

* fix(aws-sqs): Respect `scaleOnInFlight` value (#4358)

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>
Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>

* chore: update supported versions in the welcome message (#4360)

Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>

* fix odd number of arguments passed as key-value pairs for logging (#4369)

Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>
Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>

* fix: Azure Pipelines Scaler uses correct endpoint when demands are set  (#4387) (#4401)

Co-authored-by: Jorge Turrado Ferrero <Jorge_turrado@hotmail.es>
Co-authored-by: Andy Ward <mortx@toothless.eldarrin.io>
Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>

* fix: respect all required demands in azure pipeline scaler (#4405)

Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>

* fix: Allow to remove the finalizer even if the ScaledObject isn't valid (#4397)

Co-authored-by: Tom Kerkhove <kerkhove.tom@gmail.com>
Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>

* update changelog

Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>

---------

Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>
Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>
Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>
Co-authored-by: Zbynek Roubalik <zroubalik@gmail.com>
Co-authored-by: Eldarrin <32762846+Eldarrin@users.noreply.github.com>
Co-authored-by: Andy Ward <mortx@toothless.eldarrin.io>
Co-authored-by: Eugene Lugovtsov <34510252+EugeneLugovtsov@users.noreply.github.com>
Co-authored-by: Tom Kerkhove <kerkhove.tom@gmail.com>
  • Loading branch information
6 people committed Apr 13, 2023
1 parent ee28bf6 commit 8adb70e
Show file tree
Hide file tree
Showing 15 changed files with 869 additions and 68 deletions.
20 changes: 20 additions & 0 deletions .golangci.yml
Expand Up @@ -107,6 +107,26 @@ issues:
- path: mongo_scaler.go
linters:
- dupl
# Exclude gci check for //+kubebuilder:scaffold:imports comments. Waiting to
# resolve https://github.com/kedacore/keda/issues/4379
- path: cmd/operator/main.go
linters:
- gci
- path: cmd/webhooks/main.go
linters:
- gci
- path: controllers/keda/suite_test.go
linters:
- gci
- path: apis/keda/v1alpha1/scaledobject_webhook_test.go
linters:
- gci
# Exclude for azure_pipelines_scaler, reason:
# pkg/scalers/azure_pipelines_scaler.go:408:10: badCond: `countDemands == len(demandsInJob) && countDemands == len(demandsInScaler)` condition is suspicious (gocritic)
- path: azure_pipelines_scaler.go
linters:
- gocritic


linters-settings:
funlen:
Expand Down
3 changes: 2 additions & 1 deletion BUILD.md
Expand Up @@ -287,7 +287,8 @@ Follow these instructions if you want to debug the KEDA webhook using VS Code.
clientConfig:
url: "https://${YOUR_URL}/validate-keda-sh-v1alpha1-scaledobject"
```
**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)
**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)


4. Deploy CRDs and KEDA into `keda` namespace
```bash
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Expand Up @@ -16,6 +16,7 @@ To learn more about active deprecations, we recommend checking [GitHub Discussio
## History

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

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

## v2.10.1

### Fixes

- **Admission Webhooks**: Allow to remove the finalizer even if the ScaledObject isn't valid ([#4396](https://github.com/kedacore/keda/issue/4396))
- **AWS SQS Scaler**: Respect `scaleOnInFlight` value ([#4276](https://github.com/kedacore/keda/issue/4276))
- **Azure Pipelines**: Fix for disallowing `$top` on query when using `meta.parentID` method ([#4397])
- **Azure Pipelines**: Respect all required demands ([#4404](https://github.com/kedacore/keda/issues/4404))

### Other

- **General**: Drop a transitive dependency on bou.ke/monkey ([#4364](https://github.com/kedacore/keda/issues/4364))
- **General**: Fix odd number of arguments passed as key-value pairs for logging ([#4368](https://github.com/kedacore/keda/issues/4368))

## v2.10.0

### New
Expand Down
17 changes: 17 additions & 0 deletions apis/keda/v1alpha1/scaledobject_webhook.go
Expand Up @@ -62,13 +62,30 @@ func (so *ScaledObject) ValidateCreate() error {
func (so *ScaledObject) ValidateUpdate(old runtime.Object) error {
val, _ := json.MarshalIndent(so, "", " ")
scaledobjectlog.V(1).Info(fmt.Sprintf("validating scaledobject update for %s", string(val)))

if isRemovingFinalizer(so, old) {
scaledobjectlog.V(1).Info("finalizer removal, skipping validation")
return nil
}

return validateWorkload(so, "update")
}

func (so *ScaledObject) ValidateDelete() error {
return nil
}

func isRemovingFinalizer(so *ScaledObject, old runtime.Object) bool {
oldSo := old.(*ScaledObject)

soSpec, _ := json.MarshalIndent(so.Spec, "", " ")
oldSoSpec, _ := json.MarshalIndent(oldSo.Spec, "", " ")
soSpecString := string(soSpec)
oldSoSpecString := string(oldSoSpec)

return len(so.ObjectMeta.Finalizers) == 0 && len(oldSo.ObjectMeta.Finalizers) == 1 && soSpecString == oldSoSpecString
}

func validateWorkload(so *ScaledObject, action string) error {
prommetrics.RecordScaledObjectValidatingTotal(so.Namespace, action)
err := verifyCPUMemoryScalers(so, action)
Expand Down
193 changes: 164 additions & 29 deletions apis/keda/v1alpha1/scaledobject_webhook_test.go
Expand Up @@ -154,8 +154,9 @@ var _ = It("should validate the so creation when there isn't any hpa", func() {
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

err = k8sClient.Create(context.Background(), so)
Expect(err).ToNot(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).ShouldNot(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so2)
Expect(err).ToNot(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so2)
}).ShouldNot(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Expect(err).ToNot(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).ShouldNot(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Expect(err).ToNot(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).ShouldNot(HaveOccurred())
})

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

so.Spec.MaxReplicaCount = pointer.Int32(7)
err = k8sClient.Update(context.Background(), so)
Expect(err).ToNot(HaveOccurred())
Eventually(func() error {
return k8sClient.Update(context.Background(), so)
}).ShouldNot(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Expect(err).To(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).Should(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Expect(err).To(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).Should(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Expect(err).To(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).Should(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Expect(err).ToNot(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).ShouldNot(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Expect(err).To(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).Should(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Expect(err).To(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).Should(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Expect(err).ToNot(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).ShouldNot(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Expect(err).To(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).Should(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Expect(err).To(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).Should(HaveOccurred())
})

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

err = k8sClient.Create(context.Background(), so)
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).ShouldNot(HaveOccurred())
})

var _ = It("should validate so creation when all requirements are met for scaling to zero with cpu scaler", func() {
namespaceName := "scale-to-zero-good"
namespace := createNamespace(namespaceName)
workload := createDeployment(namespaceName, true, false)

so := createScaledObjectSTZ(soName, namespaceName, workloadName, 0, 5, true)

err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

err = k8sClient.Create(context.Background(), workload)
Expect(err).ToNot(HaveOccurred())

Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).ShouldNot(HaveOccurred())
})

var _ = It("shouldn't validate so creation with cpu scaler requirements not being met for scaling to 0", func() {
namespaceName := "scale-to-zero-min-replicas-bad"
namespace := createNamespace(namespaceName)
workload := createDeployment(namespaceName, true, false)

so := createScaledObjectSTZ(soName, namespaceName, workloadName, 0, 5, false)

err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())
err = k8sClient.Create(context.Background(), workload)
Expect(err).ToNot(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).Should(HaveOccurred())
})

var _ = It("should validate so creation when min replicas is > 0 with only cpu scaler given", func() {
namespaceName := "scale-to-zero-no-external-trigger-good"
namespace := createNamespace(namespaceName)
workload := createDeployment(namespaceName, true, false)

so := createScaledObjectSTZ(soName, namespaceName, workloadName, 1, 5, false)

err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())
err = k8sClient.Create(context.Background(), workload)
Expect(err).ToNot(HaveOccurred())
Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).ShouldNot(HaveOccurred())

})

var _ = It("should validate the so update if it's removing the finalizer even if it's invalid", func() {

namespaceName := "removing-finalizers"
namespace := createNamespace(namespaceName)
workload := createDeployment(namespaceName, true, true)
so := createScaledObject(soName, namespaceName, workloadName, "apps/v1", "Deployment", true)
so.ObjectMeta.Finalizers = append(so.ObjectMeta.Finalizers, "finalizer")

err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

err = k8sClient.Create(context.Background(), workload)
Expect(err).ToNot(HaveOccurred())

Eventually(func() error {
return k8sClient.Create(context.Background(), so)
}).ShouldNot(HaveOccurred())

workload.Spec.Template.Spec.Containers[0].Resources.Requests = nil
err = k8sClient.Update(context.Background(), workload)
Expect(err).ToNot(HaveOccurred())

so.ObjectMeta.Finalizers = []string{}
Eventually(func() error {
return k8sClient.Update(context.Background(), so)
}).ShouldNot(HaveOccurred())
})

var _ = AfterSuite(func() {
Expand Down Expand Up @@ -595,3 +689,44 @@ func createStatefulSet(namespace string, hasCPU, hasMemory bool) *appsv1.Statefu
},
}
}

func createScaledObjectSTZ(name string, namespace string, targetName string, minReplicas int32, maxReplicas int32, hasExternalTrigger bool) *ScaledObject {
triggers := []ScaleTriggers{
{
Type: "cpu",
Metadata: map[string]string{
"value": "10",
},
},
}
if hasExternalTrigger {
kubeWorkloadTrigger := ScaleTriggers{
Type: "kubernetes-workload",
Metadata: map[string]string{
"podSelector": "pod=workload-test",
"value": "1",
},
}
triggers = append(triggers, kubeWorkloadTrigger)
}
return &ScaledObject{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
UID: types.UID(name),
},
TypeMeta: metav1.TypeMeta{
Kind: "ScaledObject",
APIVersion: "keda.sh",
},
Spec: ScaledObjectSpec{
ScaleTargetRef: &ScaleTarget{
Name: targetName,
},
MinReplicaCount: pointer.Int32(minReplicas),
MaxReplicaCount: pointer.Int32(maxReplicas),
CooldownPeriod: pointer.Int32(1),
Triggers: triggers,
},
}
}

0 comments on commit 8adb70e

Please sign in to comment.