From 54db85faa6c52934e08c36a454c4b23a8343d2dd Mon Sep 17 00:00:00 2001 From: odubajDT Date: Fri, 14 Oct 2022 08:59:34 +0200 Subject: [PATCH 01/29] feat(operator): Introduce KeptnEvaluation Controller + CRD Signed-off-by: odubajDT --- operator/PROJECT | 9 ++ .../api/v1alpha1/keptnevaluation_types.go | 69 +++++++++++ .../api/v1alpha1/zz_generated.deepcopy.go | 109 ++++++++++++++++++ .../lifecycle.keptn.sh_keptnevaluations.yaml | 76 ++++++++++++ operator/config/crd/kustomization.yaml | 3 + .../cainjection_in_keptnevaluations.yaml | 7 ++ .../patches/webhook_in_keptnevaluations.yaml | 16 +++ .../rbac/keptnevaluation_editor_role.yaml | 24 ++++ .../rbac/keptnevaluation_viewer_role.yaml | 20 ++++ operator/config/rbac/role.yaml | 26 +++++ .../lifecycle_v1alpha1_keptnevaluation.yaml | 6 + .../controllers/keptnevaluation_controller.go | 62 ++++++++++ operator/main.go | 18 ++- 13 files changed, 441 insertions(+), 4 deletions(-) create mode 100644 operator/api/v1alpha1/keptnevaluation_types.go create mode 100644 operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml create mode 100644 operator/config/crd/patches/cainjection_in_keptnevaluations.yaml create mode 100644 operator/config/crd/patches/webhook_in_keptnevaluations.yaml create mode 100644 operator/config/rbac/keptnevaluation_editor_role.yaml create mode 100644 operator/config/rbac/keptnevaluation_viewer_role.yaml create mode 100644 operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml create mode 100644 operator/controllers/keptnevaluation_controller.go diff --git a/operator/PROJECT b/operator/PROJECT index c2fb223f0c..223a018e56 100644 --- a/operator/PROJECT +++ b/operator/PROJECT @@ -75,4 +75,13 @@ resources: kind: KeptnEvaluationProvider path: github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: keptn.sh + group: lifecycle + kind: KeptnEvaluation + path: github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1 + version: v1alpha1 version: "3" diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go new file mode 100644 index 0000000000..05f40b573a --- /dev/null +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -0,0 +1,69 @@ +/* +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 v1alpha1 + +import ( + "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1/common" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// 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. + +// KeptnEvaluationSpec defines the desired state of KeptnEvaluation +type KeptnEvaluationSpec struct { + EvaluationDefinition string `json:"evaluationDefinition"` + Source string `json:"source"` +} + +// KeptnEvaluationStatus defines the observed state of KeptnEvaluation +type KeptnEvaluationStatus struct { + EvaluationStatus []EvaluationStatusItem `json:"evaluationStatus"` + OverallStatus common.KeptnState `json:"overallStatus"` +} + +type EvaluationStatusItem struct { + Name string `json:"name"` + Value string `json:"value"` + Status common.KeptnState `json:"status"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:resource:path=keptnevaluations,shortName=ke + +// KeptnEvaluation is the Schema for the keptnevaluations API +type KeptnEvaluation struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec KeptnEvaluationSpec `json:"spec,omitempty"` + Status KeptnEvaluationStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// KeptnEvaluationList contains a list of KeptnEvaluation +type KeptnEvaluationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []KeptnEvaluation `json:"items"` +} + +func init() { + SchemeBuilder.Register(&KeptnEvaluation{}, &KeptnEvaluationList{}) +} diff --git a/operator/api/v1alpha1/zz_generated.deepcopy.go b/operator/api/v1alpha1/zz_generated.deepcopy.go index 3d15d9dfbd..6b50fe2bdf 100644 --- a/operator/api/v1alpha1/zz_generated.deepcopy.go +++ b/operator/api/v1alpha1/zz_generated.deepcopy.go @@ -55,6 +55,21 @@ func (in *ContainerSpec) DeepCopy() *ContainerSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EvaluationStatusItem) DeepCopyInto(out *EvaluationStatusItem) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EvaluationStatusItem. +func (in *EvaluationStatusItem) DeepCopy() *EvaluationStatusItem { + if in == nil { + return nil + } + out := new(EvaluationStatusItem) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FunctionReference) DeepCopyInto(out *FunctionReference) { *out = *in @@ -361,6 +376,33 @@ func (in *KeptnAppVersionStatus) DeepCopy() *KeptnAppVersionStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeptnEvaluation) DeepCopyInto(out *KeptnEvaluation) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeptnEvaluation. +func (in *KeptnEvaluation) DeepCopy() *KeptnEvaluation { + if in == nil { + return nil + } + out := new(KeptnEvaluation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KeptnEvaluation) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeptnEvaluationDefinition) DeepCopyInto(out *KeptnEvaluationDefinition) { *out = *in @@ -455,6 +497,38 @@ func (in *KeptnEvaluationDefinitionStatus) DeepCopy() *KeptnEvaluationDefinition return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeptnEvaluationList) DeepCopyInto(out *KeptnEvaluationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KeptnEvaluation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeptnEvaluationList. +func (in *KeptnEvaluationList) DeepCopy() *KeptnEvaluationList { + if in == nil { + return nil + } + out := new(KeptnEvaluationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KeptnEvaluationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeptnEvaluationProvider) DeepCopyInto(out *KeptnEvaluationProvider) { *out = *in @@ -544,6 +618,41 @@ func (in *KeptnEvaluationProviderStatus) DeepCopy() *KeptnEvaluationProviderStat return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeptnEvaluationSpec) DeepCopyInto(out *KeptnEvaluationSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeptnEvaluationSpec. +func (in *KeptnEvaluationSpec) DeepCopy() *KeptnEvaluationSpec { + if in == nil { + return nil + } + out := new(KeptnEvaluationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeptnEvaluationStatus) DeepCopyInto(out *KeptnEvaluationStatus) { + *out = *in + if in.EvaluationStatus != nil { + in, out := &in.EvaluationStatus, &out.EvaluationStatus + *out = make([]EvaluationStatusItem, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeptnEvaluationStatus. +func (in *KeptnEvaluationStatus) DeepCopy() *KeptnEvaluationStatus { + if in == nil { + return nil + } + out := new(KeptnEvaluationStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeptnTask) DeepCopyInto(out *KeptnTask) { *out = *in diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml new file mode 100644 index 0000000000..6704d4105d --- /dev/null +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -0,0 +1,76 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: keptnevaluations.lifecycle.keptn.sh +spec: + group: lifecycle.keptn.sh + names: + kind: KeptnEvaluation + listKind: KeptnEvaluationList + plural: keptnevaluations + shortNames: + - ke + singular: keptnevaluation + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: KeptnEvaluation is the Schema for the keptnevaluations API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: KeptnEvaluationSpec defines the desired state of KeptnEvaluation + properties: + evaluationDefinition: + type: string + source: + type: string + required: + - evaluationDefinition + - source + type: object + status: + description: KeptnEvaluationStatus defines the observed state of KeptnEvaluation + properties: + evaluationStatus: + items: + properties: + name: + type: string + status: + type: string + value: + type: string + required: + - name + - status + - value + type: object + type: array + overallStatus: + type: string + required: + - evaluationStatus + - overallStatus + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/operator/config/crd/kustomization.yaml b/operator/config/crd/kustomization.yaml index f723cdde44..ce10d39ba0 100644 --- a/operator/config/crd/kustomization.yaml +++ b/operator/config/crd/kustomization.yaml @@ -10,6 +10,7 @@ resources: - bases/lifecycle.keptn.sh_keptnappversions.yaml - bases/lifecycle.keptn.sh_keptnevaluationdefinitions.yaml - bases/lifecycle.keptn.sh_keptnevaluationproviders.yaml +- bases/lifecycle.keptn.sh_keptnevaluations.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -23,6 +24,7 @@ patchesStrategicMerge: #- patches/webhook_in_keptnappversions.yaml #- patches/webhook_in_keptnevaluationdefinitions.yaml #- patches/webhook_in_keptnevaluationproviders.yaml +#- patches/webhook_in_keptnevaluations.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. @@ -35,6 +37,7 @@ patchesStrategicMerge: #- patches/cainjection_in_keptnappversions.yaml #- patches/cainjection_in_keptnevaluationdefinitions.yaml #- patches/cainjection_in_keptnevaluationproviders.yaml +#- patches/cainjection_in_keptnevaluations.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/operator/config/crd/patches/cainjection_in_keptnevaluations.yaml b/operator/config/crd/patches/cainjection_in_keptnevaluations.yaml new file mode 100644 index 0000000000..3f6cd6ba19 --- /dev/null +++ b/operator/config/crd/patches/cainjection_in_keptnevaluations.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: keptnevaluations.lifecycle.keptn.sh diff --git a/operator/config/crd/patches/webhook_in_keptnevaluations.yaml b/operator/config/crd/patches/webhook_in_keptnevaluations.yaml new file mode 100644 index 0000000000..c69b624581 --- /dev/null +++ b/operator/config/crd/patches/webhook_in_keptnevaluations.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: keptnevaluations.lifecycle.keptn.sh +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/operator/config/rbac/keptnevaluation_editor_role.yaml b/operator/config/rbac/keptnevaluation_editor_role.yaml new file mode 100644 index 0000000000..87345098b0 --- /dev/null +++ b/operator/config/rbac/keptnevaluation_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit keptnevaluations. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: keptnevaluation-editor-role +rules: +- apiGroups: + - lifecycle.keptn.sh + resources: + - keptnevaluations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - lifecycle.keptn.sh + resources: + - keptnevaluations/status + verbs: + - get diff --git a/operator/config/rbac/keptnevaluation_viewer_role.yaml b/operator/config/rbac/keptnevaluation_viewer_role.yaml new file mode 100644 index 0000000000..e2d6087141 --- /dev/null +++ b/operator/config/rbac/keptnevaluation_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view keptnevaluations. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: keptnevaluation-viewer-role +rules: +- apiGroups: + - lifecycle.keptn.sh + resources: + - keptnevaluations + verbs: + - get + - list + - watch +- apiGroups: + - lifecycle.keptn.sh + resources: + - keptnevaluations/status + verbs: + - get diff --git a/operator/config/rbac/role.yaml b/operator/config/rbac/role.yaml index 7af86ffc9c..e9ede34d06 100644 --- a/operator/config/rbac/role.yaml +++ b/operator/config/rbac/role.yaml @@ -144,6 +144,32 @@ rules: - get - patch - update +- apiGroups: + - lifecycle.keptn.sh + resources: + - keptnevaluations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - lifecycle.keptn.sh + resources: + - keptnevaluations/finalizers + verbs: + - update +- apiGroups: + - lifecycle.keptn.sh + resources: + - keptnevaluations/status + verbs: + - get + - patch + - update - apiGroups: - lifecycle.keptn.sh resources: diff --git a/operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml b/operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml new file mode 100644 index 0000000000..f99f801d19 --- /dev/null +++ b/operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml @@ -0,0 +1,6 @@ +apiVersion: lifecycle.keptn.sh/v1alpha1 +kind: KeptnEvaluation +metadata: + name: keptnevaluation-sample +spec: + # TODO(user): Add fields here diff --git a/operator/controllers/keptnevaluation_controller.go b/operator/controllers/keptnevaluation_controller.go new file mode 100644 index 0000000000..cc484ce06f --- /dev/null +++ b/operator/controllers/keptnevaluation_controller.go @@ -0,0 +1,62 @@ +/* +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 controllers + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + lifecyclev1alpha1 "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1" +) + +// KeptnEvaluationReconciler reconciles a KeptnEvaluation object +type KeptnEvaluationReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluations,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluations/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluations/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the KeptnEvaluation object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *KeptnEvaluationReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&lifecyclev1alpha1.KeptnEvaluation{}). + Complete(r) +} diff --git a/operator/main.go b/operator/main.go index a130dba11e..008869b482 100644 --- a/operator/main.go +++ b/operator/main.go @@ -20,14 +20,16 @@ import ( "context" "flag" "fmt" - "github.com/kelseyhightower/envconfig" - "github.com/keptn-sandbox/lifecycle-controller/operator/controllers/keptnappversion" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" "log" "net/http" "time" + "github.com/kelseyhightower/envconfig" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + "github.com/keptn-sandbox/lifecycle-controller/operator/controllers/keptnappversion" + "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1/common" "github.com/keptn-sandbox/lifecycle-controller/operator/controllers/keptnworkload" @@ -69,6 +71,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" lifecyclev1alpha1 "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1" + "github.com/keptn-sandbox/lifecycle-controller/operator/controllers" "github.com/keptn-sandbox/lifecycle-controller/operator/webhooks" //+kubebuilder:scaffold:imports ) @@ -288,6 +291,13 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "KeptnAppVersion") os.Exit(1) } + if err = (&controllers.KeptnEvaluationReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "KeptnEvaluation") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { From f4fa0e2600cdff86cc53e2289daf6f464d22b59b Mon Sep 17 00:00:00 2001 From: odubajDT Date: Fri, 14 Oct 2022 10:28:24 +0200 Subject: [PATCH 02/29] additional fields to CRD Signed-off-by: odubajDT --- .../api/v1alpha1/keptnevaluation_types.go | 11 +++++++++-- .../lifecycle.keptn.sh_keptnevaluations.yaml | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index 05f40b573a..2b96aeb6d8 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -17,6 +17,8 @@ limitations under the License. package v1alpha1 import ( + "time" + "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1/common" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -26,12 +28,17 @@ import ( // KeptnEvaluationSpec defines the desired state of KeptnEvaluation type KeptnEvaluationSpec struct { - EvaluationDefinition string `json:"evaluationDefinition"` - Source string `json:"source"` + EvaluationDefinition string `json:"evaluationDefinition"` + Source string `json:"source"` + Timeframe time.Duration `json:"timeframe,omitempty"` + Retries int `json:"retries,omitempty"` + RetryInterval time.Duration `json:"retryInterval,omitempty"` + FailAction string `json:"failAction,omitempty"` } // KeptnEvaluationStatus defines the observed state of KeptnEvaluation type KeptnEvaluationStatus struct { + RetryCount int `json:"retryCount"` EvaluationStatus []EvaluationStatusItem `json:"evaluationStatus"` OverallStatus common.KeptnState `json:"overallStatus"` } diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index 6704d4105d..1bb617c086 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -39,8 +39,24 @@ spec: properties: evaluationDefinition: type: string + failAction: + type: string + retries: + type: integer + retryInterval: + description: A Duration represents the elapsed time between two instants + as an int64 nanosecond count. The representation limits the largest + representable duration to approximately 290 years. + format: int64 + type: integer source: type: string + timeframe: + description: A Duration represents the elapsed time between two instants + as an int64 nanosecond count. The representation limits the largest + representable duration to approximately 290 years. + format: int64 + type: integer required: - evaluationDefinition - source @@ -65,9 +81,12 @@ spec: type: array overallStatus: type: string + retryCount: + type: integer required: - evaluationStatus - overallStatus + - retryCount type: object type: object served: true From 108affc1756f5ca72d461e423ddf6be845cdb347 Mon Sep 17 00:00:00 2001 From: odubajDT Date: Fri, 14 Oct 2022 10:31:58 +0200 Subject: [PATCH 03/29] controller in separate dir Signed-off-by: odubajDT --- .../controller.go} | 2 +- operator/main.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) rename operator/controllers/{keptnevaluation_controller.go => keptnevaluation/controller.go} (98%) diff --git a/operator/controllers/keptnevaluation_controller.go b/operator/controllers/keptnevaluation/controller.go similarity index 98% rename from operator/controllers/keptnevaluation_controller.go rename to operator/controllers/keptnevaluation/controller.go index cc484ce06f..ba68b9e0b9 100644 --- a/operator/controllers/keptnevaluation_controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controllers +package keptnevaluation import ( "context" diff --git a/operator/main.go b/operator/main.go index 008869b482..bcee39d7a1 100644 --- a/operator/main.go +++ b/operator/main.go @@ -39,6 +39,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/keptn-sandbox/lifecycle-controller/operator/controllers/keptnapp" + "github.com/keptn-sandbox/lifecycle-controller/operator/controllers/keptnevaluation" "github.com/keptn-sandbox/lifecycle-controller/operator/controllers/keptntask" "github.com/keptn-sandbox/lifecycle-controller/operator/controllers/keptntaskdefinition" @@ -71,7 +72,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" lifecyclev1alpha1 "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1" - "github.com/keptn-sandbox/lifecycle-controller/operator/controllers" + "github.com/keptn-sandbox/lifecycle-controller/operator/webhooks" //+kubebuilder:scaffold:imports ) @@ -291,7 +292,7 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "KeptnAppVersion") os.Exit(1) } - if err = (&controllers.KeptnEvaluationReconciler{ + if err = (&keptnevaluation.KeptnEvaluationReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { From 0ba247ff98b3bf082f5d93ef33f449fbad6ba03a Mon Sep 17 00:00:00 2001 From: odubajDT Date: Fri, 14 Oct 2022 10:48:16 +0200 Subject: [PATCH 04/29] prepare structures Signed-off-by: odubajDT --- operator/api/v1alpha1/common/common.go | 8 +++++++ operator/api/v1alpha1/common/phases.go | 4 ++++ .../api/v1alpha1/keptnevaluation_types.go | 17 +++++++++----- operator/api/v1alpha1/keptntask_types.go | 4 ++-- operator/api/v1alpha1/semconv/semconv.go | 9 ++++++++ .../lifecycle.keptn.sh_keptnevaluations.yaml | 11 +++++++++ .../controllers/keptnevaluation/controller.go | 10 +++++++- operator/main.go | 23 +++++++++++++++++-- 8 files changed, 75 insertions(+), 11 deletions(-) diff --git a/operator/api/v1alpha1/common/common.go b/operator/api/v1alpha1/common/common.go index fdc98dadc9..fb1494a6bd 100644 --- a/operator/api/v1alpha1/common/common.go +++ b/operator/api/v1alpha1/common/common.go @@ -107,6 +107,8 @@ type CheckType string const PreDeploymentCheckType CheckType = "pre" const PostDeploymentCheckType CheckType = "post" +const PreAnalysisCheckType CheckType = "pre" +const PostAnalysisCheckType CheckType = "post" type KeptnMeters struct { TaskCount syncint64.Counter @@ -118,6 +120,9 @@ type KeptnMeters struct { AppCount syncint64.Counter AppDuration syncfloat64.Histogram AppActive syncint64.UpDownCounter + AnalysisCount syncint64.Counter + AnalysisDuration syncfloat64.Histogram + AnalysusActive syncint64.UpDownCounter } const ( @@ -132,6 +137,9 @@ const ( TaskStatus attribute.Key = attribute.Key("keptn.deployment.task.status") TaskName attribute.Key = attribute.Key("keptn.deployment.task.name") TaskType attribute.Key = attribute.Key("keptn.deployment.task.type") + EvaluationStatus attribute.Key = attribute.Key("keptn.deployment.evaluation.status") + EvaluationName attribute.Key = attribute.Key("keptn.deployment.evaluation.name") + EvaluationType attribute.Key = attribute.Key("keptn.deployment.evaluation.type") ) func GenerateTaskName(checkType CheckType, taskName string) string { diff --git a/operator/api/v1alpha1/common/phases.go b/operator/api/v1alpha1/common/phases.go index 3973c5f109..5b6a738756 100644 --- a/operator/api/v1alpha1/common/phases.go +++ b/operator/api/v1alpha1/common/phases.go @@ -10,8 +10,12 @@ type KeptnPhaseType struct { var ( PhaseWorkloadPreDeployment = KeptnPhaseType{LongName: "Workload Pre-Deployment", ShortName: "WorkloadPreDeploy"} PhaseWorkloadPostDeployment = KeptnPhaseType{LongName: "Workload Post-Deployment", ShortName: "WorkloadPostDeploy"} + PhaseWorkloadPreAnalysis = KeptnPhaseType{LongName: "Workload Pre-Analysis", ShortName: "WorkloadPreAnalysis"} + PhaseWorkloadPostAnalysis = KeptnPhaseType{LongName: "Workload Post-Analysis", ShortName: "WorkloadPostAnalysis"} PhaseWorkloadDeployment = KeptnPhaseType{LongName: "Workload Deployment", ShortName: "WorkloadDeploy"} PhaseAppPreDeployment = KeptnPhaseType{LongName: "App Pre-Deployment", ShortName: "AppPreDeploy"} PhaseAppPostDeployment = KeptnPhaseType{LongName: "App Post-Deployment", ShortName: "AppPostDeploy"} + PhaseAppPreAnalysis = KeptnPhaseType{LongName: "App Pre-Analysis", ShortName: "AppPreAnalysis"} + PhaseAppPostAnalysis = KeptnPhaseType{LongName: "App Post-Analysis", ShortName: "AppPostAnalysis"} PhaseAppDeployment = KeptnPhaseType{LongName: "App Deployment", ShortName: "AppDeploy"} ) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index 2b96aeb6d8..1d4cac60ba 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -28,12 +28,17 @@ import ( // KeptnEvaluationSpec defines the desired state of KeptnEvaluation type KeptnEvaluationSpec struct { - EvaluationDefinition string `json:"evaluationDefinition"` - Source string `json:"source"` - Timeframe time.Duration `json:"timeframe,omitempty"` - Retries int `json:"retries,omitempty"` - RetryInterval time.Duration `json:"retryInterval,omitempty"` - FailAction string `json:"failAction,omitempty"` + Workload string `json:"workload,omitempty"` + WorkloadVersion string `json:"workloadVersion"` + AppName string `json:"app,omitempty"` + AppVersion string `json:"appVersion,omitempty"` + EvaluationDefinition string `json:"evaluationDefinition"` + Source string `json:"source"` + Timeframe time.Duration `json:"timeframe,omitempty"` + Retries int `json:"retries,omitempty"` + RetryInterval time.Duration `json:"retryInterval,omitempty"` + FailAction string `json:"failAction,omitempty"` + Type common.CheckType `json:"checkType,omitempty"` } // KeptnEvaluationStatus defines the observed state of KeptnEvaluation diff --git a/operator/api/v1alpha1/keptntask_types.go b/operator/api/v1alpha1/keptntask_types.go index 17f595d74a..a62341acbb 100644 --- a/operator/api/v1alpha1/keptntask_types.go +++ b/operator/api/v1alpha1/keptntask_types.go @@ -29,9 +29,9 @@ import ( // KeptnTaskSpec defines the desired state of KeptnTask type KeptnTaskSpec struct { - Workload string `json:"workload,omitempty"` //TODO make autofill logic + Workload string `json:"workload,omitempty"` Version string `json:"version"` - AppName string `json:"app,omitempty"` //TODO make autofill logic + AppName string `json:"app,omitempty"` TaskDefinition string `json:"taskDefinition"` Context TaskContext `json:"context"` Parameters TaskParameters `json:"parameters,omitempty"` diff --git a/operator/api/v1alpha1/semconv/semconv.go b/operator/api/v1alpha1/semconv/semconv.go index eb18768fa3..7e3cb866a0 100644 --- a/operator/api/v1alpha1/semconv/semconv.go +++ b/operator/api/v1alpha1/semconv/semconv.go @@ -36,6 +36,15 @@ func AddAttributeFromTask(s trace.Span, t v1alpha1.KeptnTask) { s.SetAttributes(common.TaskType.String(string(t.Spec.Type))) } +func AddAttributeFromEvaluation(s trace.Span, t v1alpha1.KeptnEvaluation) { + s.SetAttributes(common.AppName.String(t.Spec.AppName)) + s.SetAttributes(common.AppVersion.String(t.Spec.AppVersion)) + s.SetAttributes(common.WorkloadName.String(t.Spec.Workload)) + s.SetAttributes(common.WorkloadVersion.String(t.Spec.WorkloadVersion)) + s.SetAttributes(common.EvaluationName.String(t.Name)) + s.SetAttributes(common.EvaluationType.String(string(t.Spec.Type))) +} + func AddAttributeFromAnnotations(s trace.Span, annotations map[string]string) { s.SetAttributes(common.AppName.String(annotations[common.AppAnnotation])) s.SetAttributes(common.WorkloadName.String(annotations[common.WorkloadAnnotation])) diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index 1bb617c086..28628f8b49 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -37,6 +37,12 @@ spec: spec: description: KeptnEvaluationSpec defines the desired state of KeptnEvaluation properties: + app: + type: string + appVersion: + type: string + checkType: + type: string evaluationDefinition: type: string failAction: @@ -57,9 +63,14 @@ spec: representable duration to approximately 290 years. format: int64 type: integer + workload: + type: string + workloadVersion: + type: string required: - evaluationDefinition - source + - workloadVersion type: object status: description: KeptnEvaluationStatus defines the observed state of KeptnEvaluation diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index ba68b9e0b9..92e7fc4131 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -19,18 +19,26 @@ package keptnevaluation import ( "context" + "go.opentelemetry.io/otel/trace" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" + "github.com/go-logr/logr" lifecyclev1alpha1 "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1" + "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1/common" ) // KeptnEvaluationReconciler reconciles a KeptnEvaluation object type KeptnEvaluationReconciler struct { client.Client - Scheme *runtime.Scheme + Scheme *runtime.Scheme + Recorder record.EventRecorder + Log logr.Logger + Meters common.KeptnMeters + Tracer trace.Tracer } //+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluations,verbs=get;list;watch;create;update;patch;delete diff --git a/operator/main.go b/operator/main.go index bcee39d7a1..32016de1c4 100644 --- a/operator/main.go +++ b/operator/main.go @@ -151,6 +151,18 @@ func main() { if err != nil { setupLog.Error(err, "unable to start OTel") } + analysisCount, err := meter.SyncInt64().Counter("keptn.analysis.count", instrument.WithDescription("a simple counter for Keptn analysis for Evaluations")) + if err != nil { + setupLog.Error(err, "unable to start OTel") + } + analysisDuration, err := meter.SyncFloat64().Histogram("keptn.analysis.duration", instrument.WithDescription("a histogram of duration for Keptn analysis for Evaluations"), instrument.WithUnit(unit.Unit("s"))) + if err != nil { + setupLog.Error(err, "unable to start OTel") + } + analysisActive, err := meter.SyncInt64().UpDownCounter("keptn.analysis.active", instrument.WithDescription("a simple counter of active apps for Keptn analysis for Evaluations")) + if err != nil { + setupLog.Error(err, "unable to start OTel") + } meters := common.KeptnMeters{ TaskCount: taskCount, @@ -162,6 +174,9 @@ func main() { AppCount: appCount, AppDuration: appDuration, AppActive: appActive, + AnalysisCount: analysisCount, + AnalysisDuration: analysisDuration, + AnalysusActive: analysisActive, } // Start the prometheus HTTP server and pass the exporter Collector to it @@ -293,8 +308,12 @@ func main() { os.Exit(1) } if err = (&keptnevaluation.KeptnEvaluationReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Log: ctrl.Log.WithName("KeptnAppVersion Controller"), + Recorder: mgr.GetEventRecorderFor("keptnappversion-controller"), + Tracer: otel.Tracer("keptn/operator/appversion"), + Meters: meters, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "KeptnEvaluation") os.Exit(1) From 31560fe8bdff3c4e6181445358d48bc460b8271c Mon Sep 17 00:00:00 2001 From: odubajDT Date: Fri, 14 Oct 2022 11:00:22 +0200 Subject: [PATCH 05/29] set up everything except logic Signed-off-by: odubajDT --- operator/api/v1alpha1/common/common.go | 2 +- .../api/v1alpha1/keptnevaluation_types.go | 46 ++++++++++++ .../api/v1alpha1/zz_generated.deepcopy.go | 2 + .../lifecycle.keptn.sh_keptnevaluations.yaml | 6 ++ .../controllers/keptnevaluation/controller.go | 74 +++++++++++++++++-- operator/controllers/keptntask/controller.go | 2 +- operator/main.go | 2 +- 7 files changed, 126 insertions(+), 8 deletions(-) diff --git a/operator/api/v1alpha1/common/common.go b/operator/api/v1alpha1/common/common.go index fb1494a6bd..6b80ac3520 100644 --- a/operator/api/v1alpha1/common/common.go +++ b/operator/api/v1alpha1/common/common.go @@ -122,7 +122,7 @@ type KeptnMeters struct { AppActive syncint64.UpDownCounter AnalysisCount syncint64.Counter AnalysisDuration syncfloat64.Histogram - AnalysusActive syncint64.UpDownCounter + AnalysisActive syncint64.UpDownCounter } const ( diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index 1d4cac60ba..6d7458e63a 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -20,6 +20,7 @@ import ( "time" "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1/common" + "go.opentelemetry.io/otel/attribute" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -46,6 +47,8 @@ type KeptnEvaluationStatus struct { RetryCount int `json:"retryCount"` EvaluationStatus []EvaluationStatusItem `json:"evaluationStatus"` OverallStatus common.KeptnState `json:"overallStatus"` + StartTime metav1.Time `json:"startTime,omitempty"` + EndTime metav1.Time `json:"endTime,omitempty"` } type EvaluationStatusItem struct { @@ -79,3 +82,46 @@ type KeptnEvaluationList struct { func init() { SchemeBuilder.Register(&KeptnEvaluation{}, &KeptnEvaluationList{}) } + +func (i *KeptnEvaluation) SetStartTime() { + if i.Status.StartTime.IsZero() { + i.Status.StartTime = metav1.NewTime(time.Now().UTC()) + } +} + +func (i *KeptnEvaluation) SetEndTime() { + if i.Status.EndTime.IsZero() { + i.Status.EndTime = metav1.NewTime(time.Now().UTC()) + } +} + +func (i *KeptnEvaluation) IsStartTimeSet() bool { + return !i.Status.StartTime.IsZero() +} + +func (i *KeptnEvaluation) IsEndTimeSet() bool { + return !i.Status.EndTime.IsZero() +} + +func (i KeptnEvaluation) GetActiveMetricsAttributes() []attribute.KeyValue { + return []attribute.KeyValue{ + common.AppName.String(i.Spec.AppName), + common.AppVersion.String(i.Spec.AppVersion), + common.WorkloadName.String(i.Spec.Workload), + common.WorkloadVersion.String(i.Spec.WorkloadVersion), + common.EvaluationName.String(i.Name), + common.EvaluationType.String(string(i.Spec.Type)), + } +} + +func (i KeptnEvaluation) GetMetricsAttributes() []attribute.KeyValue { + return []attribute.KeyValue{ + common.AppName.String(i.Spec.AppName), + common.AppVersion.String(i.Spec.AppVersion), + common.WorkloadName.String(i.Spec.Workload), + common.WorkloadVersion.String(i.Spec.WorkloadVersion), + common.EvaluationName.String(i.Name), + common.EvaluationType.String(string(i.Spec.Type)), + common.EvaluationStatus.String(string(i.Status.OverallStatus)), + } +} diff --git a/operator/api/v1alpha1/zz_generated.deepcopy.go b/operator/api/v1alpha1/zz_generated.deepcopy.go index 6b50fe2bdf..94d270a9b6 100644 --- a/operator/api/v1alpha1/zz_generated.deepcopy.go +++ b/operator/api/v1alpha1/zz_generated.deepcopy.go @@ -641,6 +641,8 @@ func (in *KeptnEvaluationStatus) DeepCopyInto(out *KeptnEvaluationStatus) { *out = make([]EvaluationStatusItem, len(*in)) copy(*out, *in) } + in.StartTime.DeepCopyInto(&out.StartTime) + in.EndTime.DeepCopyInto(&out.EndTime) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeptnEvaluationStatus. diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index 28628f8b49..5777e2e1fe 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -75,6 +75,9 @@ spec: status: description: KeptnEvaluationStatus defines the observed state of KeptnEvaluation properties: + endTime: + format: date-time + type: string evaluationStatus: items: properties: @@ -94,6 +97,9 @@ spec: type: string retryCount: type: integer + startTime: + format: date-time + type: string required: - evaluationStatus - overallStatus diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index 92e7fc4131..91d0294de0 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -18,17 +18,22 @@ package keptnevaluation import ( "context" + "time" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" + "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" "github.com/go-logr/logr" - lifecyclev1alpha1 "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1" + klcv1alpha1 "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1" "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1/common" + "github.com/keptn-sandbox/lifecycle-controller/operator/api/v1alpha1/semconv" ) // KeptnEvaluationReconciler reconciles a KeptnEvaluation object @@ -55,9 +60,68 @@ type KeptnEvaluationReconciler struct { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - _ = log.FromContext(ctx) + r.Log.Info("Reconciling KeptnEvaluation") + evaluation := &klcv1alpha1.KeptnEvaluation{} - // TODO(user): your logic here + if err := r.Client.Get(ctx, req.NamespacedName, evaluation); err != nil { + if errors.IsNotFound(err) { + // taking down all associated K8s resources is handled by K8s + r.Log.Info("KeptnEvaluation resource not found. Ignoring since object must be deleted") + return ctrl.Result{}, nil + } + r.Log.Error(err, "Failed to get the KeptnEvaluation") + return ctrl.Result{Requeue: true, RequeueAfter: 30 * time.Second}, nil + } + + traceContextCarrier := propagation.MapCarrier(evaluation.Annotations) + ctx = otel.GetTextMapPropagator().Extract(ctx, traceContextCarrier) + + ctx, span := r.Tracer.Start(ctx, "reconcile_evaluation", trace.WithSpanKind(trace.SpanKindConsumer)) + defer span.End() + + semconv.AddAttributeFromEvaluation(span, *evaluation) + + if !evaluation.IsStartTimeSet() { + // metrics: increment active evaluation counter + r.Meters.AnalysisActive.Add(ctx, 1, evaluation.GetActiveMetricsAttributes()...) + evaluation.SetStartTime() + } + + // TODO logic of evaluation controller + // + // + // + // + // + // + // + + r.Log.Info("Finished Reconciling KeptnEvaluation") + + // Evaluation is completed at this place + + if !evaluation.IsEndTimeSet() { + // metrics: decrement active evaluation counter + r.Meters.AnalysisActive.Add(ctx, -1, evaluation.GetActiveMetricsAttributes()...) + evaluation.SetEndTime() + } + + err := r.Client.Status().Update(ctx, evaluation) + if err != nil { + span.SetStatus(codes.Error, err.Error()) + return ctrl.Result{Requeue: true}, err + } + + attrs := evaluation.GetMetricsAttributes() + + r.Log.Info("Increasing evaluation count") + + // metrics: increment evaluation counter + r.Meters.AnalysisCount.Add(ctx, 1, attrs...) + + // metrics: add evaluation duration + duration := evaluation.Status.EndTime.Time.Sub(evaluation.Status.StartTime.Time) + r.Meters.AnalysisDuration.Record(ctx, duration.Seconds(), attrs...) return ctrl.Result{}, nil } @@ -65,6 +129,6 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ // SetupWithManager sets up the controller with the Manager. func (r *KeptnEvaluationReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&lifecyclev1alpha1.KeptnEvaluation{}). + For(&klcv1alpha1.KeptnEvaluation{}). Complete(r) } diff --git a/operator/controllers/keptntask/controller.go b/operator/controllers/keptntask/controller.go index 3f34fa6201..07d56efa90 100644 --- a/operator/controllers/keptntask/controller.go +++ b/operator/controllers/keptntask/controller.go @@ -116,7 +116,7 @@ func (r *KeptnTaskReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( r.Log.Info("Finished Reconciling KeptnTask") - // WorkloadInstance is completed at this place + // Task is completed at this place if !task.IsEndTimeSet() { // metrics: decrement active task counter diff --git a/operator/main.go b/operator/main.go index 32016de1c4..461fbf91b4 100644 --- a/operator/main.go +++ b/operator/main.go @@ -176,7 +176,7 @@ func main() { AppActive: appActive, AnalysisCount: analysisCount, AnalysisDuration: analysisDuration, - AnalysusActive: analysisActive, + AnalysisActive: analysisActive, } // Start the prometheus HTTP server and pass the exporter Collector to it From 7e18a8ad88bf6e3b8898b38534691446a4fcd366 Mon Sep 17 00:00:00 2001 From: odubajDT Date: Fri, 14 Oct 2022 11:53:55 +0200 Subject: [PATCH 06/29] first draft without evaluation logic Signed-off-by: odubajDT --- .../api/v1alpha1/keptnevaluation_types.go | 10 +++ .../controllers/keptnevaluation/controller.go | 79 ++++++++++++++++--- 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index 6d7458e63a..efdad0280f 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -125,3 +125,13 @@ func (i KeptnEvaluation) GetMetricsAttributes() []attribute.KeyValue { common.EvaluationStatus.String(string(i.Status.OverallStatus)), } } + +func (e *KeptnEvaluation) InitializeEvaluationStatuses(definition KeptnEvaluationDefinition) { + for _, query := range definition.Spec.Objectives { + evaluationStatusItem := EvaluationStatusItem{ + Name: query.Name, + Status: common.StatePending, + } + e.Status.EvaluationStatus = append(e.Status.EvaluationStatus, evaluationStatusItem) + } +} diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index 91d0294de0..58c3096467 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -26,6 +26,7 @@ import ( "go.opentelemetry.io/otel/trace" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -87,14 +88,44 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ evaluation.SetStartTime() } - // TODO logic of evaluation controller - // - // - // - // - // - // - // + if !evaluation.Status.OverallStatus.IsCompleted() && evaluation.Status.RetryCount <= evaluation.Spec.Retries { + evaluationDefinition, evaluationProvider, err := r.fetchDefinitionAndProvider(ctx, req.NamespacedName) + if err != nil { + return ctrl.Result{Requeue: true, RequeueAfter: 30 * time.Second}, nil + } + if evaluationDefinition == nil && evaluationProvider == nil { + return ctrl.Result{}, nil + } + + if len(evaluation.Status.EvaluationStatus) != len(evaluationDefinition.Spec.Objectives) { + evaluation.InitializeEvaluationStatuses(*evaluationDefinition) + } + + statusSummary := common.StatusSummary{} + + for i, query := range evaluationDefinition.Spec.Objectives { + if evaluation.Status.EvaluationStatus[i].Status.IsSucceeded() { + statusSummary = common.UpdateStatusSummary(common.StateSucceeded, statusSummary) + continue + } + statusItem := r.queryEvaluation(query, *evaluationProvider) + statusSummary = common.UpdateStatusSummary(statusItem.Status, statusSummary) + evaluation.Status.EvaluationStatus[i] = *statusItem + } + + evaluation.Status.RetryCount++ + evaluation.Status.OverallStatus = common.GetOverallState(statusSummary) + } + + err := r.Client.Status().Update(ctx, evaluation) + if err != nil { + span.SetStatus(codes.Error, err.Error()) + return ctrl.Result{Requeue: true}, err + } + + if !evaluation.Status.OverallStatus.IsCompleted() { + return ctrl.Result{Requeue: true, RequeueAfter: evaluation.Spec.RetryInterval * time.Second}, nil + } r.Log.Info("Finished Reconciling KeptnEvaluation") @@ -106,7 +137,7 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ evaluation.SetEndTime() } - err := r.Client.Status().Update(ctx, evaluation) + err = r.Client.Status().Update(ctx, evaluation) if err != nil { span.SetStatus(codes.Error, err.Error()) return ctrl.Result{Requeue: true}, err @@ -132,3 +163,33 @@ func (r *KeptnEvaluationReconciler) SetupWithManager(mgr ctrl.Manager) error { For(&klcv1alpha1.KeptnEvaluation{}). Complete(r) } + +func (r KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Context, namespace types.NamespacedName) (*klcv1alpha1.KeptnEvaluationDefinition, *klcv1alpha1.KeptnEvaluationProvider, error) { + evaluationDefinition := &klcv1alpha1.KeptnEvaluationDefinition{} + if err := r.Client.Get(ctx, namespace, evaluationDefinition); err != nil { + if errors.IsNotFound(err) { + // taking down all associated K8s resources is handled by K8s + r.Log.Info("KeptnEvaluationDefinition resource not found. Ignoring since object must be deleted") + return nil, nil, nil + } + r.Log.Error(err, "Failed to get the KeptnEvaluationDefinition") + return nil, nil, err + } + + evaluationProvider := &klcv1alpha1.KeptnEvaluationProvider{} + if err := r.Client.Get(ctx, namespace, evaluationProvider); err != nil { + if errors.IsNotFound(err) { + // taking down all associated K8s resources is handled by K8s + r.Log.Info("KeptnEvaluationProvider resource not found. Ignoring since object must be deleted") + return nil, nil, nil + } + r.Log.Error(err, "Failed to get the KeptnEvaluationProvider") + return nil, nil, err + } + + return evaluationDefinition, evaluationProvider, nil +} + +func (r KeptnEvaluationReconciler) queryEvaluation(klcv1alpha1.Objective, klcv1alpha1.KeptnEvaluationProvider) *klcv1alpha1.EvaluationStatusItem { + return nil +} From 1c627ca5e73dfdf6ceba2f2c2cfb8368e158608b Mon Sep 17 00:00:00 2001 From: RealAnna Date: Fri, 14 Oct 2022 11:59:31 +0200 Subject: [PATCH 07/29] chore: init evaluation status Signed-off-by: RealAnna --- operator/controllers/keptnevaluation/controller.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index 58c3096467..ea609153b9 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -190,6 +190,12 @@ func (r KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Contex return evaluationDefinition, evaluationProvider, nil } -func (r KeptnEvaluationReconciler) queryEvaluation(klcv1alpha1.Objective, klcv1alpha1.KeptnEvaluationProvider) *klcv1alpha1.EvaluationStatusItem { - return nil +func (r KeptnEvaluationReconciler) queryEvaluation(objective klcv1alpha1.Objective, provider klcv1alpha1.KeptnEvaluationProvider) *klcv1alpha1.EvaluationStatusItem { + query := &klcv1alpha1.EvaluationStatusItem{ + Name: objective.Name, + Value: "", + Status: "", + } + + return query } From 798adf8994bd4d2abbb71dd03b8f8b9533d7cbae Mon Sep 17 00:00:00 2001 From: RealAnna Date: Fri, 14 Oct 2022 12:06:47 +0200 Subject: [PATCH 08/29] chore: note TODOS Signed-off-by: RealAnna --- operator/controllers/keptnevaluation/controller.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index ea609153b9..33658dbe8d 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -89,7 +89,7 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ } if !evaluation.Status.OverallStatus.IsCompleted() && evaluation.Status.RetryCount <= evaluation.Spec.Retries { - evaluationDefinition, evaluationProvider, err := r.fetchDefinitionAndProvider(ctx, req.NamespacedName) + evaluationDefinition, evaluationProvider, err := r.fetchDefinitionAndProvider(ctx, req.NamespacedName) //TODO we need to fetch using the right name not the Evaluation name if err != nil { return ctrl.Result{Requeue: true, RequeueAfter: 30 * time.Second}, nil } @@ -197,5 +197,8 @@ func (r KeptnEvaluationReconciler) queryEvaluation(objective klcv1alpha1.Objecti Status: "", } + //TODO query provider like prometheus service does + //TODO decide and update status in query + return query } From a15569eae8523ffe6f5f80a28943b4dadf5a9422 Mon Sep 17 00:00:00 2001 From: RealAnna Date: Fri, 14 Oct 2022 12:13:47 +0200 Subject: [PATCH 09/29] chore: fixed namespaced resources Signed-off-by: RealAnna --- operator/controllers/keptnevaluation/controller.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index 33658dbe8d..cba090d326 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -89,7 +89,8 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ } if !evaluation.Status.OverallStatus.IsCompleted() && evaluation.Status.RetryCount <= evaluation.Spec.Retries { - evaluationDefinition, evaluationProvider, err := r.fetchDefinitionAndProvider(ctx, req.NamespacedName) //TODO we need to fetch using the right name not the Evaluation name + namespacedDefinition := types.NamespacedName{req.NamespacedName.Namespace, evaluation.Spec.EvaluationDefinition} + evaluationDefinition, evaluationProvider, err := r.fetchDefinitionAndProvider(ctx, namespacedDefinition) if err != nil { return ctrl.Result{Requeue: true, RequeueAfter: 30 * time.Second}, nil } @@ -164,9 +165,9 @@ func (r *KeptnEvaluationReconciler) SetupWithManager(mgr ctrl.Manager) error { Complete(r) } -func (r KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Context, namespace types.NamespacedName) (*klcv1alpha1.KeptnEvaluationDefinition, *klcv1alpha1.KeptnEvaluationProvider, error) { +func (r KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Context, namespacedDefinition types.NamespacedName) (*klcv1alpha1.KeptnEvaluationDefinition, *klcv1alpha1.KeptnEvaluationProvider, error) { evaluationDefinition := &klcv1alpha1.KeptnEvaluationDefinition{} - if err := r.Client.Get(ctx, namespace, evaluationDefinition); err != nil { + if err := r.Client.Get(ctx, namespacedDefinition, evaluationDefinition); err != nil { if errors.IsNotFound(err) { // taking down all associated K8s resources is handled by K8s r.Log.Info("KeptnEvaluationDefinition resource not found. Ignoring since object must be deleted") @@ -176,8 +177,9 @@ func (r KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Contex return nil, nil, err } + namespacedProvider := types.NamespacedName{Namespace: namespacedDefinition.Namespace, Name: evaluationDefinition.Spec.Source} evaluationProvider := &klcv1alpha1.KeptnEvaluationProvider{} - if err := r.Client.Get(ctx, namespace, evaluationProvider); err != nil { + if err := r.Client.Get(ctx, namespacedProvider, evaluationProvider); err != nil { if errors.IsNotFound(err) { // taking down all associated K8s resources is handled by K8s r.Log.Info("KeptnEvaluationProvider resource not found. Ignoring since object must be deleted") From c1052fd985913e29e842510535bbfe4c2712c7f5 Mon Sep 17 00:00:00 2001 From: RealAnna Date: Fri, 14 Oct 2022 12:35:58 +0200 Subject: [PATCH 10/29] chore: fixed queryEvaluation to always return false for now Signed-off-by: RealAnna --- .../controllers/keptnevaluation/controller.go | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index cba090d326..cad889293d 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -89,11 +89,15 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ } if !evaluation.Status.OverallStatus.IsCompleted() && evaluation.Status.RetryCount <= evaluation.Spec.Retries { - namespacedDefinition := types.NamespacedName{req.NamespacedName.Namespace, evaluation.Spec.EvaluationDefinition} + namespacedDefinition := types.NamespacedName{ + Namespace: req.NamespacedName.Namespace, + Name: evaluation.Spec.EvaluationDefinition, + } evaluationDefinition, evaluationProvider, err := r.fetchDefinitionAndProvider(ctx, namespacedDefinition) if err != nil { return ctrl.Result{Requeue: true, RequeueAfter: 30 * time.Second}, nil } + if evaluationDefinition == nil && evaluationProvider == nil { return ctrl.Result{}, nil } @@ -167,6 +171,7 @@ func (r *KeptnEvaluationReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Context, namespacedDefinition types.NamespacedName) (*klcv1alpha1.KeptnEvaluationDefinition, *klcv1alpha1.KeptnEvaluationProvider, error) { evaluationDefinition := &klcv1alpha1.KeptnEvaluationDefinition{} + if err := r.Client.Get(ctx, namespacedDefinition, evaluationDefinition); err != nil { if errors.IsNotFound(err) { // taking down all associated K8s resources is handled by K8s @@ -177,8 +182,13 @@ func (r KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Contex return nil, nil, err } - namespacedProvider := types.NamespacedName{Namespace: namespacedDefinition.Namespace, Name: evaluationDefinition.Spec.Source} + namespacedProvider := types.NamespacedName{ + Namespace: namespacedDefinition.Namespace, + Name: evaluationDefinition.Spec.Source, + } + evaluationProvider := &klcv1alpha1.KeptnEvaluationProvider{} + if err := r.Client.Get(ctx, namespacedProvider, evaluationProvider); err != nil { if errors.IsNotFound(err) { // taking down all associated K8s resources is handled by K8s @@ -196,11 +206,14 @@ func (r KeptnEvaluationReconciler) queryEvaluation(objective klcv1alpha1.Objecti query := &klcv1alpha1.EvaluationStatusItem{ Name: objective.Name, Value: "", - Status: "", + Status: common.StateFailed, //setting status per default to failed } - //TODO query provider like prometheus service does - //TODO decide and update status in query + //TODO query provider like prometheus service does, save result in value THIS SHALL BE SOLVED IN TICKET #163 + // will be something like + // import apiv1 "github.com/prometheus/client_golang/api/prometheus/v1" + // if provider ==prometheus { result, w, err := apiv1.PrometheusAPI.Query(context.TODO(), query, endUnix) if err != nil { return 0, fmt.Errorf("unable to query prometheus api: %w", err)}} + //TODO check value with evaluation target and update status in query return query } From 363c2a69e959a2600f6bde1fc99f367918a7e4a3 Mon Sep 17 00:00:00 2001 From: RealAnna Date: Fri, 14 Oct 2022 13:19:19 +0200 Subject: [PATCH 11/29] chore: added rebac and generated resources Signed-off-by: RealAnna --- operator/api/v1alpha1/keptnevaluation_types.go | 1 - .../bases/lifecycle.keptn.sh_keptnevaluations.yaml | 3 --- .../samples/lifecycle_v1alpha1_keptnevaluation.yaml | 3 ++- ...lifecycle_v1alpha1_keptnevaluationdefinition.yaml | 12 ++++++++++-- .../lifecycle_v1alpha1_keptnevaluationprovider.yaml | 5 +++-- operator/controllers/keptnevaluation/controller.go | 10 ++++++---- scheduler/manifests/install/kustomization.yaml | 4 ---- 7 files changed, 21 insertions(+), 17 deletions(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index efdad0280f..1203efdbaa 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -34,7 +34,6 @@ type KeptnEvaluationSpec struct { AppName string `json:"app,omitempty"` AppVersion string `json:"appVersion,omitempty"` EvaluationDefinition string `json:"evaluationDefinition"` - Source string `json:"source"` Timeframe time.Duration `json:"timeframe,omitempty"` Retries int `json:"retries,omitempty"` RetryInterval time.Duration `json:"retryInterval,omitempty"` diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index 5777e2e1fe..5ee1d680cb 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -55,8 +55,6 @@ spec: representable duration to approximately 290 years. format: int64 type: integer - source: - type: string timeframe: description: A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest @@ -69,7 +67,6 @@ spec: type: string required: - evaluationDefinition - - source - workloadVersion type: object status: diff --git a/operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml b/operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml index f99f801d19..8b533c9274 100644 --- a/operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml +++ b/operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml @@ -3,4 +3,5 @@ kind: KeptnEvaluation metadata: name: keptnevaluation-sample spec: - # TODO(user): Add fields here + evaluationDefinition: my-prometheus-definition #name of the KeptnEvaluationDefinition to use + workloadVersion: "1.3" diff --git a/operator/config/samples/lifecycle_v1alpha1_keptnevaluationdefinition.yaml b/operator/config/samples/lifecycle_v1alpha1_keptnevaluationdefinition.yaml index f72dcd9f7b..8e5ca8b459 100644 --- a/operator/config/samples/lifecycle_v1alpha1_keptnevaluationdefinition.yaml +++ b/operator/config/samples/lifecycle_v1alpha1_keptnevaluationdefinition.yaml @@ -1,6 +1,14 @@ apiVersion: lifecycle.keptn.sh/v1alpha1 kind: KeptnEvaluationDefinition metadata: - name: keptnevaluationdefinition-sample + name: my-prometheus-definition spec: - # TODO(user): Add fields here + source: prometheus + objectives: + - name: query-1 #string + query: "xxxx" #string: promQL query + evaluationTarget: <20 #string: can only be starting with < or > + - name: query-2 + query: "yyyy" + evaluationTarget: >4 + diff --git a/operator/config/samples/lifecycle_v1alpha1_keptnevaluationprovider.yaml b/operator/config/samples/lifecycle_v1alpha1_keptnevaluationprovider.yaml index 3c167a398b..9ba6060c90 100644 --- a/operator/config/samples/lifecycle_v1alpha1_keptnevaluationprovider.yaml +++ b/operator/config/samples/lifecycle_v1alpha1_keptnevaluationprovider.yaml @@ -1,6 +1,7 @@ apiVersion: lifecycle.keptn.sh/v1alpha1 kind: KeptnEvaluationProvider metadata: - name: keptnevaluationprovider-sample + name: prometheus spec: - # TODO(user): Add fields here + targetServer: "http://prometheus-k8s.monitoring.svc.cluster.local:9090" #string + secretName: prometheusLoginCredentials #secret name, optional diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index cad889293d..02789d2d20 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -50,6 +50,8 @@ type KeptnEvaluationReconciler struct { //+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluations,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluations/status,verbs=get;update;patch //+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluations/finalizers,verbs=update +//+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluationproviders,verbs=get +//+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluationdefinitions,verbs=get // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -169,7 +171,7 @@ func (r *KeptnEvaluationReconciler) SetupWithManager(mgr ctrl.Manager) error { Complete(r) } -func (r KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Context, namespacedDefinition types.NamespacedName) (*klcv1alpha1.KeptnEvaluationDefinition, *klcv1alpha1.KeptnEvaluationProvider, error) { +func (r *KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Context, namespacedDefinition types.NamespacedName) (*klcv1alpha1.KeptnEvaluationDefinition, *klcv1alpha1.KeptnEvaluationProvider, error) { evaluationDefinition := &klcv1alpha1.KeptnEvaluationDefinition{} if err := r.Client.Get(ctx, namespacedDefinition, evaluationDefinition); err != nil { @@ -202,7 +204,7 @@ func (r KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Contex return evaluationDefinition, evaluationProvider, nil } -func (r KeptnEvaluationReconciler) queryEvaluation(objective klcv1alpha1.Objective, provider klcv1alpha1.KeptnEvaluationProvider) *klcv1alpha1.EvaluationStatusItem { +func (r *KeptnEvaluationReconciler) queryEvaluation(objective klcv1alpha1.Objective, provider klcv1alpha1.KeptnEvaluationProvider) *klcv1alpha1.EvaluationStatusItem { query := &klcv1alpha1.EvaluationStatusItem{ Name: objective.Name, Value: "", @@ -210,9 +212,9 @@ func (r KeptnEvaluationReconciler) queryEvaluation(objective klcv1alpha1.Objecti } //TODO query provider like prometheus service does, save result in value THIS SHALL BE SOLVED IN TICKET #163 - // will be something like + // it will be something hardcoded like // import apiv1 "github.com/prometheus/client_golang/api/prometheus/v1" - // if provider ==prometheus { result, w, err := apiv1.PrometheusAPI.Query(context.TODO(), query, endUnix) if err != nil { return 0, fmt.Errorf("unable to query prometheus api: %w", err)}} + // if provider ==prometheus { result, w, err := apiv1.PrometheusAPI.Query(context.Background(), query, endUnix) if err != nil { return 0, fmt.Errorf("unable to query prometheus api: %w", err)}} //TODO check value with evaluation target and update status in query return query diff --git a/scheduler/manifests/install/kustomization.yaml b/scheduler/manifests/install/kustomization.yaml index 21e94a6f28..3a29ccbe72 100644 --- a/scheduler/manifests/install/kustomization.yaml +++ b/scheduler/manifests/install/kustomization.yaml @@ -1,18 +1,14 @@ namespace: keptn-lifecycle-controller-system - resources: - base/deployment.yaml - base/rbac.yaml - base/serviceaccount.yaml - generatorOptions: disableNameSuffixHash: true - configMapGenerator: - files: - base/scheduler-config.yaml name: scheduler-config - apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: From c99d8fc73db0cfdf6a0b77f37305bd8b42214c1a Mon Sep 17 00:00:00 2001 From: RealAnna Date: Fri, 14 Oct 2022 13:30:05 +0200 Subject: [PATCH 12/29] chore: added rebac and generated resources Signed-off-by: RealAnna --- operator/config/rbac/role.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/operator/config/rbac/role.yaml b/operator/config/rbac/role.yaml index e9ede34d06..dc3de66e39 100644 --- a/operator/config/rbac/role.yaml +++ b/operator/config/rbac/role.yaml @@ -144,6 +144,18 @@ rules: - get - patch - update +- apiGroups: + - lifecycle.keptn.sh + resources: + - keptnevaluationdefinitions + verbs: + - get +- apiGroups: + - lifecycle.keptn.sh + resources: + - keptnevaluationproviders + verbs: + - get - apiGroups: - lifecycle.keptn.sh resources: From c60978002d14b3f58ad682702666d2d3ede78ca7 Mon Sep 17 00:00:00 2001 From: RealAnna Date: Fri, 14 Oct 2022 13:38:04 +0200 Subject: [PATCH 13/29] chore: fixed copypasta Signed-off-by: RealAnna --- operator/config/rbac/role.yaml | 4 ++++ operator/controllers/keptnevaluation/controller.go | 4 ++-- operator/main.go | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/operator/config/rbac/role.yaml b/operator/config/rbac/role.yaml index dc3de66e39..b95972b03f 100644 --- a/operator/config/rbac/role.yaml +++ b/operator/config/rbac/role.yaml @@ -150,12 +150,16 @@ rules: - keptnevaluationdefinitions verbs: - get + - list + - watch - apiGroups: - lifecycle.keptn.sh resources: - keptnevaluationproviders verbs: - get + - list + - watch - apiGroups: - lifecycle.keptn.sh resources: diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index 02789d2d20..3a3808a836 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -50,8 +50,8 @@ type KeptnEvaluationReconciler struct { //+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluations,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluations/status,verbs=get;update;patch //+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluations/finalizers,verbs=update -//+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluationproviders,verbs=get -//+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluationdefinitions,verbs=get +//+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluationproviders,verbs=get;list;watch +//+kubebuilder:rbac:groups=lifecycle.keptn.sh,resources=keptnevaluationdefinitions,verbs=get;list;watch // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. diff --git a/operator/main.go b/operator/main.go index 461fbf91b4..5baa8db795 100644 --- a/operator/main.go +++ b/operator/main.go @@ -310,9 +310,9 @@ func main() { if err = (&keptnevaluation.KeptnEvaluationReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Log: ctrl.Log.WithName("KeptnAppVersion Controller"), - Recorder: mgr.GetEventRecorderFor("keptnappversion-controller"), - Tracer: otel.Tracer("keptn/operator/appversion"), + Log: ctrl.Log.WithName("KeptnEvaluation Controller"), + Recorder: mgr.GetEventRecorderFor("keptnevaluation-controller"), + Tracer: otel.Tracer("keptn/operator/evaluation"), Meters: meters, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "KeptnEvaluation") From 03ad5390cf83b41a969454f7c541a89a683f0dfa Mon Sep 17 00:00:00 2001 From: RealAnna Date: Fri, 14 Oct 2022 13:56:49 +0200 Subject: [PATCH 14/29] feat: added few events ordered controller Signed-off-by: RealAnna --- .../controllers/keptnevaluation/controller.go | 64 +++++++++++-------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index 3a3808a836..30c4f1c115 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -18,6 +18,7 @@ package keptnevaluation import ( "context" + "fmt" "time" "go.opentelemetry.io/otel" @@ -122,46 +123,53 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ evaluation.Status.RetryCount++ evaluation.Status.OverallStatus = common.GetOverallState(statusSummary) - } - err := r.Client.Status().Update(ctx, evaluation) - if err != nil { - span.SetStatus(codes.Error, err.Error()) - return ctrl.Result{Requeue: true}, err } - if !evaluation.Status.OverallStatus.IsCompleted() { - return ctrl.Result{Requeue: true, RequeueAfter: evaluation.Spec.RetryInterval * time.Second}, nil - } + if evaluation.Status.OverallStatus.IsCompleted() { - r.Log.Info("Finished Reconciling KeptnEvaluation") + r.Log.Info("Finished Reconciling KeptnEvaluation") + + if !evaluation.IsEndTimeSet() { + // metrics: decrement active evaluation counter + r.Meters.AnalysisActive.Add(ctx, -1, evaluation.GetActiveMetricsAttributes()...) + evaluation.SetEndTime() + } + + err := r.Client.Status().Update(ctx, evaluation) + if err != nil { + span.SetStatus(codes.Error, err.Error()) + r.recordEvent("Warning", evaluation, "ReconcileErrored", "could not update status") + return ctrl.Result{Requeue: true}, err + } - // Evaluation is completed at this place + r.recordEvent("Normal", evaluation, string(evaluation.Status.OverallStatus), "the evaluation has "+string(evaluation.Status.OverallStatus)) - if !evaluation.IsEndTimeSet() { - // metrics: decrement active evaluation counter - r.Meters.AnalysisActive.Add(ctx, -1, evaluation.GetActiveMetricsAttributes()...) - evaluation.SetEndTime() + attrs := evaluation.GetMetricsAttributes() + + r.Log.Info("Increasing evaluation count") + + // metrics: increment evaluation counter + r.Meters.AnalysisCount.Add(ctx, 1, attrs...) + + // metrics: add evaluation duration + duration := evaluation.Status.EndTime.Time.Sub(evaluation.Status.StartTime.Time) + r.Meters.AnalysisDuration.Record(ctx, duration.Seconds(), attrs...) + + return ctrl.Result{}, nil } - err = r.Client.Status().Update(ctx, evaluation) + // Evaluation is uncompleted , update status anyway + err := r.Client.Status().Update(ctx, evaluation) if err != nil { + r.recordEvent("Warning", evaluation, "ReconcileErrored", "could not update status") span.SetStatus(codes.Error, err.Error()) return ctrl.Result{Requeue: true}, err } - attrs := evaluation.GetMetricsAttributes() + r.recordEvent("Warning", evaluation, "NotFinished", "has not finished") - r.Log.Info("Increasing evaluation count") - - // metrics: increment evaluation counter - r.Meters.AnalysisCount.Add(ctx, 1, attrs...) - - // metrics: add evaluation duration - duration := evaluation.Status.EndTime.Time.Sub(evaluation.Status.StartTime.Time) - r.Meters.AnalysisDuration.Record(ctx, duration.Seconds(), attrs...) - - return ctrl.Result{}, nil + return ctrl.Result{Requeue: true, RequeueAfter: evaluation.Spec.RetryInterval * time.Second}, nil } // SetupWithManager sets up the controller with the Manager. @@ -219,3 +227,7 @@ func (r *KeptnEvaluationReconciler) queryEvaluation(objective klcv1alpha1.Object return query } + +func (r *KeptnEvaluationReconciler) recordEvent(eventType string, evaluation *klcv1alpha1.KeptnEvaluation, shortReason string, longReason string) { + r.Recorder.Event(evaluation, eventType, shortReason, fmt.Sprintf("%s / Namespace: %s, Name: %s, WorkloadVersion: %s ", longReason, evaluation.Namespace, evaluation.Name, evaluation.Spec.WorkloadVersion)) +} From 2d42716df5d9f110638284da2d28cc5e2530769c Mon Sep 17 00:00:00 2001 From: RealAnna Date: Fri, 14 Oct 2022 14:00:36 +0200 Subject: [PATCH 15/29] feat: added few events ordered controller Signed-off-by: RealAnna --- .../controllers/keptnevaluation/controller.go | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index 30c4f1c115..cc5c4629a7 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -126,50 +126,51 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ } - if evaluation.Status.OverallStatus.IsCompleted() { - - r.Log.Info("Finished Reconciling KeptnEvaluation") - - if !evaluation.IsEndTimeSet() { - // metrics: decrement active evaluation counter - r.Meters.AnalysisActive.Add(ctx, -1, evaluation.GetActiveMetricsAttributes()...) - evaluation.SetEndTime() - } - + if !evaluation.Status.OverallStatus.IsCompleted() { + // Evaluation is uncompleted, update status anyway this avoids updating twice in case of completion err := r.Client.Status().Update(ctx, evaluation) if err != nil { - span.SetStatus(codes.Error, err.Error()) r.recordEvent("Warning", evaluation, "ReconcileErrored", "could not update status") + span.SetStatus(codes.Error, err.Error()) return ctrl.Result{Requeue: true}, err } - r.recordEvent("Normal", evaluation, string(evaluation.Status.OverallStatus), "the evaluation has "+string(evaluation.Status.OverallStatus)) + r.recordEvent("Warning", evaluation, "NotFinished", "has not finished") - attrs := evaluation.GetMetricsAttributes() + return ctrl.Result{Requeue: true, RequeueAfter: evaluation.Spec.RetryInterval * time.Second}, nil - r.Log.Info("Increasing evaluation count") - - // metrics: increment evaluation counter - r.Meters.AnalysisCount.Add(ctx, 1, attrs...) + } - // metrics: add evaluation duration - duration := evaluation.Status.EndTime.Time.Sub(evaluation.Status.StartTime.Time) - r.Meters.AnalysisDuration.Record(ctx, duration.Seconds(), attrs...) + r.Log.Info("Finished Reconciling KeptnEvaluation") - return ctrl.Result{}, nil + if !evaluation.IsEndTimeSet() { + // metrics: decrement active evaluation counter + r.Meters.AnalysisActive.Add(ctx, -1, evaluation.GetActiveMetricsAttributes()...) + evaluation.SetEndTime() } - // Evaluation is uncompleted , update status anyway err := r.Client.Status().Update(ctx, evaluation) if err != nil { - r.recordEvent("Warning", evaluation, "ReconcileErrored", "could not update status") span.SetStatus(codes.Error, err.Error()) + r.recordEvent("Warning", evaluation, "ReconcileErrored", "could not update status") return ctrl.Result{Requeue: true}, err } - r.recordEvent("Warning", evaluation, "NotFinished", "has not finished") + r.recordEvent("Normal", evaluation, string(evaluation.Status.OverallStatus), "the evaluation has "+string(evaluation.Status.OverallStatus)) + + attrs := evaluation.GetMetricsAttributes() + + r.Log.Info("Increasing evaluation count") + + // metrics: increment evaluation counter + r.Meters.AnalysisCount.Add(ctx, 1, attrs...) + + // metrics: add evaluation duration + duration := evaluation.Status.EndTime.Time.Sub(evaluation.Status.StartTime.Time) + r.Meters.AnalysisDuration.Record(ctx, duration.Seconds(), attrs...) + + return ctrl.Result{}, nil - return ctrl.Result{Requeue: true, RequeueAfter: evaluation.Spec.RetryInterval * time.Second}, nil } // SetupWithManager sets up the controller with the Manager. From 3884cb4986ec86161191cdc7d61dc6624fd686b9 Mon Sep 17 00:00:00 2001 From: odubajDT Date: Mon, 17 Oct 2022 07:17:13 +0200 Subject: [PATCH 16/29] implement timeFrame and retryCount functionality Signed-off-by: odubajDT --- operator/api/v1alpha1/keptnevaluation_types.go | 8 +++++--- .../bases/lifecycle.keptn.sh_keptnevaluations.yaml | 2 ++ operator/controllers/keptnevaluation/controller.go | 12 ++++++++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index 1203efdbaa..4a2ddda26f 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -43,11 +43,13 @@ type KeptnEvaluationSpec struct { // KeptnEvaluationStatus defines the observed state of KeptnEvaluation type KeptnEvaluationStatus struct { + // +kubebuilder:default:=0 RetryCount int `json:"retryCount"` EvaluationStatus []EvaluationStatusItem `json:"evaluationStatus"` - OverallStatus common.KeptnState `json:"overallStatus"` - StartTime metav1.Time `json:"startTime,omitempty"` - EndTime metav1.Time `json:"endTime,omitempty"` + // +kubebuilder:default:=Pending + OverallStatus common.KeptnState `json:"overallStatus"` + StartTime metav1.Time `json:"startTime,omitempty"` + EndTime metav1.Time `json:"endTime,omitempty"` } type EvaluationStatusItem struct { diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index 5ee1d680cb..8f7c3aae2f 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -91,8 +91,10 @@ spec: type: object type: array overallStatus: + default: Pending type: string retryCount: + default: 0 type: integer startTime: format: date-time diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index cc5c4629a7..729ce9198b 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -91,7 +91,15 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ evaluation.SetStartTime() } - if !evaluation.Status.OverallStatus.IsCompleted() && evaluation.Status.RetryCount <= evaluation.Spec.Retries { + currentDuration := time.Now().UTC().Sub(evaluation.Status.StartTime.Time) + if evaluation.Status.RetryCount >= evaluation.Spec.Retries || currentDuration > evaluation.Spec.Timeframe { + r.recordEvent("Warning", evaluation, "ReconcileTimeOut", "timeOut or retryCount exceeded") + err := fmt.Errorf("TimeOut or retryCount for evaluation exceeded") + span.SetStatus(codes.Error, err.Error()) + return ctrl.Result{}, err + } + + if !evaluation.Status.OverallStatus.IsCompleted() { namespacedDefinition := types.NamespacedName{ Namespace: req.NamespacedName.Namespace, Name: evaluation.Spec.EvaluationDefinition, @@ -137,7 +145,7 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ r.recordEvent("Warning", evaluation, "NotFinished", "has not finished") - return ctrl.Result{Requeue: true, RequeueAfter: evaluation.Spec.RetryInterval * time.Second}, nil + return ctrl.Result{Requeue: true, RequeueAfter: evaluation.Spec.RetryInterval}, nil } From c928f1bac807c2a09e87abd52d161195c270c9a7 Mon Sep 17 00:00:00 2001 From: odubajDT Date: Mon, 17 Oct 2022 07:22:24 +0200 Subject: [PATCH 17/29] polish duration Signed-off-by: odubajDT --- .../api/v1alpha1/keptnevaluation_types.go | 21 ++++++++++--------- .../api/v1alpha1/zz_generated.deepcopy.go | 2 ++ .../lifecycle.keptn.sh_keptnevaluations.yaml | 13 +++--------- .../controllers/keptnevaluation/controller.go | 4 ++-- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index 4a2ddda26f..93ea75b453 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -29,16 +29,17 @@ import ( // KeptnEvaluationSpec defines the desired state of KeptnEvaluation type KeptnEvaluationSpec struct { - Workload string `json:"workload,omitempty"` - WorkloadVersion string `json:"workloadVersion"` - AppName string `json:"app,omitempty"` - AppVersion string `json:"appVersion,omitempty"` - EvaluationDefinition string `json:"evaluationDefinition"` - Timeframe time.Duration `json:"timeframe,omitempty"` - Retries int `json:"retries,omitempty"` - RetryInterval time.Duration `json:"retryInterval,omitempty"` - FailAction string `json:"failAction,omitempty"` - Type common.CheckType `json:"checkType,omitempty"` + Workload string `json:"workload,omitempty"` + WorkloadVersion string `json:"workloadVersion"` + AppName string `json:"app,omitempty"` + AppVersion string `json:"appVersion,omitempty"` + EvaluationDefinition string `json:"evaluationDefinition"` + Timeframe metav1.Duration `json:"timeframe,omitempty"` + // +kubebuilder:default:=10 + Retries int `json:"retries,omitempty"` + RetryInterval metav1.Duration `json:"retryInterval,omitempty"` + FailAction string `json:"failAction,omitempty"` + Type common.CheckType `json:"checkType,omitempty"` } // KeptnEvaluationStatus defines the observed state of KeptnEvaluation diff --git a/operator/api/v1alpha1/zz_generated.deepcopy.go b/operator/api/v1alpha1/zz_generated.deepcopy.go index 94d270a9b6..30cd9d075c 100644 --- a/operator/api/v1alpha1/zz_generated.deepcopy.go +++ b/operator/api/v1alpha1/zz_generated.deepcopy.go @@ -621,6 +621,8 @@ func (in *KeptnEvaluationProviderStatus) DeepCopy() *KeptnEvaluationProviderStat // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeptnEvaluationSpec) DeepCopyInto(out *KeptnEvaluationSpec) { *out = *in + out.Timeframe = in.Timeframe + out.RetryInterval = in.RetryInterval } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeptnEvaluationSpec. diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index 8f7c3aae2f..9e0ca9d295 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -48,19 +48,12 @@ spec: failAction: type: string retries: + default: 10 type: integer retryInterval: - description: A Duration represents the elapsed time between two instants - as an int64 nanosecond count. The representation limits the largest - representable duration to approximately 290 years. - format: int64 - type: integer + type: string timeframe: - description: A Duration represents the elapsed time between two instants - as an int64 nanosecond count. The representation limits the largest - representable duration to approximately 290 years. - format: int64 - type: integer + type: string workload: type: string workloadVersion: diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index 729ce9198b..3e939fd225 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -92,7 +92,7 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ } currentDuration := time.Now().UTC().Sub(evaluation.Status.StartTime.Time) - if evaluation.Status.RetryCount >= evaluation.Spec.Retries || currentDuration > evaluation.Spec.Timeframe { + if evaluation.Status.RetryCount >= evaluation.Spec.Retries || currentDuration > evaluation.Spec.Timeframe.Duration { r.recordEvent("Warning", evaluation, "ReconcileTimeOut", "timeOut or retryCount exceeded") err := fmt.Errorf("TimeOut or retryCount for evaluation exceeded") span.SetStatus(codes.Error, err.Error()) @@ -145,7 +145,7 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ r.recordEvent("Warning", evaluation, "NotFinished", "has not finished") - return ctrl.Result{Requeue: true, RequeueAfter: evaluation.Spec.RetryInterval}, nil + return ctrl.Result{Requeue: true, RequeueAfter: evaluation.Spec.RetryInterval.Duration}, nil } From c194d391484caa0bfccaff8a0bdba494b8800b3e Mon Sep 17 00:00:00 2001 From: RealAnna Date: Mon, 17 Oct 2022 08:47:32 +0200 Subject: [PATCH 18/29] feat: added print app version and status Signed-off-by: RealAnna --- operator/api/v1alpha1/keptnevaluation_types.go | 4 ++++ .../lifecycle.keptn.sh_keptnevaluations.yaml | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index 93ea75b453..32fdb2d6d6 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -62,6 +62,10 @@ type EvaluationStatusItem struct { //+kubebuilder:object:root=true //+kubebuilder:subresource:status //+kubebuilder:resource:path=keptnevaluations,shortName=ke +//+kubebuilder:printcolumn:name="AppName",type=string,JSONPath=`.spec.appName` +// +kubebuilder:printcolumn:name="AppVersion",type=string,JSONPath=`.spec.appVersion` +// +kubebuilder:printcolumn:name="EvaluationStatus",type=string,JSONPath=`.status.evaluationStatus` +// +kubebuilder:printcolumn:name="OverallStatus",type=string,JSONPath=`.status.overallStatus` // KeptnEvaluation is the Schema for the keptnevaluations API type KeptnEvaluation struct { diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index 9e0ca9d295..718416b732 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -17,7 +17,20 @@ spec: singular: keptnevaluation scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .spec.appName + name: AppName + type: string + - jsonPath: .spec.appVersion + name: AppVersion + type: string + - jsonPath: .status.evaluationStatus + name: EvaluationStatus + type: string + - jsonPath: .status.overallStatus + name: OverallStatus + type: string + name: v1alpha1 schema: openAPIV3Schema: description: KeptnEvaluation is the Schema for the keptnevaluations API From 9dea1c5f35d9a5969083608fccea5a69c8f261ce Mon Sep 17 00:00:00 2001 From: RealAnna Date: Mon, 17 Oct 2022 08:53:37 +0200 Subject: [PATCH 19/29] feat: added default timeframe Signed-off-by: RealAnna --- operator/api/v1alpha1/keptnevaluation_types.go | 13 +++++++------ operator/config/manager/kustomization.yaml | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index 32fdb2d6d6..e7ce3a9ca5 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -29,12 +29,13 @@ import ( // KeptnEvaluationSpec defines the desired state of KeptnEvaluation type KeptnEvaluationSpec struct { - Workload string `json:"workload,omitempty"` - WorkloadVersion string `json:"workloadVersion"` - AppName string `json:"app,omitempty"` - AppVersion string `json:"appVersion,omitempty"` - EvaluationDefinition string `json:"evaluationDefinition"` - Timeframe metav1.Duration `json:"timeframe,omitempty"` + Workload string `json:"workload,omitempty"` + WorkloadVersion string `json:"workloadVersion"` + AppName string `json:"app,omitempty"` + AppVersion string `json:"appVersion,omitempty"` + EvaluationDefinition string `json:"evaluationDefinition"` + // +kubebuilder:default:=30s + Timeframe metav1.Duration `json:"timeframe,omitempty"` // +kubebuilder:default:=10 Retries int `json:"retries,omitempty"` RetryInterval metav1.Duration `json:"retryInterval,omitempty"` diff --git a/operator/config/manager/kustomization.yaml b/operator/config/manager/kustomization.yaml index f061866560..dd898decfc 100644 --- a/operator/config/manager/kustomization.yaml +++ b/operator/config/manager/kustomization.yaml @@ -10,5 +10,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: controller - newName: docker.io/thschue/keptn-lifecycle-operator - newTag: "202210131665678206" + newName: docker.io/annadreal/keptn-lifecycle-operator + newTag: "202210171665989220" From 460096129fdd01e0bb18e9713229e1fc59ce0e80 Mon Sep 17 00:00:00 2001 From: RealAnna Date: Mon, 17 Oct 2022 08:59:18 +0200 Subject: [PATCH 20/29] feat: added default timeframe Signed-off-by: RealAnna --- operator/api/v1alpha1/keptnevaluation_types.go | 2 +- .../config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index e7ce3a9ca5..112dbf5331 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -34,7 +34,7 @@ type KeptnEvaluationSpec struct { AppName string `json:"app,omitempty"` AppVersion string `json:"appVersion,omitempty"` EvaluationDefinition string `json:"evaluationDefinition"` - // +kubebuilder:default:=30s + // +kubebuilder:default:=30 Timeframe metav1.Duration `json:"timeframe,omitempty"` // +kubebuilder:default:=10 Retries int `json:"retries,omitempty"` diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index 718416b732..99ad2aa9fc 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -66,6 +66,7 @@ spec: retryInterval: type: string timeframe: + default: 30 type: string workload: type: string From fe030eb2bb1cfda52ae90214715513a3f27b7d61 Mon Sep 17 00:00:00 2001 From: RealAnna Date: Mon, 17 Oct 2022 09:25:43 +0200 Subject: [PATCH 21/29] feat: added default timeframe Signed-off-by: RealAnna --- operator/api/v1alpha1/keptnevaluation_types.go | 6 +++++- operator/config/manager/kustomization.yaml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index 112dbf5331..7ecc05d633 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -34,7 +34,11 @@ type KeptnEvaluationSpec struct { AppName string `json:"app,omitempty"` AppVersion string `json:"appVersion,omitempty"` EvaluationDefinition string `json:"evaluationDefinition"` - // +kubebuilder:default:=30 + // +optional + // +kubebuilder:default:="30s" + // +kubebuilder:validation:Pattern="^0|([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$" + // +kubebuilder:validation:Type:=string + // +optional Timeframe metav1.Duration `json:"timeframe,omitempty"` // +kubebuilder:default:=10 Retries int `json:"retries,omitempty"` diff --git a/operator/config/manager/kustomization.yaml b/operator/config/manager/kustomization.yaml index dd898decfc..6cf87400ce 100644 --- a/operator/config/manager/kustomization.yaml +++ b/operator/config/manager/kustomization.yaml @@ -11,4 +11,4 @@ kind: Kustomization images: - name: controller newName: docker.io/annadreal/keptn-lifecycle-operator - newTag: "202210171665989220" + newTag: "202210171665989897" From fff6e4d516dc0e51b230ab06df4bce809690d97e Mon Sep 17 00:00:00 2001 From: RealAnna Date: Mon, 17 Oct 2022 09:30:22 +0200 Subject: [PATCH 22/29] feat: added default timeframe Signed-off-by: RealAnna --- .../config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml | 3 ++- operator/config/manager/kustomization.yaml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index 99ad2aa9fc..848166676a 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -66,7 +66,8 @@ spec: retryInterval: type: string timeframe: - default: 30 + default: 30s + pattern: ^0|([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$ type: string workload: type: string diff --git a/operator/config/manager/kustomization.yaml b/operator/config/manager/kustomization.yaml index 6cf87400ce..f091367ec9 100644 --- a/operator/config/manager/kustomization.yaml +++ b/operator/config/manager/kustomization.yaml @@ -11,4 +11,4 @@ kind: Kustomization images: - name: controller newName: docker.io/annadreal/keptn-lifecycle-operator - newTag: "202210171665989897" + newTag: "202210171665991591" From 4fc2322956f88d50c9a76816031627a6c0b09d37 Mon Sep 17 00:00:00 2001 From: RealAnna Date: Mon, 17 Oct 2022 09:39:20 +0200 Subject: [PATCH 23/29] feat: added default timeframe Signed-off-by: RealAnna --- operator/api/v1alpha1/keptnevaluation_types.go | 7 ++++++- .../crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index 7ecc05d633..eed9b5ba45 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -41,7 +41,12 @@ type KeptnEvaluationSpec struct { // +optional Timeframe metav1.Duration `json:"timeframe,omitempty"` // +kubebuilder:default:=10 - Retries int `json:"retries,omitempty"` + Retries int `json:"retries,omitempty"` + // +optional + // +kubebuilder:default:="5s" + // +kubebuilder:validation:Pattern="^0|([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$" + // +kubebuilder:validation:Type:=string + // +optional RetryInterval metav1.Duration `json:"retryInterval,omitempty"` FailAction string `json:"failAction,omitempty"` Type common.CheckType `json:"checkType,omitempty"` diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index 848166676a..42f253691f 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -64,6 +64,8 @@ spec: default: 10 type: integer retryInterval: + default: 5s + pattern: ^0|([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$ type: string timeframe: default: 30s From 6b5adf3be8e1fba4625af4892cc61824860d716d Mon Sep 17 00:00:00 2001 From: RealAnna Date: Mon, 17 Oct 2022 10:30:22 +0200 Subject: [PATCH 24/29] feat: added endtime in case of failure, change status to map in evaluation Signed-off-by: RealAnna --- .../api/v1alpha1/keptnevaluation_types.go | 20 +++++----- .../api/v1alpha1/zz_generated.deepcopy.go | 6 ++- .../lifecycle.keptn.sh_keptnevaluations.yaml | 9 ++--- operator/config/manager/kustomization.yaml | 2 +- .../controllers/keptnevaluation/controller.go | 40 ++++++++++++------- operator/go.mod | 3 +- operator/go.sum | 6 ++- 7 files changed, 48 insertions(+), 38 deletions(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index eed9b5ba45..a5093e482e 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -35,7 +35,7 @@ type KeptnEvaluationSpec struct { AppVersion string `json:"appVersion,omitempty"` EvaluationDefinition string `json:"evaluationDefinition"` // +optional - // +kubebuilder:default:="30s" + // +kubebuilder:default:="2m" // +kubebuilder:validation:Pattern="^0|([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$" // +kubebuilder:validation:Type:=string // +optional @@ -55,8 +55,8 @@ type KeptnEvaluationSpec struct { // KeptnEvaluationStatus defines the observed state of KeptnEvaluation type KeptnEvaluationStatus struct { // +kubebuilder:default:=0 - RetryCount int `json:"retryCount"` - EvaluationStatus []EvaluationStatusItem `json:"evaluationStatus"` + RetryCount int `json:"retryCount"` + EvaluationStatus map[string]EvaluationStatusItem `json:"evaluationStatus"` // +kubebuilder:default:=Pending OverallStatus common.KeptnState `json:"overallStatus"` StartTime metav1.Time `json:"startTime,omitempty"` @@ -64,7 +64,6 @@ type KeptnEvaluationStatus struct { } type EvaluationStatusItem struct { - Name string `json:"name"` Value string `json:"value"` Status common.KeptnState `json:"status"` } @@ -142,12 +141,11 @@ func (i KeptnEvaluation) GetMetricsAttributes() []attribute.KeyValue { } } -func (e *KeptnEvaluation) InitializeEvaluationStatuses(definition KeptnEvaluationDefinition) { - for _, query := range definition.Spec.Objectives { - evaluationStatusItem := EvaluationStatusItem{ - Name: query.Name, - Status: common.StatePending, - } - e.Status.EvaluationStatus = append(e.Status.EvaluationStatus, evaluationStatusItem) +func (e *KeptnEvaluation) AddEvaluationStatus(objective Objective) { + + evaluationStatusItem := EvaluationStatusItem{ + Status: common.StatePending, } + e.Status.EvaluationStatus[objective.Name] = evaluationStatusItem + } diff --git a/operator/api/v1alpha1/zz_generated.deepcopy.go b/operator/api/v1alpha1/zz_generated.deepcopy.go index 30cd9d075c..2e407eef78 100644 --- a/operator/api/v1alpha1/zz_generated.deepcopy.go +++ b/operator/api/v1alpha1/zz_generated.deepcopy.go @@ -640,8 +640,10 @@ func (in *KeptnEvaluationStatus) DeepCopyInto(out *KeptnEvaluationStatus) { *out = *in if in.EvaluationStatus != nil { in, out := &in.EvaluationStatus, &out.EvaluationStatus - *out = make([]EvaluationStatusItem, len(*in)) - copy(*out, *in) + *out = make(map[string]EvaluationStatusItem, len(*in)) + for key, val := range *in { + (*out)[key] = val + } } in.StartTime.DeepCopyInto(&out.StartTime) in.EndTime.DeepCopyInto(&out.EndTime) diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index 42f253691f..ae2c09fe36 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -68,7 +68,7 @@ spec: pattern: ^0|([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$ type: string timeframe: - default: 30s + default: 2m pattern: ^0|([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$ type: string workload: @@ -86,20 +86,17 @@ spec: format: date-time type: string evaluationStatus: - items: + additionalProperties: properties: - name: - type: string status: type: string value: type: string required: - - name - status - value type: object - type: array + type: object overallStatus: default: Pending type: string diff --git a/operator/config/manager/kustomization.yaml b/operator/config/manager/kustomization.yaml index f091367ec9..ec9be7054a 100644 --- a/operator/config/manager/kustomization.yaml +++ b/operator/config/manager/kustomization.yaml @@ -11,4 +11,4 @@ kind: Kustomization images: - name: controller newName: docker.io/annadreal/keptn-lifecycle-operator - newTag: "202210171665991591" + newTag: "202210171665994530" diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index 3e939fd225..d6e6225e66 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -96,10 +96,11 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ r.recordEvent("Warning", evaluation, "ReconcileTimeOut", "timeOut or retryCount exceeded") err := fmt.Errorf("TimeOut or retryCount for evaluation exceeded") span.SetStatus(codes.Error, err.Error()) + r.updateFinishedEvaluationMetrics(ctx, evaluation) return ctrl.Result{}, err } - if !evaluation.Status.OverallStatus.IsCompleted() { + if !evaluation.Status.OverallStatus.IsSucceeded() { namespacedDefinition := types.NamespacedName{ Namespace: req.NamespacedName.Namespace, Name: evaluation.Spec.EvaluationDefinition, @@ -109,32 +110,38 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{Requeue: true, RequeueAfter: 30 * time.Second}, nil } - if evaluationDefinition == nil && evaluationProvider == nil { + if evaluationDefinition == nil || evaluationProvider == nil { return ctrl.Result{}, nil } - if len(evaluation.Status.EvaluationStatus) != len(evaluationDefinition.Spec.Objectives) { - evaluation.InitializeEvaluationStatuses(*evaluationDefinition) - } - statusSummary := common.StatusSummary{} + newStatus := make(map[string]klcv1alpha1.EvaluationStatusItem) + + if evaluation.Status.EvaluationStatus == nil { + evaluation.Status.EvaluationStatus = make(map[string]klcv1alpha1.EvaluationStatusItem) + } - for i, query := range evaluationDefinition.Spec.Objectives { - if evaluation.Status.EvaluationStatus[i].Status.IsSucceeded() { + for _, query := range evaluationDefinition.Spec.Objectives { + if _, ok := evaluation.Status.EvaluationStatus[query.Name]; !ok { + evaluation.AddEvaluationStatus(query) + } + if evaluation.Status.EvaluationStatus[query.Name].Status.IsSucceeded() { statusSummary = common.UpdateStatusSummary(common.StateSucceeded, statusSummary) + newStatus[query.Name] = evaluation.Status.EvaluationStatus[query.Name] continue } statusItem := r.queryEvaluation(query, *evaluationProvider) statusSummary = common.UpdateStatusSummary(statusItem.Status, statusSummary) - evaluation.Status.EvaluationStatus[i] = *statusItem + newStatus[query.Name] = *statusItem } evaluation.Status.RetryCount++ + evaluation.Status.EvaluationStatus = newStatus evaluation.Status.OverallStatus = common.GetOverallState(statusSummary) } - if !evaluation.Status.OverallStatus.IsCompleted() { + if !evaluation.Status.OverallStatus.IsSucceeded() { // Evaluation is uncompleted, update status anyway this avoids updating twice in case of completion err := r.Client.Status().Update(ctx, evaluation) if err != nil { @@ -143,7 +150,7 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{Requeue: true}, err } - r.recordEvent("Warning", evaluation, "NotFinished", "has not finished") + r.recordEvent("Normal", evaluation, "NotFinished", "has not finished") return ctrl.Result{Requeue: true, RequeueAfter: evaluation.Spec.RetryInterval.Duration}, nil @@ -164,6 +171,13 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{Requeue: true}, err } + r.updateFinishedEvaluationMetrics(ctx, evaluation) + + return ctrl.Result{}, nil + +} + +func (r *KeptnEvaluationReconciler) updateFinishedEvaluationMetrics(ctx context.Context, evaluation *klcv1alpha1.KeptnEvaluation) { r.recordEvent("Normal", evaluation, string(evaluation.Status.OverallStatus), "the evaluation has "+string(evaluation.Status.OverallStatus)) attrs := evaluation.GetMetricsAttributes() @@ -176,9 +190,6 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ // metrics: add evaluation duration duration := evaluation.Status.EndTime.Time.Sub(evaluation.Status.StartTime.Time) r.Meters.AnalysisDuration.Record(ctx, duration.Seconds(), attrs...) - - return ctrl.Result{}, nil - } // SetupWithManager sets up the controller with the Manager. @@ -223,7 +234,6 @@ func (r *KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Conte func (r *KeptnEvaluationReconciler) queryEvaluation(objective klcv1alpha1.Objective, provider klcv1alpha1.KeptnEvaluationProvider) *klcv1alpha1.EvaluationStatusItem { query := &klcv1alpha1.EvaluationStatusItem{ - Name: objective.Name, Value: "", Status: common.StateFailed, //setting status per default to failed } diff --git a/operator/go.mod b/operator/go.mod index a33f0fb518..d20a114ba5 100644 --- a/operator/go.mod +++ b/operator/go.mod @@ -19,6 +19,7 @@ require ( go.opentelemetry.io/otel/sdk v1.10.0 go.opentelemetry.io/otel/sdk/metric v0.32.1 go.opentelemetry.io/otel/trace v1.10.0 + golang.org/x/exp v0.0.0-20221012211006-4de253d81b95 google.golang.org/grpc v1.46.2 k8s.io/api v0.24.2 k8s.io/apimachinery v0.24.2 @@ -79,7 +80,7 @@ require ( golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect - golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect diff --git a/operator/go.sum b/operator/go.sum index d8b4fc14d5..420c26fa65 100644 --- a/operator/go.sum +++ b/operator/go.sum @@ -581,6 +581,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20221012211006-4de253d81b95 h1:sBdrWpxhGDdTAYNqbgBLAR+ULAPPhfgncLr1X0lyWtg= +golang.org/x/exp v0.0.0-20221012211006-4de253d81b95/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -750,8 +752,8 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= From a3672f5ec7e836b9a44751cf371f36c2d72061f9 Mon Sep 17 00:00:00 2001 From: RealAnna Date: Mon, 17 Oct 2022 11:24:50 +0200 Subject: [PATCH 25/29] feat: added endtime in case of failure, change status to map in evaluation Signed-off-by: RealAnna --- .../api/v1alpha1/keptnevaluation_types.go | 6 --- .../api/v1alpha1/zz_generated.deepcopy.go | 1 - .../lifecycle.keptn.sh_keptnevaluations.yaml | 4 -- operator/config/manager/kustomization.yaml | 2 +- .../lifecycle_v1alpha1_keptnevaluation.yaml | 1 + .../controllers/keptnevaluation/controller.go | 45 +++++++++++-------- 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/operator/api/v1alpha1/keptnevaluation_types.go b/operator/api/v1alpha1/keptnevaluation_types.go index a5093e482e..afb9e88b87 100644 --- a/operator/api/v1alpha1/keptnevaluation_types.go +++ b/operator/api/v1alpha1/keptnevaluation_types.go @@ -34,12 +34,6 @@ type KeptnEvaluationSpec struct { AppName string `json:"app,omitempty"` AppVersion string `json:"appVersion,omitempty"` EvaluationDefinition string `json:"evaluationDefinition"` - // +optional - // +kubebuilder:default:="2m" - // +kubebuilder:validation:Pattern="^0|([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$" - // +kubebuilder:validation:Type:=string - // +optional - Timeframe metav1.Duration `json:"timeframe,omitempty"` // +kubebuilder:default:=10 Retries int `json:"retries,omitempty"` // +optional diff --git a/operator/api/v1alpha1/zz_generated.deepcopy.go b/operator/api/v1alpha1/zz_generated.deepcopy.go index 2e407eef78..3f8ca6b148 100644 --- a/operator/api/v1alpha1/zz_generated.deepcopy.go +++ b/operator/api/v1alpha1/zz_generated.deepcopy.go @@ -621,7 +621,6 @@ func (in *KeptnEvaluationProviderStatus) DeepCopy() *KeptnEvaluationProviderStat // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeptnEvaluationSpec) DeepCopyInto(out *KeptnEvaluationSpec) { *out = *in - out.Timeframe = in.Timeframe out.RetryInterval = in.RetryInterval } diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml index ae2c09fe36..3b803ee567 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnevaluations.yaml @@ -67,10 +67,6 @@ spec: default: 5s pattern: ^0|([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$ type: string - timeframe: - default: 2m - pattern: ^0|([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$ - type: string workload: type: string workloadVersion: diff --git a/operator/config/manager/kustomization.yaml b/operator/config/manager/kustomization.yaml index ec9be7054a..580ea90cfe 100644 --- a/operator/config/manager/kustomization.yaml +++ b/operator/config/manager/kustomization.yaml @@ -11,4 +11,4 @@ kind: Kustomization images: - name: controller newName: docker.io/annadreal/keptn-lifecycle-operator - newTag: "202210171665994530" + newTag: "202210171665998375" diff --git a/operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml b/operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml index 8b533c9274..fcc6fec0d2 100644 --- a/operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml +++ b/operator/config/samples/lifecycle_v1alpha1_keptnevaluation.yaml @@ -5,3 +5,4 @@ metadata: spec: evaluationDefinition: my-prometheus-definition #name of the KeptnEvaluationDefinition to use workloadVersion: "1.3" + diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index d6e6225e66..b2fb0bab4f 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -19,6 +19,8 @@ package keptnevaluation import ( "context" "fmt" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/predicate" "time" "go.opentelemetry.io/otel" @@ -91,12 +93,13 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ evaluation.SetStartTime() } - currentDuration := time.Now().UTC().Sub(evaluation.Status.StartTime.Time) - if evaluation.Status.RetryCount >= evaluation.Spec.Retries || currentDuration > evaluation.Spec.Timeframe.Duration { - r.recordEvent("Warning", evaluation, "ReconcileTimeOut", "timeOut or retryCount exceeded") - err := fmt.Errorf("TimeOut or retryCount for evaluation exceeded") + if evaluation.Status.RetryCount >= evaluation.Spec.Retries { + r.recordEvent("Warning", evaluation, "ReconcileTimeOut", "retryCount exceeded") + err := fmt.Errorf("RetryCount for evaluation exceeded") span.SetStatus(codes.Error, err.Error()) - r.updateFinishedEvaluationMetrics(ctx, evaluation) + evaluation.Status.OverallStatus = common.StateFailed + r.updateFinishedEvaluationMetrics(ctx, evaluation, span) + return ctrl.Result{}, err } @@ -137,7 +140,11 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ evaluation.Status.RetryCount++ evaluation.Status.EvaluationStatus = newStatus - evaluation.Status.OverallStatus = common.GetOverallState(statusSummary) + if common.GetOverallState(statusSummary) == common.StateSucceeded { + evaluation.Status.OverallStatus = common.StateSucceeded + } else { + evaluation.Status.OverallStatus = common.StatePending + } } @@ -158,6 +165,15 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ r.Log.Info("Finished Reconciling KeptnEvaluation") + err := r.updateFinishedEvaluationMetrics(ctx, evaluation, span) + + return ctrl.Result{}, err + +} + +func (r *KeptnEvaluationReconciler) updateFinishedEvaluationMetrics(ctx context.Context, evaluation *klcv1alpha1.KeptnEvaluation, span trace.Span) error { + r.recordEvent("Normal", evaluation, string(evaluation.Status.OverallStatus), "the evaluation has "+string(evaluation.Status.OverallStatus)) + if !evaluation.IsEndTimeSet() { // metrics: decrement active evaluation counter r.Meters.AnalysisActive.Add(ctx, -1, evaluation.GetActiveMetricsAttributes()...) @@ -168,18 +184,9 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ if err != nil { span.SetStatus(codes.Error, err.Error()) r.recordEvent("Warning", evaluation, "ReconcileErrored", "could not update status") - return ctrl.Result{Requeue: true}, err + return err } - r.updateFinishedEvaluationMetrics(ctx, evaluation) - - return ctrl.Result{}, nil - -} - -func (r *KeptnEvaluationReconciler) updateFinishedEvaluationMetrics(ctx context.Context, evaluation *klcv1alpha1.KeptnEvaluation) { - r.recordEvent("Normal", evaluation, string(evaluation.Status.OverallStatus), "the evaluation has "+string(evaluation.Status.OverallStatus)) - attrs := evaluation.GetMetricsAttributes() r.Log.Info("Increasing evaluation count") @@ -190,12 +197,13 @@ func (r *KeptnEvaluationReconciler) updateFinishedEvaluationMetrics(ctx context. // metrics: add evaluation duration duration := evaluation.Status.EndTime.Time.Sub(evaluation.Status.StartTime.Time) r.Meters.AnalysisDuration.Record(ctx, duration.Seconds(), attrs...) + return nil } // SetupWithManager sets up the controller with the Manager. func (r *KeptnEvaluationReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&klcv1alpha1.KeptnEvaluation{}). + For(&klcv1alpha1.KeptnEvaluation{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). Complete(r) } @@ -235,7 +243,7 @@ func (r *KeptnEvaluationReconciler) fetchDefinitionAndProvider(ctx context.Conte func (r *KeptnEvaluationReconciler) queryEvaluation(objective klcv1alpha1.Objective, provider klcv1alpha1.KeptnEvaluationProvider) *klcv1alpha1.EvaluationStatusItem { query := &klcv1alpha1.EvaluationStatusItem{ Value: "", - Status: common.StateFailed, //setting status per default to failed + Status: common.StateSucceeded, //setting status per default to failed } //TODO query provider like prometheus service does, save result in value THIS SHALL BE SOLVED IN TICKET #163 @@ -243,6 +251,7 @@ func (r *KeptnEvaluationReconciler) queryEvaluation(objective klcv1alpha1.Object // import apiv1 "github.com/prometheus/client_golang/api/prometheus/v1" // if provider ==prometheus { result, w, err := apiv1.PrometheusAPI.Query(context.Background(), query, endUnix) if err != nil { return 0, fmt.Errorf("unable to query prometheus api: %w", err)}} //TODO check value with evaluation target and update status in query + // result, w, err := prometheus.API().Query(context.Background(), query, time.Now()) return query } From 5c79b6d6a357dc56cbb4141fbf55525b390deb52 Mon Sep 17 00:00:00 2001 From: RealAnna Date: Mon, 17 Oct 2022 11:35:47 +0200 Subject: [PATCH 26/29] feat: added endtime in case of failure, change status to map in evaluation Signed-off-by: RealAnna --- operator/controllers/keptnevaluation/controller.go | 1 + 1 file changed, 1 insertion(+) diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index b2fb0bab4f..f1fcabbc8b 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -118,6 +118,7 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ } statusSummary := common.StatusSummary{} + statusSummary.Total = len(evaluationDefinition.Spec.Objectives) newStatus := make(map[string]klcv1alpha1.EvaluationStatusItem) if evaluation.Status.EvaluationStatus == nil { From 72952cce86f4b33026b36665284878608e9b45bc Mon Sep 17 00:00:00 2001 From: odubajDT Date: Mon, 17 Oct 2022 15:12:38 +0200 Subject: [PATCH 27/29] rename analysis to evaluation Signed-off-by: odubajDT --- operator/api/v1alpha1/common/common.go | 14 ++++---- operator/api/v1alpha1/common/phases.go | 8 ++--- operator/api/v1alpha1/keptnapp_types.go | 12 +++---- operator/api/v1alpha1/keptnworkload_types.go | 14 ++++---- .../api/v1alpha1/zz_generated.deepcopy.go | 16 ++++----- .../bases/lifecycle.keptn.sh_keptnapps.yaml | 4 +-- .../lifecycle.keptn.sh_keptnappversions.yaml | 4 +-- ...cycle.keptn.sh_keptnworkloadinstances.yaml | 4 +-- .../lifecycle.keptn.sh_keptnworkloads.yaml | 4 +-- .../controllers/keptnevaluation/controller.go | 11 +++--- operator/main.go | 12 +++---- operator/webhooks/pod_mutating_webhook.go | 36 +++++++++---------- 12 files changed, 70 insertions(+), 69 deletions(-) diff --git a/operator/api/v1alpha1/common/common.go b/operator/api/v1alpha1/common/common.go index 6b80ac3520..54aebd0454 100644 --- a/operator/api/v1alpha1/common/common.go +++ b/operator/api/v1alpha1/common/common.go @@ -14,11 +14,11 @@ const VersionAnnotation = "keptn.sh/version" const AppAnnotation = "keptn.sh/app" const PreDeploymentTaskAnnotation = "keptn.sh/pre-deployment-tasks" const PostDeploymentTaskAnnotation = "keptn.sh/post-deployment-tasks" -const PreDeploymentAnalysisAnnotation = "keptn.sh/pre-deployment-analysis" -const PostDeploymentAnalysisAnnotation = "keptn.sh/post-deployment-analysis" const K8sRecommendedWorkloadAnnotations = "app.kubernetes.io/name" const K8sRecommendedVersionAnnotations = "app.kubernetes.io/version" const K8sRecommendedAppAnnotations = "app.kubernetes.io/part-of" +const PreDeploymentEvaluationAnnotation = "keptn.sh/pre-deployment-evaluation" +const PostDeploymentEvaluationAnnotation = "keptn.sh/post-deployment-evaluation" const TaskNameAnnotation = "keptn.sh/task-name" const NamespaceEnabledAnnotation = "keptn.sh/lifecycle-controller" @@ -107,8 +107,8 @@ type CheckType string const PreDeploymentCheckType CheckType = "pre" const PostDeploymentCheckType CheckType = "post" -const PreAnalysisCheckType CheckType = "pre" -const PostAnalysisCheckType CheckType = "post" +const PreEvaluationCheckType CheckType = "pre" +const PostEvaluationCheckType CheckType = "post" type KeptnMeters struct { TaskCount syncint64.Counter @@ -120,9 +120,9 @@ type KeptnMeters struct { AppCount syncint64.Counter AppDuration syncfloat64.Histogram AppActive syncint64.UpDownCounter - AnalysisCount syncint64.Counter - AnalysisDuration syncfloat64.Histogram - AnalysisActive syncint64.UpDownCounter + EvaluationCount syncint64.Counter + EvaluationDuration syncfloat64.Histogram + EvaluationActive syncint64.UpDownCounter } const ( diff --git a/operator/api/v1alpha1/common/phases.go b/operator/api/v1alpha1/common/phases.go index 5b6a738756..6ab448abda 100644 --- a/operator/api/v1alpha1/common/phases.go +++ b/operator/api/v1alpha1/common/phases.go @@ -10,12 +10,12 @@ type KeptnPhaseType struct { var ( PhaseWorkloadPreDeployment = KeptnPhaseType{LongName: "Workload Pre-Deployment", ShortName: "WorkloadPreDeploy"} PhaseWorkloadPostDeployment = KeptnPhaseType{LongName: "Workload Post-Deployment", ShortName: "WorkloadPostDeploy"} - PhaseWorkloadPreAnalysis = KeptnPhaseType{LongName: "Workload Pre-Analysis", ShortName: "WorkloadPreAnalysis"} - PhaseWorkloadPostAnalysis = KeptnPhaseType{LongName: "Workload Post-Analysis", ShortName: "WorkloadPostAnalysis"} + PhaseWorkloadPreEvaluation = KeptnPhaseType{LongName: "Workload Pre-Evaluation", ShortName: "WorkloadPreEvaluation"} + PhaseWorkloadPostEvaluation = KeptnPhaseType{LongName: "Workload Post-Evaluation", ShortName: "WorkloadPostEvaluation"} PhaseWorkloadDeployment = KeptnPhaseType{LongName: "Workload Deployment", ShortName: "WorkloadDeploy"} PhaseAppPreDeployment = KeptnPhaseType{LongName: "App Pre-Deployment", ShortName: "AppPreDeploy"} PhaseAppPostDeployment = KeptnPhaseType{LongName: "App Post-Deployment", ShortName: "AppPostDeploy"} - PhaseAppPreAnalysis = KeptnPhaseType{LongName: "App Pre-Analysis", ShortName: "AppPreAnalysis"} - PhaseAppPostAnalysis = KeptnPhaseType{LongName: "App Post-Analysis", ShortName: "AppPostAnalysis"} + PhaseAppPreEvaluation = KeptnPhaseType{LongName: "App Pre-Evaluation", ShortName: "AppPreEvaluation"} + PhaseAppPostEvaluation = KeptnPhaseType{LongName: "App Post-Evaluation", ShortName: "AppPostEvaluation"} PhaseAppDeployment = KeptnPhaseType{LongName: "App Deployment", ShortName: "AppDeploy"} ) diff --git a/operator/api/v1alpha1/keptnapp_types.go b/operator/api/v1alpha1/keptnapp_types.go index 68df9ccce5..5d40766579 100644 --- a/operator/api/v1alpha1/keptnapp_types.go +++ b/operator/api/v1alpha1/keptnapp_types.go @@ -27,12 +27,12 @@ import ( // KeptnAppSpec defines the desired state of KeptnApp type KeptnAppSpec struct { - Version string `json:"version"` - Workloads []KeptnWorkloadRef `json:"workloads,omitempty"` - PreDeploymentTasks []string `json:"preDeploymentTasks,omitempty"` - PostDeploymentTasks []string `json:"postDeploymentTasks,omitempty"` - PreDeploymentAnalysis []string `json:"preDeploymentAnalysis,omitempty"` - PostDeploymentAnalysis []string `json:"postDeploymentAnalysis,omitempty"` + Version string `json:"version"` + Workloads []KeptnWorkloadRef `json:"workloads,omitempty"` + PreDeploymentTasks []string `json:"preDeploymentTasks,omitempty"` + PostDeploymentTasks []string `json:"postDeploymentTasks,omitempty"` + PreDeploymentEvaluation []string `json:"preDeploymentEvaluation,omitempty"` + PostDeploymentEvaluation []string `json:"postDeploymentEvaluation,omitempty"` } // KeptnAppStatus defines the observed state of KeptnApp diff --git a/operator/api/v1alpha1/keptnworkload_types.go b/operator/api/v1alpha1/keptnworkload_types.go index 5019e57b6f..72af4a92cf 100644 --- a/operator/api/v1alpha1/keptnworkload_types.go +++ b/operator/api/v1alpha1/keptnworkload_types.go @@ -28,13 +28,13 @@ import ( // KeptnWorkloadSpec defines the desired state of KeptnWorkload type KeptnWorkloadSpec struct { - AppName string `json:"app"` - Version string `json:"version"` - PreDeploymentTasks []string `json:"preDeploymentTasks,omitempty"` - PostDeploymentTasks []string `json:"postDeploymentTasks,omitempty"` - PreDeploymentAnalysis []string `json:"preDeploymentAnalysis,omitempty"` - PostDeploymentAnalysis []string `json:"postDeploymentAnalysis,omitempty"` - ResourceReference ResourceReference `json:"resourceReference"` + AppName string `json:"app"` + Version string `json:"version"` + PreDeploymentTasks []string `json:"preDeploymentTasks,omitempty"` + PostDeploymentTasks []string `json:"postDeploymentTasks,omitempty"` + PreDeploymentEvaluation []string `json:"preDeploymentEvaluation,omitempty"` + PostDeploymentEvaluation []string `json:"postDeploymentEvaluation,omitempty"` + ResourceReference ResourceReference `json:"resourceReference"` } // KeptnWorkloadStatus defines the observed state of KeptnWorkload diff --git a/operator/api/v1alpha1/zz_generated.deepcopy.go b/operator/api/v1alpha1/zz_generated.deepcopy.go index 3f8ca6b148..4fc55c4edf 100644 --- a/operator/api/v1alpha1/zz_generated.deepcopy.go +++ b/operator/api/v1alpha1/zz_generated.deepcopy.go @@ -228,13 +228,13 @@ func (in *KeptnAppSpec) DeepCopyInto(out *KeptnAppSpec) { *out = make([]string, len(*in)) copy(*out, *in) } - if in.PreDeploymentAnalysis != nil { - in, out := &in.PreDeploymentAnalysis, &out.PreDeploymentAnalysis + if in.PreDeploymentEvaluation != nil { + in, out := &in.PreDeploymentEvaluation, &out.PreDeploymentEvaluation *out = make([]string, len(*in)) copy(*out, *in) } - if in.PostDeploymentAnalysis != nil { - in, out := &in.PostDeploymentAnalysis, &out.PostDeploymentAnalysis + if in.PostDeploymentEvaluation != nil { + in, out := &in.PostDeploymentEvaluation, &out.PostDeploymentEvaluation *out = make([]string, len(*in)) copy(*out, *in) } @@ -1035,13 +1035,13 @@ func (in *KeptnWorkloadSpec) DeepCopyInto(out *KeptnWorkloadSpec) { *out = make([]string, len(*in)) copy(*out, *in) } - if in.PreDeploymentAnalysis != nil { - in, out := &in.PreDeploymentAnalysis, &out.PreDeploymentAnalysis + if in.PreDeploymentEvaluation != nil { + in, out := &in.PreDeploymentEvaluation, &out.PreDeploymentEvaluation *out = make([]string, len(*in)) copy(*out, *in) } - if in.PostDeploymentAnalysis != nil { - in, out := &in.PostDeploymentAnalysis, &out.PostDeploymentAnalysis + if in.PostDeploymentEvaluation != nil { + in, out := &in.PostDeploymentEvaluation, &out.PostDeploymentEvaluation *out = make([]string, len(*in)) copy(*out, *in) } diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnapps.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnapps.yaml index 1724b74092..04a3124ac8 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnapps.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnapps.yaml @@ -35,7 +35,7 @@ spec: spec: description: KeptnAppSpec defines the desired state of KeptnApp properties: - postDeploymentAnalysis: + postDeploymentEvaluation: items: type: string type: array @@ -43,7 +43,7 @@ spec: items: type: string type: array - preDeploymentAnalysis: + preDeploymentEvaluation: items: type: string type: array diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnappversions.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnappversions.yaml index 068dd4435a..eac4434de3 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnappversions.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnappversions.yaml @@ -55,7 +55,7 @@ spec: properties: appName: type: string - postDeploymentAnalysis: + postDeploymentEvaluation: items: type: string type: array @@ -63,7 +63,7 @@ spec: items: type: string type: array - preDeploymentAnalysis: + preDeploymentEvaluation: items: type: string type: array diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloadinstances.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloadinstances.yaml index 141c7aa567..fd7677c305 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloadinstances.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloadinstances.yaml @@ -59,7 +59,7 @@ spec: properties: app: type: string - postDeploymentAnalysis: + postDeploymentEvaluation: items: type: string type: array @@ -67,7 +67,7 @@ spec: items: type: string type: array - preDeploymentAnalysis: + preDeploymentEvaluation: items: type: string type: array diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloads.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloads.yaml index 5bb108f6b9..301f77cbf3 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloads.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloads.yaml @@ -44,7 +44,7 @@ spec: properties: app: type: string - postDeploymentAnalysis: + postDeploymentEvaluation: items: type: string type: array @@ -52,7 +52,7 @@ spec: items: type: string type: array - preDeploymentAnalysis: + preDeploymentEvaluation: items: type: string type: array diff --git a/operator/controllers/keptnevaluation/controller.go b/operator/controllers/keptnevaluation/controller.go index f1fcabbc8b..2df00909cd 100644 --- a/operator/controllers/keptnevaluation/controller.go +++ b/operator/controllers/keptnevaluation/controller.go @@ -19,9 +19,10 @@ package keptnevaluation import ( "context" "fmt" + "time" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/predicate" - "time" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" @@ -89,7 +90,7 @@ func (r *KeptnEvaluationReconciler) Reconcile(ctx context.Context, req ctrl.Requ if !evaluation.IsStartTimeSet() { // metrics: increment active evaluation counter - r.Meters.AnalysisActive.Add(ctx, 1, evaluation.GetActiveMetricsAttributes()...) + r.Meters.EvaluationActive.Add(ctx, 1, evaluation.GetActiveMetricsAttributes()...) evaluation.SetStartTime() } @@ -177,7 +178,7 @@ func (r *KeptnEvaluationReconciler) updateFinishedEvaluationMetrics(ctx context. if !evaluation.IsEndTimeSet() { // metrics: decrement active evaluation counter - r.Meters.AnalysisActive.Add(ctx, -1, evaluation.GetActiveMetricsAttributes()...) + r.Meters.EvaluationActive.Add(ctx, -1, evaluation.GetActiveMetricsAttributes()...) evaluation.SetEndTime() } @@ -193,11 +194,11 @@ func (r *KeptnEvaluationReconciler) updateFinishedEvaluationMetrics(ctx context. r.Log.Info("Increasing evaluation count") // metrics: increment evaluation counter - r.Meters.AnalysisCount.Add(ctx, 1, attrs...) + r.Meters.EvaluationCount.Add(ctx, 1, attrs...) // metrics: add evaluation duration duration := evaluation.Status.EndTime.Time.Sub(evaluation.Status.StartTime.Time) - r.Meters.AnalysisDuration.Record(ctx, duration.Seconds(), attrs...) + r.Meters.EvaluationDuration.Record(ctx, duration.Seconds(), attrs...) return nil } diff --git a/operator/main.go b/operator/main.go index 5baa8db795..70bdc039cf 100644 --- a/operator/main.go +++ b/operator/main.go @@ -151,15 +151,15 @@ func main() { if err != nil { setupLog.Error(err, "unable to start OTel") } - analysisCount, err := meter.SyncInt64().Counter("keptn.analysis.count", instrument.WithDescription("a simple counter for Keptn analysis for Evaluations")) + evaluationCount, err := meter.SyncInt64().Counter("keptn.evaluation.count", instrument.WithDescription("a simple counter for Keptn evaluation for Evaluations")) if err != nil { setupLog.Error(err, "unable to start OTel") } - analysisDuration, err := meter.SyncFloat64().Histogram("keptn.analysis.duration", instrument.WithDescription("a histogram of duration for Keptn analysis for Evaluations"), instrument.WithUnit(unit.Unit("s"))) + evaluationDuration, err := meter.SyncFloat64().Histogram("keptn.evaluation.duration", instrument.WithDescription("a histogram of duration for Keptn evaluation for Evaluations"), instrument.WithUnit(unit.Unit("s"))) if err != nil { setupLog.Error(err, "unable to start OTel") } - analysisActive, err := meter.SyncInt64().UpDownCounter("keptn.analysis.active", instrument.WithDescription("a simple counter of active apps for Keptn analysis for Evaluations")) + evaluationActive, err := meter.SyncInt64().UpDownCounter("keptn.evaluation.active", instrument.WithDescription("a simple counter of active apps for Keptn evaluation for Evaluations")) if err != nil { setupLog.Error(err, "unable to start OTel") } @@ -174,9 +174,9 @@ func main() { AppCount: appCount, AppDuration: appDuration, AppActive: appActive, - AnalysisCount: analysisCount, - AnalysisDuration: analysisDuration, - AnalysisActive: analysisActive, + EvaluationCount: evaluationCount, + EvaluationDuration: evaluationDuration, + EvaluationActive: evaluationActive, } // Start the prometheus HTTP server and pass the exporter Collector to it diff --git a/operator/webhooks/pod_mutating_webhook.go b/operator/webhooks/pod_mutating_webhook.go index 5ef884c8c9..add1da45a6 100644 --- a/operator/webhooks/pod_mutating_webhook.go +++ b/operator/webhooks/pod_mutating_webhook.go @@ -299,8 +299,8 @@ func (a *PodMutatingWebhook) generateWorkload(ctx context.Context, pod *corev1.P var preDeploymentTasks []string var postDeploymentTasks []string - var preDeploymentAnalysis []string - var postDeploymentAnalysis []string + var preDeploymentEvaluation []string + var postDeploymentEvaluation []string if annotations, found := getLabelOrAnnotation(pod, common.PreDeploymentTaskAnnotation, ""); found { preDeploymentTasks = strings.Split(annotations, ",") @@ -310,12 +310,12 @@ func (a *PodMutatingWebhook) generateWorkload(ctx context.Context, pod *corev1.P postDeploymentTasks = strings.Split(annotations, ",") } - if annotations, found := getLabelOrAnnotation(pod, common.PreDeploymentAnalysisAnnotation, ""); found { - preDeploymentAnalysis = strings.Split(annotations, ",") + if annotations, found := getLabelOrAnnotation(pod, common.PreDeploymentEvaluationAnnotation, ""); found { + preDeploymentEvaluation = strings.Split(annotations, ",") } - if annotations, found := getLabelOrAnnotation(pod, common.PostDeploymentAnalysisAnnotation, ""); found { - postDeploymentAnalysis = strings.Split(annotations, ",") + if annotations, found := getLabelOrAnnotation(pod, common.PostDeploymentEvaluationAnnotation, ""); found { + postDeploymentEvaluation = strings.Split(annotations, ",") } // create TraceContext @@ -330,13 +330,13 @@ func (a *PodMutatingWebhook) generateWorkload(ctx context.Context, pod *corev1.P Annotations: traceContextCarrier, }, Spec: klcv1alpha1.KeptnWorkloadSpec{ - AppName: applicationName, - Version: version, - ResourceReference: a.getResourceReference(pod), - PreDeploymentTasks: preDeploymentTasks, - PostDeploymentTasks: postDeploymentTasks, - PreDeploymentAnalysis: preDeploymentAnalysis, - PostDeploymentAnalysis: postDeploymentAnalysis, + AppName: applicationName, + Version: version, + ResourceReference: a.getResourceReference(pod), + PreDeploymentTasks: preDeploymentTasks, + PostDeploymentTasks: postDeploymentTasks, + PreDeploymentEvaluation: preDeploymentEvaluation, + PostDeploymentEvaluation: postDeploymentEvaluation, }, } } @@ -357,11 +357,11 @@ func (a *PodMutatingWebhook) generateApp(ctx context.Context, pod *corev1.Pod, n Annotations: traceContextCarrier, }, Spec: klcv1alpha1.KeptnAppSpec{ - Version: version, - PreDeploymentTasks: []string{}, - PostDeploymentTasks: []string{}, - PreDeploymentAnalysis: []string{}, - PostDeploymentAnalysis: []string{}, + Version: version, + PreDeploymentTasks: []string{}, + PostDeploymentTasks: []string{}, + PreDeploymentEvaluation: []string{}, + PostDeploymentEvaluation: []string{}, Workloads: []klcv1alpha1.KeptnWorkloadRef{ { Name: appName, From 1da417903bb28f0ae6ed114f1e02d79105b2625c Mon Sep 17 00:00:00 2001 From: odubajDT Date: Mon, 17 Oct 2022 15:13:25 +0200 Subject: [PATCH 28/29] go mod tidy Signed-off-by: odubajDT --- operator/go.mod | 1 - operator/go.sum | 2 -- 2 files changed, 3 deletions(-) diff --git a/operator/go.mod b/operator/go.mod index d20a114ba5..b73e6b42f4 100644 --- a/operator/go.mod +++ b/operator/go.mod @@ -19,7 +19,6 @@ require ( go.opentelemetry.io/otel/sdk v1.10.0 go.opentelemetry.io/otel/sdk/metric v0.32.1 go.opentelemetry.io/otel/trace v1.10.0 - golang.org/x/exp v0.0.0-20221012211006-4de253d81b95 google.golang.org/grpc v1.46.2 k8s.io/api v0.24.2 k8s.io/apimachinery v0.24.2 diff --git a/operator/go.sum b/operator/go.sum index 420c26fa65..56d4797f8d 100644 --- a/operator/go.sum +++ b/operator/go.sum @@ -581,8 +581,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20221012211006-4de253d81b95 h1:sBdrWpxhGDdTAYNqbgBLAR+ULAPPhfgncLr1X0lyWtg= -golang.org/x/exp v0.0.0-20221012211006-4de253d81b95/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= From ea4a33ecd4140bdd9bd99a797de7779fae50d1b1 Mon Sep 17 00:00:00 2001 From: odubajDT Date: Mon, 17 Oct 2022 15:24:57 +0200 Subject: [PATCH 29/29] make generate Signed-off-by: odubajDT --- operator/api/v1alpha1/zz_generated.deepcopy.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/operator/api/v1alpha1/zz_generated.deepcopy.go b/operator/api/v1alpha1/zz_generated.deepcopy.go index 4fc55c4edf..9ae1ee6b14 100644 --- a/operator/api/v1alpha1/zz_generated.deepcopy.go +++ b/operator/api/v1alpha1/zz_generated.deepcopy.go @@ -811,6 +811,7 @@ func (in *KeptnTaskList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeptnTaskSpec) DeepCopyInto(out *KeptnTaskSpec) { *out = *in + out.Context = in.Context in.Parameters.DeepCopyInto(&out.Parameters) out.SecureParameters = in.SecureParameters } @@ -1118,6 +1119,21 @@ func (in *SecureParameters) DeepCopy() *SecureParameters { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TaskContext) DeepCopyInto(out *TaskContext) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskContext. +func (in *TaskContext) DeepCopy() *TaskContext { + if in == nil { + return nil + } + out := new(TaskContext) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TaskParameters) DeepCopyInto(out *TaskParameters) { *out = *in