From e61b9f81b550e688ddd34dede51b83ed69cbf6cd Mon Sep 17 00:00:00 2001 From: Rakshit Gondwal Date: Thu, 20 Jul 2023 16:47:22 +0530 Subject: [PATCH] feat: add step field in KeptnMetric Signed-off-by: Rakshit Gondwal --- .../api/v1alpha3/keptnmetric_types.go | 2 + .../api/v1alpha3/keptnmetric_webhook.go | 21 +- .../api/v1alpha3/keptnmetric_webhook_test.go | 192 ++++++++++++++++++ .../bases/metrics.keptn.sh_keptnmetrics.yaml | 5 + 4 files changed, 218 insertions(+), 2 deletions(-) diff --git a/metrics-operator/api/v1alpha3/keptnmetric_types.go b/metrics-operator/api/v1alpha3/keptnmetric_types.go index da1f05d049..85f1b3628c 100644 --- a/metrics-operator/api/v1alpha3/keptnmetric_types.go +++ b/metrics-operator/api/v1alpha3/keptnmetric_types.go @@ -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 diff --git a/metrics-operator/api/v1alpha3/keptnmetric_webhook.go b/metrics-operator/api/v1alpha3/keptnmetric_webhook.go index eeaba7df38..c219bb4aba 100644 --- a/metrics-operator/api/v1alpha3/keptnmetric_webhook.go +++ b/metrics-operator/api/v1alpha3/keptnmetric_webhook.go @@ -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, @@ -93,3 +95,18 @@ func (s *KeptnMetric) validateRangeInterval() *field.Error { } return nil } + +func (s *KeptnMetric) validateRangeStep() *field.Error { + if s.Spec.Range == nil { + 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 +} diff --git a/metrics-operator/api/v1alpha3/keptnmetric_webhook_test.go b/metrics-operator/api/v1alpha3/keptnmetric_webhook_test.go index 6561dc0f16..5b5d3a70ff 100644 --- a/metrics-operator/api/v1alpha3/keptnmetric_webhook_test.go +++ b/metrics-operator/api/v1alpha3/keptnmetric_webhook_test.go @@ -141,3 +141,195 @@ 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: "", + }, + }, + want: apierrors.NewInvalid( + schema.GroupKind{Group: "metrics.keptn.sh", Kind: "KeptnMetric"}, + "create-with-empty-step", + field.ErrorList{ + field.Invalid( + field.NewPath("spec").Child("range").Child("step"), + "", + "Forbidden! The time interval cannot be parsed. Please check for suitable conventions", + ), + }, + ), + }, + { + 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) + } + }) + } +} diff --git a/metrics-operator/config/crd/bases/metrics.keptn.sh_keptnmetrics.yaml b/metrics-operator/config/crd/bases/metrics.keptn.sh_keptnmetrics.yaml index fafde197b0..c242d58338 100644 --- a/metrics-operator/config/crd/bases/metrics.keptn.sh_keptnmetrics.yaml +++ b/metrics-operator/config/crd/bases/metrics.keptn.sh_keptnmetrics.yaml @@ -224,6 +224,11 @@ spec: description: Interval specifies the duration of the time interval for the data query type: string + step: + default: 1m + description: Step represents the query resolution step width for + the data query + type: string type: object required: - fetchIntervalSeconds