Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add step field in KeptnMetric #1755

Merged
merged 6 commits into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions metrics-operator/api/v1alpha3/keptnmetric_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ type RangeSpec struct {
// Interval specifies the duration of the time interval for the data query
// +kubebuilder:default:="5m"
Interval string `json:"interval,omitempty"`
// Step represents the query resolution step width for the data query
Step string `json:"step,omitempty"`
}

// +kubebuilder:object:root=true
Expand Down
21 changes: 19 additions & 2 deletions metrics-operator/api/v1alpha3/keptnmetric_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,17 @@ func (r *KeptnMetric) ValidateDelete() error {
}

func (s *KeptnMetric) validateKeptnMetric() error {
var allErrs field.ErrorList //defined as a list to allow returning multiple validation errors
var allErrs field.ErrorList // defined as a list to allow returning multiple validation errors
var err *field.Error
if err = s.validateRangeInterval(); err != nil {
allErrs = append(allErrs, err)
}
if err = s.validateRangeStep(); err != nil {
allErrs = append(allErrs, err)
}
if len(allErrs) == 0 {
return nil
}

return apierrors.NewInvalid(
schema.GroupKind{Group: "metrics.keptn.sh", Kind: "KeptnMetric"},
s.Name,
Expand All @@ -93,3 +95,18 @@ func (s *KeptnMetric) validateRangeInterval() *field.Error {
}
return nil
}

func (s *KeptnMetric) validateRangeStep() *field.Error {
if s.Spec.Range == nil || s.Spec.Range.Step == "" {
return nil
}
_, err := time.ParseDuration(s.Spec.Range.Step)
if err != nil {
return field.Invalid(
field.NewPath("spec").Child("range").Child("step"),
s.Spec.Range.Step,
errors.New("Forbidden! The time interval cannot be parsed. Please check for suitable conventions").Error(),
)
}
return nil
}
181 changes: 181 additions & 0 deletions metrics-operator/api/v1alpha3/keptnmetric_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,184 @@ func TestKeptnMetric_validateRangeInterval(t *testing.T) {
})
}
}

func TestKeptnMetric_validateRangeStep(t *testing.T) {

tests := []struct {
name string
verb string
Spec KeptnMetricSpec
want error
oldSpec runtime.Object
}{
{
name: "create-with-wrong-step",
verb: "create",
Spec: KeptnMetricSpec{
Range: &RangeSpec{
Interval: "5m",
Step: "1mins",
},
},
want: apierrors.NewInvalid(
schema.GroupKind{Group: "metrics.keptn.sh", Kind: "KeptnMetric"},
"create-with-wrong-step",
field.ErrorList{
field.Invalid(
field.NewPath("spec").Child("range").Child("step"),
"1mins",
"Forbidden! The time interval cannot be parsed. Please check for suitable conventions",
),
},
),
},
{
name: "create-with-empty-step",
verb: "create",
Spec: KeptnMetricSpec{
Range: &RangeSpec{
Interval: "5m",
Step: "",
},
},
},
{
name: "create-with-right-step",
verb: "create",
Spec: KeptnMetricSpec{
Range: &RangeSpec{
Interval: "5m",
Step: "1m",
},
},
},
{
name: "create-with-wrong-interval-right-step",
verb: "update",
Spec: KeptnMetricSpec{
Range: &RangeSpec{
Interval: "5mins",
Step: "1m",
},
},
want: apierrors.NewInvalid(
schema.GroupKind{Group: "metrics.keptn.sh", Kind: "KeptnMetric"},
"create-with-wrong-interval-right-step",
field.ErrorList{
field.Invalid(
field.NewPath("spec").Child("range").Child("interval"),
"5mins",
"Forbidden! The time interval cannot be parsed. Please check for suitable conventions",
),
},
),
},
{
name: "create-with-wrong-interval-wrong-step",
verb: "update",
Spec: KeptnMetricSpec{
Range: &RangeSpec{
Interval: "5mins",
Step: "1mins",
},
},
want: apierrors.NewInvalid(
schema.GroupKind{Group: "metrics.keptn.sh", Kind: "KeptnMetric"},
"create-with-wrong-interval-wrong-step",
field.ErrorList{
field.Invalid(
field.NewPath("spec").Child("range").Child("interval"),
"5mins",
"Forbidden! The time interval cannot be parsed. Please check for suitable conventions",
),
field.Invalid(
field.NewPath("spec").Child("range").Child("step"),
"1mins",
"Forbidden! The time interval cannot be parsed. Please check for suitable conventions",
),
},
),
},
{
name: "update-with-right-step",
verb: "update",
Spec: KeptnMetricSpec{
Range: &RangeSpec{
Interval: "5m",
Step: "1m",
},
},
oldSpec: &KeptnMetric{
Spec: KeptnMetricSpec{
Range: &RangeSpec{
Interval: "5m",
Step: "1mins",
},
},
},
},
{
name: "update-with-wrong-step",
verb: "update",
Spec: KeptnMetricSpec{
Range: &RangeSpec{
Interval: "5m",
Step: "1mins",
},
},
want: apierrors.NewInvalid(
schema.GroupKind{Group: "metrics.keptn.sh", Kind: "KeptnMetric"},
"update-with-wrong-step",
field.ErrorList{
field.Invalid(
field.NewPath("spec").Child("range").Child("step"),
"1mins",
"Forbidden! The time interval cannot be parsed. Please check for suitable conventions",
),
},
),
oldSpec: &KeptnMetric{
Spec: KeptnMetricSpec{
Range: &RangeSpec{
Interval: "5m",
Step: "1m",
},
},
},
},
{
name: "delete",
verb: "delete",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var s *KeptnMetric
if tt.Spec.Range == nil {
s = &KeptnMetric{
ObjectMeta: metav1.ObjectMeta{Name: tt.name},
Spec: KeptnMetricSpec{Range: tt.Spec.Range},
}
} else {
s = &KeptnMetric{
ObjectMeta: metav1.ObjectMeta{Name: tt.name},
Spec: KeptnMetricSpec{Range: &RangeSpec{Interval: tt.Spec.Range.Interval, Step: tt.Spec.Range.Step}},
}
}
var err error
switch tt.verb {
case "create":
err = s.ValidateCreate()
case "update":
err = s.ValidateUpdate(tt.oldSpec)
case "delete":
err = s.ValidateDelete()
}
if tt.want == nil {
require.Nil(t, err)
} else {
require.Equal(t, tt.want, err)
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ spec:
description: Interval specifies the duration of the time interval
for the data query
type: string
step:
description: Step represents the query resolution step width for
the data query
type: string
type: object
required:
- fetchIntervalSeconds
Expand Down
3 changes: 2 additions & 1 deletion test/integration/metrics/01-teststep-install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ apply:
- goodmetric2.yaml
- goodmetric3.yaml
- goodmetric4.yaml
- goodmetric5.yaml
commands:
- command: kubectl apply -f badmetric.yaml
- command: kubectl apply -f badmetric1.yaml badmetric2.yaml
ignoreFailure: true # we must install ignoring the validating webhook error to proceed with the test
4 changes: 3 additions & 1 deletion test/integration/metrics/02-teststep-assert.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
error: # this checks that kubectl get resource fails, AKA bad CRD not added
- badmetric.yaml
- badmetric1.yaml
- badmetric2.yaml
assert: # this checks that kubectl get resource succeeds
- goodmetric1.yaml
- goodmetric2.yaml
- goodmetric3.yaml
- goodmetric4.yaml
- goodmetric5.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ commands:
- script: ./retrieve-metrics.sh "podtato-head2"
- script: ./retrieve-metrics.sh "podtato-head3"
- script: ./retrieve-metrics.sh "podtato-head4"
- script: ./retrieve-metrics.sh "podtato-head5"
12 changes: 12 additions & 0 deletions test/integration/metrics/badmetric2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: metrics.keptn.sh/v1alpha3
kind: KeptnMetric
metadata:
name: podtato-head1
spec:
provider:
name: "my-provider"
query: "sum(kube_pod_container_resource_limits{resource='cpu'})"
fetchIntervalSeconds: 5
range:
interval: "5m"
step: "1mins"
12 changes: 12 additions & 0 deletions test/integration/metrics/goodmetric5.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: metrics.keptn.sh/v1alpha3
kind: KeptnMetric
metadata:
name: podtato-head5
spec:
provider:
name: "my-provider2"
query: "sum(kube_pod_container_resource_limits{resource='cpu'})"
fetchIntervalSeconds: 5
range:
interval: "5m"
step: "1m"