Skip to content

Commit

Permalink
feat(operator): introduce evaluation support for Dynatrace (#194)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: With API version `v1alpha2`, `KeptnEvaluationProvider` uses a Secret Selector instead of `SecretName`.
  • Loading branch information
thisthat authored Dec 14, 2022
1 parent 66daa18 commit c6483cc
Show file tree
Hide file tree
Showing 14 changed files with 1,233 additions and 111 deletions.
125 changes: 125 additions & 0 deletions operator/api/v1alpha2/keptnevaluationprovider_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
Copyright 2022.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha2

import (
"testing"

"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
)

func TestHasKey(t *testing.T) {
tests := []struct {
name string
provider KeptnEvaluationProvider
result bool
}{
{
name: "Correct Definition",
provider: KeptnEvaluationProvider{
Spec: KeptnEvaluationProviderSpec{
TargetServer: "",
SecretKeyRef: corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "mysecret",
},
Key: "mykey",
},
},
},
result: true,
},
{
name: "Missing key",
provider: KeptnEvaluationProvider{
Spec: KeptnEvaluationProviderSpec{
TargetServer: "",
SecretKeyRef: corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "mysecret",
},
Key: "",
},
},
},
result: false,
},
{
name: "Missing name",
provider: KeptnEvaluationProvider{
Spec: KeptnEvaluationProviderSpec{
TargetServer: "",
SecretKeyRef: corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "",
},
Key: "mykey",
},
},
},
result: false,
},
{
name: "Key made by spaces",
provider: KeptnEvaluationProvider{
Spec: KeptnEvaluationProviderSpec{
TargetServer: "",
SecretKeyRef: corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "mysecret",
},
Key: " ",
},
},
},
result: false,
},
{
name: "Name made by spaces",
provider: KeptnEvaluationProvider{
Spec: KeptnEvaluationProviderSpec{
TargetServer: "",
SecretKeyRef: corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: " ",
},
Key: "mykey",
},
},
},
result: false,
},
{
name: "Empty secret struct",
provider: KeptnEvaluationProvider{
Spec: KeptnEvaluationProviderSpec{
TargetServer: "",
SecretKeyRef: corev1.SecretKeySelector{},
},
},
result: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require.Equal(t, tt.result, tt.provider.HasSecretDefined())
})

}
}
16 changes: 14 additions & 2 deletions operator/api/v1alpha2/keptnevaluationprovider_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ limitations under the License.
package v1alpha2

import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"strings"
)

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// KeptnEvaluationProviderSpec defines the desired state of KeptnEvaluationProvider
type KeptnEvaluationProviderSpec struct {
TargetServer string `json:"targetServer"`
SecretName string `json:"secretName,omitempty"`
TargetServer string `json:"targetServer"`
SecretKeyRef corev1.SecretKeySelector `json:"secretKeyRef,omitempty"`
}

// KeptnEvaluationProviderStatus defines the observed state of KeptnEvaluationProvider
Expand Down Expand Up @@ -61,3 +63,13 @@ type KeptnEvaluationProviderList struct {
func init() {
SchemeBuilder.Register(&KeptnEvaluationProvider{}, &KeptnEvaluationProviderList{})
}

func (p *KeptnEvaluationProvider) HasSecretDefined() bool {
if p.Spec.SecretKeyRef == (corev1.SecretKeySelector{}) {
return false
}
if strings.TrimSpace(p.Spec.SecretKeyRef.Name) == "" || strings.TrimSpace(p.Spec.SecretKeyRef.Key) == "" {
return false
}
return true
}
3 changes: 2 additions & 1 deletion operator/api/v1alpha2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,24 @@ spec:
description: KeptnEvaluationProviderSpec defines the desired state of
KeptnEvaluationProvider
properties:
secretName:
type: string
secretKeyRef:
description: SecretKeySelector selects a key of a Secret.
properties:
key:
description: The key of the secret to select from. Must be a
valid secret key.
type: string
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
optional:
description: Specify whether the Secret or its key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
targetServer:
type: string
required:
Expand Down
6 changes: 6 additions & 0 deletions operator/config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ rules:
- get
- list
- watch
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- apiGroups:
- lifecycle.keptn.sh
resources:
Expand Down
39 changes: 39 additions & 0 deletions operator/controllers/keptnevaluation/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package keptnevaluation

import (
"fmt"
"math"
"strconv"

klcv1alpha2 "github.com/keptn/lifecycle-toolkit/operator/api/v1alpha2"
)

func checkValue(objective klcv1alpha2.Objective, item *klcv1alpha2.EvaluationStatusItem) (bool, error) {

if len(item.Value) == 0 || len(objective.EvaluationTarget) == 0 {
return false, fmt.Errorf("no values")
}

eval := objective.EvaluationTarget[1:]
sign := objective.EvaluationTarget[:1]

resultValue, err := strconv.ParseFloat(item.Value, 64)
if err != nil || math.IsNaN(resultValue) {
return false, err
}

compareValue, err := strconv.ParseFloat(eval, 64)
if err != nil || math.IsNaN(compareValue) {
return false, err
}

// choose comparator
switch sign {
case ">":
return resultValue > compareValue, nil
case "<":
return resultValue < compareValue, nil
default:
return false, fmt.Errorf("invalid operator")
}
}
Loading

0 comments on commit c6483cc

Please sign in to comment.