From 01b75a830ea75027bb6031fb1c49141357c36790 Mon Sep 17 00:00:00 2001 From: Sagnik Dutta Date: Thu, 28 Sep 2023 19:48:31 +0530 Subject: [PATCH] RHIROS-1326 Kruize 0.0.20_rm Integration --- Makefile | 4 +- internal/api/utils.go | 10 +- internal/services/report_processor.go | 10 +- internal/types/kruizePayload/common.go | 45 +++-- internal/utils/kruize/kruize_api.go | 48 ++++- internal/utils/kruize/metrics.go | 11 ++ openapi.json | 264 ++++++++++++------------- 7 files changed, 223 insertions(+), 169 deletions(-) diff --git a/Makefile b/Makefile index 69b905ba..bdaa9858 100644 --- a/Makefile +++ b/Makefile @@ -118,9 +118,9 @@ upload-msg-to-rosocp: get-recommendations: ifdef env $(eval APIPOD=$(shell oc get pods -o custom-columns=POD:.metadata.name --no-headers -n ${env} | grep ros-ocp-backend-api)) - oc exec ${APIPOD} -c ros-ocp-backend-api -n ${env} -- /bin/bash -c 'curl -s -H "X-Rh-Identity: ${b64_identity}" -H "x-rh-request_id: testtesttest" http://localhost:8000/api/cost-management/v1/recommendations/openshift' | python -m json.tool + oc exec ${APIPOD} -c ros-ocp-backend-api -n ${env} -- /bin/bash -c 'curl -s -H "X-Rh-Identity: ${b64_identity}" -H "x-rh-request_id: testtesttest" http://localhost:8000/api/cost-management/v1/recommendations/openshift?start_date=1992-12-26' | python -m json.tool else curl -s -H "x-rh-identity: ${b64_identity}" \ -H "x-rh-request_id: testtesttest" \ - http://localhost:8000/api/cost-management/v1/recommendations/openshift | python -m json.tool + http://localhost:8000/api/cost-management/v1/recommendations/openshift?start_date=1992-12-26 | python -m json.tool endif diff --git a/internal/api/utils.go b/internal/api/utils.go index d6381e03..e6881480 100644 --- a/internal/api/utils.go +++ b/internal/api/utils.go @@ -223,11 +223,6 @@ func TransformComponentUnits(jsonData datatypes.JSON) map[string]interface{} { return nil } - durationBased, ok := data["duration_based"].(map[string]interface{}) - if !ok { - fmt.Printf("duration_based not found in JSON") - } - convertMemory := func(memory map[string]interface{}) error { amount, ok := memory["amount"].(float64) if ok { @@ -274,6 +269,11 @@ func TransformComponentUnits(jsonData datatypes.JSON) map[string]interface{} { return nil } + durationBased, ok := data["duration_based"].(map[string]interface{}) + if !ok { + fmt.Printf("duration_based not found in JSON") + } + /* Recommendation data is available for three periods For each of these actual values will be present in diff --git a/internal/services/report_processor.go b/internal/services/report_processor.go index 8fb1a649..e024c996 100644 --- a/internal/services/report_processor.go +++ b/internal/services/report_processor.go @@ -199,7 +199,7 @@ func ProcessReport(msg *kafka.Message) { continue } - if kruize.Is_valid_recommendation(recommendation) { + if kruize.Is_valid_recommendation(recommendation, experiment_name, maxEndTime.String()) { containers := recommendation[0].Kubernetes_objects[0].Containers for _, container := range containers { for _, v := range container.Recommendations.Data { @@ -212,8 +212,8 @@ func ProcessReport(msg *kafka.Message) { recommendationSet := model.RecommendationSet{ WorkloadID: workload.ID, ContainerName: container.Container_name, - MonitoringStartTime: v.Duration_based.Short_term.Monitoring_start_time, - MonitoringEndTime: v.Duration_based.Short_term.Monitoring_end_time, + MonitoringStartTime: v.RecommendationTerms.Short_term.MonitoringStartTime, + MonitoringEndTime: v.MonitoringEndTime, Recommendations: marshalData, } if err := recommendationSet.CreateRecommendationSet(); err != nil { @@ -227,8 +227,8 @@ func ProcessReport(msg *kafka.Message) { historicalRecommendationSet := model.HistoricalRecommendationSet{ WorkloadID: workload.ID, ContainerName: container.Container_name, - MonitoringStartTime: v.Duration_based.Short_term.Monitoring_start_time, - MonitoringEndTime: v.Duration_based.Short_term.Monitoring_end_time, + MonitoringStartTime: v.RecommendationTerms.Short_term.MonitoringStartTime, + MonitoringEndTime: v.MonitoringEndTime, Recommendations: marshalData, } if err := historicalRecommendationSet.CreateHistoricalRecommendationSet(); err != nil { diff --git a/internal/types/kruizePayload/common.go b/internal/types/kruizePayload/common.go index 935ace90..b19ee1a5 100644 --- a/internal/types/kruizePayload/common.go +++ b/internal/types/kruizePayload/common.go @@ -38,36 +38,47 @@ type aggregation_info struct { } type recommendation struct { - Data map[string]recommendationType `json:"data,omitempty"` + Version string `json:"version,omitempty"` + Data map[string]RecommendationData `json:"data,omitempty"` Notifications map[string]notification `json:"notifications,omitempty"` } + type notification struct { NotifyType string `json:"type,omitempty"` Message string `json:"message,omitempty"` Code int `json:"code,omitempty"` } -type recommendationType struct { - Duration_based termbased `json:"duration_based,omitempty"` +type RecommendationEngineObject struct { + PodsCount int `json:"pods_count,omitempty"` + ConfidenceLevel float64 `json:"confidence_level,omitempty"` + Config ConfigObject `json:"config,omitempty"` + Variation ConfigObject `json:"variation,omitempty"` + Notifications map[string]notification `json:"notifications,omitempty"` +} + +type RecommendationData struct { + Notifications map[string]notification `json:"notifications"` + MonitoringEndTime time.Time `json:"monitoring_end_time"` + Current ConfigObject `json:"current"` + RecommendationTerms TermBased `json:"recommendation_terms"` } -type termbased struct { - Short_term recommendationObject `json:"short_term,omitempty"` - Medium_term recommendationObject `json:"medium_term,omitempty"` - Long_term recommendationObject `json:"long_term,omitempty"` +type RecommendationTerm struct { + DurationInHours float64 `json:"duration_in_hours"` + Notifications map[string]notification `json:"notifications"` + MonitoringStartTime time.Time + RecommendationEngines struct { + Cost RecommendationEngineObject `json:"cost"` + Performance RecommendationEngineObject `json:"performance"` + } `json:"recommendation_engines"` } -type recommendationObject struct { - Monitoring_start_time time.Time `json:"monitoring_start_time,omitempty"` - Monitoring_end_time time.Time `json:"monitoring_end_time,omitempty"` - Duration_in_hours float64 `json:"duration_in_hours,omitempty"` - Pods_count int `json:"pods_count,omitempty"` - Confidence_level float64 `json:"confidence_level,omitempty"` - Current ConfigObject `json:"current,omitempty"` - Config ConfigObject `json:"config,omitempty"` - Variation ConfigObject `json:"variation,omitempty"` - Notifications map[string]notification `json:"notifications,omitempty"` +type TermBased struct { + Short_term RecommendationTerm `json:"short_term,omitempty"` + Medium_term RecommendationTerm `json:"medium_term,omitempty"` + Long_term RecommendationTerm `json:"long_term,omitempty"` } type ConfigObject struct { diff --git a/internal/utils/kruize/kruize_api.go b/internal/utils/kruize/kruize_api.go index 39fd2ddc..e617e94f 100644 --- a/internal/utils/kruize/kruize_api.go +++ b/internal/utils/kruize/kruize_api.go @@ -176,14 +176,50 @@ func Update_recommendations(experiment_name string, interval_end_time time.Time) } -func Is_valid_recommendation(d []kruizePayload.ListRecommendations) bool { +func Is_valid_recommendation(d []kruizePayload.ListRecommendations, experiment_name string, maxEndTime string) bool { if len(d) > 0 { + + // To maintain a local reference the following map has been created from + // https://github.com/kruize/autotune/blob/master/design/NotificationCodes.md#detailed-codes + notificationCodeValidities := map[string]string{ + "111000": "INFO", + "120001": "INFO", + "221001": "ERROR", + "221002": "ERROR", + "221003": "ERROR", + "221004": "ERROR", + "223001": "ERROR", + "223002": "ERROR", + "223003": "ERROR", + "223004": "ERROR", + "224001": "ERROR", + "224002": "ERROR", + "224003": "ERROR", + "224004": "ERROR", + } + notifications := d[0].Kubernetes_objects[0].Containers[0].Recommendations.Notifications - // 112101 is notification code for "Duration Based Recommendations Available". - if _, ok := notifications["112101"]; ok { - return true - } else { - return false + + for key := range notifications{ + notificationType, keyExists := notificationCodeValidities[key] + if !keyExists { + return false + } + + if key == "111000" && notificationType == "INFO"{ + notificationsLevelTwo := d[0].Kubernetes_objects[0].Containers[0].Recommendations.Data[maxEndTime].Notifications + for key := range notificationsLevelTwo{ + if notificationCodeValidities[key] == "ERROR"{ + kruizeInvalidRecommendationDetail.WithLabelValues(key, experiment_name).Set(1) + } + } + return true + } else { + // Setting the metric counter to 1 as we expect a single metric + // for a combination of notification_code and experiment_name + kruizeInvalidRecommendationDetail.WithLabelValues(key, experiment_name).Set(1) + return false + } } } return false diff --git a/internal/utils/kruize/metrics.go b/internal/utils/kruize/metrics.go index a6980148..eb3d17a3 100644 --- a/internal/utils/kruize/metrics.go +++ b/internal/utils/kruize/metrics.go @@ -13,3 +13,14 @@ var ( []string{"path"}, ) ) + + +var ( + kruizeInvalidRecommendationDetail = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "rosocp_kruize_invalid_recommendation_detail", + Help: "List of INFO/ERROR type recommendations from Kruize", + }, + []string{"notification_code", "experiment_name"}, + ) +) \ No newline at end of file diff --git a/openapi.json b/openapi.json index 0411151a..c2c9d4f2 100644 --- a/openapi.json +++ b/openapi.json @@ -27,7 +27,7 @@ { "name": "workload_type", "in": "query", - "description": "Workload type", + "description": "Options are daemonset, deployment, deploymentconfig, replicaset, replicationcontroller, statefulset", "required": false, "schema": { "type": "string" @@ -67,7 +67,8 @@ "required": false, "schema": { "type": "string" - } + }, + "example": "YYYY-MM-DD" }, { "name": "end_date", @@ -76,7 +77,8 @@ "required": false, "schema": { "type": "string" - } + }, + "example": "YYYY-MM-DD" }, { "name": "offset", @@ -202,12 +204,12 @@ "properties": { "count": { "type": "integer", - "minimum": 0 + "minimum": 1 }, "limit": { "type": "integer", "minimum": 1, - "maximum": 100 + "maximum": 10 }, "offset": { "type": "integer", @@ -236,24 +238,18 @@ }, "Notifications": { "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "NOTICE", - "WARNING", - "CRITICAL" - ] - }, - "message": { - "type": "string", - "example": "There is not enough data available to generate a recommendation." - }, - "code": { - "type": "number" - } + "properties": { + "type": { + "type": "string", + "example": "INFO" + }, + "code": { + "type": "string", + "example": 112101 + }, + "message": { + "type": "string", + "example": "Duration Based Recommendations Available" } } }, @@ -336,7 +332,7 @@ "properties": { "amount": { "type": "number", - "example": 1.91 + "example": 2 }, "format": { "type": "string", @@ -349,7 +345,7 @@ "properties": { "amount": { "type": "number", - "example": 16.391 + "example": 20.391 }, "format": { "type": "string", @@ -372,7 +368,7 @@ "properties": { "amount": { "type": "number", - "example": 2.11 + "example": 3.11 }, "format": { "type": "string", @@ -403,7 +399,7 @@ "properties": { "amount": { "type": "number", - "example": 1.92 + "example": 3 }, "format": { "type": "string", @@ -428,31 +424,6 @@ } } }, - "notifications": { - "$ref": "#/components/schemas/Notifications" - }, - "pods_count": { - "type": "integer", - "example": 1 - }, - "confidence_level": { - "type": "number", - "example": 0.5 - }, - "duration_in_hours": { - "type": "number", - "example": 361 - }, - "monitoring_end_time": { - "type": "string", - "format": "date-time", - "example": "2023-04-18T15:00:00.000Z" - }, - "monitoring_start_time": { - "type": "string", - "format": "date-time", - "example": "2023-04-03T15:00:00.000Z" - }, "variation": { "type": "object", "properties": { @@ -464,7 +435,7 @@ "properties": { "amount": { "type": "number", - "example": 3 + "example": 1 }, "format": { "type": "string", @@ -477,7 +448,7 @@ "properties": { "amount": { "type": "number", - "example": 344 + "example": 0.959 }, "format": { "type": "string", @@ -495,7 +466,7 @@ "properties": { "amount": { "type": "number", - "example": 4 + "example": 1 }, "format": { "type": "string", @@ -508,7 +479,7 @@ "properties": { "amount": { "type": "number", - "example": 500 + "example": 3.995 }, "format": { "type": "string", @@ -519,6 +490,31 @@ } } } + }, + "notifications": { + "$ref": "#/components/schemas/Notifications" + }, + "pods_count": { + "type": "integer", + "example": 1 + }, + "confidence_level": { + "type": "number", + "example": 0.5 + }, + "duration_in_hours": { + "type": "number", + "example": 361 + }, + "monitoring_end_time": { + "type": "string", + "format": "date-time", + "example": "2023-04-18T15:00:00.000Z" + }, + "monitoring_start_time": { + "type": "string", + "format": "date-time", + "example": "2023-04-03T15:00:00.000Z" } } }, @@ -549,7 +545,7 @@ "properties": { "amount": { "type": "number", - "example": 30.715 + "example": 300 }, "format": { "type": "string", @@ -580,11 +576,11 @@ "properties": { "amount": { "type": "number", - "example": 16.391 + "example": 5 }, "format": { "type": "string", - "example": "MiB" + "example": "GiB" } } } @@ -616,11 +612,11 @@ "properties": { "amount": { "type": "number", - "example": 31.674 + "example": 500 }, "format": { "type": "string", - "example": "GiB" + "example": "MiB" } } } @@ -634,7 +630,7 @@ "properties": { "amount": { "type": "number", - "example": 1.92 + "example": 3.92 }, "format": { "type": "string", @@ -647,11 +643,11 @@ "properties": { "amount": { "type": "number", - "example": 16.396 + "example": 6 }, "format": { "type": "string", - "example": "MiB" + "example": "GiB" } } } @@ -659,31 +655,6 @@ } } }, - "notifications": { - "$ref": "#/components/schemas/Notifications" - }, - "pods_count": { - "type": "integer", - "example": 1 - }, - "confidence_level": { - "type": "number", - "example": 0.5 - }, - "duration_in_hours": { - "type": "number", - "example": 169 - }, - "monitoring_end_time": { - "type": "string", - "format": "date-time", - "example": "2023-04-18T15:00:00.000Z" - }, - "monitoring_start_time": { - "type": "string", - "format": "date-time", - "example": "2023-04-11T15:00:00.000Z" - }, "variation": { "type": "object", "properties": { @@ -695,7 +666,7 @@ "properties": { "amount": { "type": "number", - "example": 2 + "example": -1.468 }, "format": { "type": "string", @@ -708,7 +679,7 @@ "properties": { "amount": { "type": "number", - "example": 959.4 + "example": 200 }, "format": { "type": "string", @@ -726,7 +697,7 @@ "properties": { "amount": { "type": "number", - "example": 5 + "example": 2 }, "format": { "type": "string", @@ -739,17 +710,42 @@ "properties": { "amount": { "type": "number", - "example": 200.333 + "example": 1 }, "format": { "type": "string", - "example": "MiB" + "example": "GiB" } } } } } } + }, + "notifications": { + "$ref": "#/components/schemas/Notifications" + }, + "pods_count": { + "type": "integer", + "example": 1 + }, + "confidence_level": { + "type": "number", + "example": 0.5 + }, + "duration_in_hours": { + "type": "number", + "example": 169 + }, + "monitoring_end_time": { + "type": "string", + "format": "date-time", + "example": "2023-04-18T15:00:00.000Z" + }, + "monitoring_start_time": { + "type": "string", + "format": "date-time", + "example": "2023-04-11T15:00:00.000Z" } } }, @@ -767,7 +763,7 @@ "properties": { "amount": { "type": "number", - "example": 2.09 + "example": 3.76 }, "format": { "type": "string", @@ -780,11 +776,11 @@ "properties": { "amount": { "type": "number", - "example": 30.715 + "example": 5 }, "format": { "type": "string", - "example": "MiB" + "example": "GiB" } } } @@ -811,7 +807,7 @@ "properties": { "amount": { "type": "number", - "example": 16.391 + "example": 400 }, "format": { "type": "string", @@ -834,7 +830,7 @@ "properties": { "amount": { "type": "number", - "example": 2.11 + "example": 5 }, "format": { "type": "string", @@ -847,11 +843,11 @@ "properties": { "amount": { "type": "number", - "example": 31.674 + "example": 6.7 }, "format": { "type": "string", - "example": "MiB" + "example": "GiB" } } } @@ -865,7 +861,7 @@ "properties": { "amount": { "type": "number", - "example": 1.92 + "example": 3 }, "format": { "type": "string", @@ -878,7 +874,7 @@ "properties": { "amount": { "type": "number", - "example": 16.396 + "example": 700 }, "format": { "type": "string", @@ -890,31 +886,6 @@ } } }, - "notifications": { - "$ref": "#/components/schemas/Notifications" - }, - "pods_count": { - "type": "integer", - "example": 1 - }, - "confidence_level": { - "type": "number", - "example": 0.5 - }, - "duration_in_hours": { - "type": "number", - "example": 25 - }, - "monitoring_end_time": { - "type": "string", - "format": "date-time", - "example": "2023-04-18T15:00:00.000Z" - }, - "monitoring_start_time": { - "type": "string", - "format": "date-time", - "example": "2023-04-17T15:00:00.000Z" - }, "variation": { "type": "object", "properties": { @@ -926,7 +897,7 @@ "properties": { "amount": { "type": "number", - "example": 5 + "example": 1.24 }, "format": { "type": "string", @@ -939,11 +910,11 @@ "properties": { "amount": { "type": "number", - "example": 929.111 + "example": 1.7 }, "format": { "type": "string", - "example": "MiB" + "example": "GiB" } } } @@ -957,7 +928,7 @@ "properties": { "amount": { "type": "number", - "example": 3 + "example": 1.08 }, "format": { "type": "string", @@ -970,7 +941,7 @@ "properties": { "amount": { "type": "number", - "example": 500 + "example": 300 }, "format": { "type": "string", @@ -981,6 +952,31 @@ } } } + }, + "notifications": { + "$ref": "#/components/schemas/Notifications" + }, + "pods_count": { + "type": "integer", + "example": 1 + }, + "confidence_level": { + "type": "number", + "example": 0.5 + }, + "duration_in_hours": { + "type": "number", + "example": 25 + }, + "monitoring_end_time": { + "type": "string", + "format": "date-time", + "example": "2023-04-18T15:00:00.000Z" + }, + "monitoring_start_time": { + "type": "string", + "format": "date-time", + "example": "2023-04-17T15:00:00.000Z" } } } @@ -1004,4 +1000,4 @@ } } } -} +} \ No newline at end of file