diff --git a/.github/scripts/.helm-tests/default/result.yaml b/.github/scripts/.helm-tests/default/result.yaml index 585b255b00..784db338cb 100644 --- a/.github/scripts/.helm-tests/default/result.yaml +++ b/.github/scripts/.helm-tests/default/result.yaml @@ -274,6 +274,9 @@ spec: required: - name type: object + query: + description: Query represents the executed query + type: string value: description: Value is the value the provider returned type: string diff --git a/docs/content/en/docs/crd-ref/metrics/v1alpha3/_index.md b/docs/content/en/docs/crd-ref/metrics/v1alpha3/_index.md index 5f25c214ce..7051a7bf42 100644 --- a/docs/content/en/docs/crd-ref/metrics/v1alpha3/_index.md +++ b/docs/content/en/docs/crd-ref/metrics/v1alpha3/_index.md @@ -435,6 +435,7 @@ _Appears in:_ | Field | Description | | --- | --- | | `objectiveReference` _[ObjectReference](#objectreference)_ | Objective store reference to corresponding objective template | +| `query` _string_ | Query represents the executed query | | `value` _string_ | Value is the value the provider returned | | `errMsg` _string_ | ErrMsg stores any possible error at retrieval time | diff --git a/helm/chart/templates/analysis-crd.yaml b/helm/chart/templates/analysis-crd.yaml index fdb3468c59..e3fc687a37 100644 --- a/helm/chart/templates/analysis-crd.yaml +++ b/helm/chart/templates/analysis-crd.yaml @@ -135,6 +135,9 @@ spec: required: - name type: object + query: + description: Query represents the executed query + type: string value: description: Value is the value the provider returned type: string diff --git a/metrics-operator/api/v1alpha3/analysis_types.go b/metrics-operator/api/v1alpha3/analysis_types.go index 2be35bfdbc..59394fca64 100644 --- a/metrics-operator/api/v1alpha3/analysis_types.go +++ b/metrics-operator/api/v1alpha3/analysis_types.go @@ -38,6 +38,8 @@ type AnalysisSpec struct { type ProviderResult struct { // Objective store reference to corresponding objective template Objective ObjectReference `json:"objectiveReference,omitempty"` + // Query represents the executed query + Query string `json:"query,omitempty"` // Value is the value the provider returned Value string `json:"value,omitempty"` // ErrMsg stores any possible error at retrieval time diff --git a/metrics-operator/config/crd/bases/metrics.keptn.sh_analyses.yaml b/metrics-operator/config/crd/bases/metrics.keptn.sh_analyses.yaml index c5af7dd7b0..abb2f03242 100644 --- a/metrics-operator/config/crd/bases/metrics.keptn.sh_analyses.yaml +++ b/metrics-operator/config/crd/bases/metrics.keptn.sh_analyses.yaml @@ -130,6 +130,9 @@ spec: required: - name type: object + query: + description: Query represents the executed query + type: string value: description: Value is the value the provider returned type: string diff --git a/metrics-operator/controllers/analysis/controller_test.go b/metrics-operator/controllers/analysis/controller_test.go index a3c8d2acfc..5525e4fe11 100644 --- a/metrics-operator/controllers/analysis/controller_test.go +++ b/metrics-operator/controllers/analysis/controller_test.go @@ -539,6 +539,7 @@ func Test_extractMissingObjectives(t *testing.T) { existingValues := map[string]metricsapi.ProviderResult{ common.ComputeKey(ad.Spec.Objectives[1].AnalysisValueTemplateRef): { Value: "1.0", + Query: "query", }, common.ComputeKey(ad.Spec.Objectives[2].AnalysisValueTemplateRef): { ErrMsg: "error", @@ -551,6 +552,7 @@ func Test_extractMissingObjectives(t *testing.T) { require.Equal(t, needToRetry, todo[1].AnalysisValueTemplateRef) require.Len(t, existing, 1) require.Equal(t, "1.0", existing[common.ComputeKey(done)].Value) + require.Equal(t, "query", existing[common.ComputeKey(done)].Query) // verify that the analysisDefinition has not been changed require.Len(t, ad.Spec.Objectives, 3) diff --git a/metrics-operator/controllers/analysis/objectives_evaluator.go b/metrics-operator/controllers/analysis/objectives_evaluator.go index 3464335a26..cc076629eb 100644 --- a/metrics-operator/controllers/analysis/objectives_evaluator.go +++ b/metrics-operator/controllers/analysis/objectives_evaluator.go @@ -40,6 +40,7 @@ func (oe ObjectivesEvaluator) Evaluate(ctx context.Context, providerType string, } result := metricsapi.ProviderResult{ Objective: o.Objective.AnalysisValueTemplateRef, + Query: o.Query, Value: value, ErrMsg: strErr, } diff --git a/metrics-operator/controllers/analysis/objectives_evaluator_test.go b/metrics-operator/controllers/analysis/objectives_evaluator_test.go index 480aa97484..6ad150689f 100644 --- a/metrics-operator/controllers/analysis/objectives_evaluator_test.go +++ b/metrics-operator/controllers/analysis/objectives_evaluator_test.go @@ -49,6 +49,7 @@ func TestEvaluate(t *testing.T) { Name: "mytemp", Namespace: "default", }, + Query: "query_fake_metric", Value: "10", ErrMsg: "", }, @@ -78,6 +79,7 @@ func TestEvaluate(t *testing.T) { Namespace: "default", }, Value: "", + Query: "query_fake_metric", ErrMsg: "something bad", }, expectedError: "something bad", diff --git a/metrics-operator/controllers/common/analysis/analysis_evaluator_test.go b/metrics-operator/controllers/common/analysis/analysis_evaluator_test.go index 28770a180e..6916bfde34 100644 --- a/metrics-operator/controllers/common/analysis/analysis_evaluator_test.go +++ b/metrics-operator/controllers/common/analysis/analysis_evaluator_test.go @@ -59,6 +59,7 @@ func TestAnalysisEvaluator_Evaluate(t *testing.T) { { Result: types.TargetResult{}, Value: 5.0, + Query: "query", Score: 10.0, Error: nil, }, @@ -68,6 +69,7 @@ func TestAnalysisEvaluator_Evaluate(t *testing.T) { EvaluateFunc: func(values map[string]v1alpha3.ProviderResult, objective *v1alpha3.Objective) types.ObjectiveResult { return types.ObjectiveResult{ Result: types.TargetResult{}, + Query: "query", Value: 5.0, Score: 10.0, Error: nil, @@ -103,12 +105,14 @@ func TestAnalysisEvaluator_Evaluate(t *testing.T) { { Result: types.TargetResult{}, Value: 5.0, + Query: "query", Score: 10.0, Error: nil, }, { Result: types.TargetResult{}, Value: 5.0, + Query: "query", Score: 10.0, Error: nil, }, @@ -119,6 +123,7 @@ func TestAnalysisEvaluator_Evaluate(t *testing.T) { return types.ObjectiveResult{ Result: types.TargetResult{}, Value: 5.0, + Query: "query", Score: 10.0, Error: nil, } @@ -149,6 +154,7 @@ func TestAnalysisEvaluator_Evaluate(t *testing.T) { ObjectiveResults: []types.ObjectiveResult{ { Result: types.TargetResult{}, + Query: "query", Value: 5.0, Score: 5.0, Error: nil, @@ -159,6 +165,7 @@ func TestAnalysisEvaluator_Evaluate(t *testing.T) { EvaluateFunc: func(values map[string]v1alpha3.ProviderResult, objective *v1alpha3.Objective) types.ObjectiveResult { return types.ObjectiveResult{ Result: types.TargetResult{}, + Query: "query", Value: 5.0, Score: 5.0, Error: nil, @@ -191,6 +198,7 @@ func TestAnalysisEvaluator_Evaluate(t *testing.T) { { Result: types.TargetResult{}, Value: 5.0, + Query: "query", Score: 0.0, Error: nil, }, @@ -201,6 +209,7 @@ func TestAnalysisEvaluator_Evaluate(t *testing.T) { return types.ObjectiveResult{ Result: types.TargetResult{}, Value: 5.0, + Query: "query", Score: 0.0, Error: nil, } @@ -237,12 +246,14 @@ func TestAnalysisEvaluator_Evaluate(t *testing.T) { { Result: types.TargetResult{}, Value: 5.0, + Query: "query", Score: 10.0, Error: nil, }, { Result: types.TargetResult{}, Value: 5.0, + Query: "query", Score: 0.0, Error: nil, }, @@ -254,6 +265,7 @@ func TestAnalysisEvaluator_Evaluate(t *testing.T) { return types.ObjectiveResult{ Result: types.TargetResult{}, Value: 5.0, + Query: "query", Score: 0.0, Error: nil, } @@ -261,6 +273,7 @@ func TestAnalysisEvaluator_Evaluate(t *testing.T) { return types.ObjectiveResult{ Result: types.TargetResult{}, Value: 5.0, + Query: "query", Score: 10.0, Error: nil, } diff --git a/metrics-operator/controllers/common/analysis/objective_evaluator.go b/metrics-operator/controllers/common/analysis/objective_evaluator.go index 9a0d0d6554..675ccb4959 100644 --- a/metrics-operator/controllers/common/analysis/objective_evaluator.go +++ b/metrics-operator/controllers/common/analysis/objective_evaluator.go @@ -26,7 +26,8 @@ func (oe *ObjectiveEvaluator) Evaluate(values map[string]v1alpha3.ProviderResult } // get the value - floatVal, err := getValueFromMap(values, ComputeKey(obj.AnalysisValueTemplateRef)) + floatVal, query, err := getResultFromMap(values, ComputeKey(obj.AnalysisValueTemplateRef)) + result.Query = query if err != nil { result.Error = err return result @@ -50,17 +51,17 @@ func (oe *ObjectiveEvaluator) Evaluate(values map[string]v1alpha3.ProviderResult return result } -func getValueFromMap(values map[string]v1alpha3.ProviderResult, key string) (float64, error) { +func getResultFromMap(values map[string]v1alpha3.ProviderResult, key string) (float64, string, error) { val, ok := values[key] if !ok { - return 0.0, fmt.Errorf("required value '%s' not available", key) + return 0.0, "", fmt.Errorf("required value '%s' not available", key) } floatVal, err := strconv.ParseFloat(val.Value, 64) if err != nil { - return 0.0, err + return 0.0, val.Query, err } - return floatVal, nil + return floatVal, val.Query, nil } func ComputeKey(obj v1alpha3.ObjectReference) string { diff --git a/metrics-operator/controllers/common/analysis/objective_evaluator_test.go b/metrics-operator/controllers/common/analysis/objective_evaluator_test.go index d9d584cae9..5ccbd61518 100644 --- a/metrics-operator/controllers/common/analysis/objective_evaluator_test.go +++ b/metrics-operator/controllers/common/analysis/objective_evaluator_test.go @@ -40,7 +40,7 @@ func TestObjectiveEvaluator_Evaluate(t *testing.T) { { name: "evaluation passed", values: map[string]v1alpha3.ProviderResult{ - "name": {Value: "20"}, + "name": {Value: "20", Query: "qqqqqqqq"}, }, o: v1alpha3.Objective{ AnalysisValueTemplateRef: v1alpha3.ObjectReference{ @@ -59,6 +59,7 @@ func TestObjectiveEvaluator_Evaluate(t *testing.T) { Score: 2.0, Error: nil, Value: 20.0, + Query: "qqqqqqqq", Result: types.TargetResult{ Pass: true, }, @@ -73,7 +74,7 @@ func TestObjectiveEvaluator_Evaluate(t *testing.T) { { name: "evaluation finished with warning", values: map[string]v1alpha3.ProviderResult{ - "name": {Value: "20"}, + "name": {Value: "20", Query: "qqqqqqqq"}, }, o: v1alpha3.Objective{ AnalysisValueTemplateRef: v1alpha3.ObjectReference{ @@ -93,6 +94,7 @@ func TestObjectiveEvaluator_Evaluate(t *testing.T) { Score: 1.0, Error: nil, Value: 20.0, + Query: "qqqqqqqq", Result: types.TargetResult{ Pass: false, Warning: true, @@ -108,7 +110,7 @@ func TestObjectiveEvaluator_Evaluate(t *testing.T) { { name: "evaluation failed", values: map[string]v1alpha3.ProviderResult{ - "name": {Value: "20"}, + "name": {Value: "20", Query: "qqqqqqqq"}, }, o: v1alpha3.Objective{ AnalysisValueTemplateRef: v1alpha3.ObjectReference{ @@ -128,6 +130,7 @@ func TestObjectiveEvaluator_Evaluate(t *testing.T) { Score: 0.0, Error: nil, Value: 20.0, + Query: "qqqqqqqq", Result: types.TargetResult{ Pass: false, Warning: false, @@ -155,44 +158,49 @@ func TestGetValueFromMap(t *testing.T) { values map[string]v1alpha3.ProviderResult in string val float64 + query string wantErr bool }{ { name: "happy path", values: map[string]v1alpha3.ProviderResult{ - "key1": {Value: "7"}, + "key1": {Value: "7", Query: "qqqqqqqq"}, }, in: "key1", val: 7.0, + query: "qqqqqqqq", wantErr: false, }, { name: "key not found", values: map[string]v1alpha3.ProviderResult{ - "key1": {Value: "7"}, + "key1": {Value: "7", Query: "qqqqqqqq"}, }, in: "key", val: 0.0, + query: "", wantErr: true, }, { name: "value not float", values: map[string]v1alpha3.ProviderResult{ - "key": {}, + "key1": {Value: "", Query: "qqqqqqqq"}, }, in: "key1", val: 0.0, + query: "qqqqqqqq", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - res, err := getValueFromMap(tt.values, tt.in) + res, query, err := getResultFromMap(tt.values, tt.in) if (err != nil) != tt.wantErr { t.Errorf("error = %v, wantErr %v", err, tt.wantErr) } require.Equal(t, tt.val, res) + require.Equal(t, tt.query, query) }) } } diff --git a/metrics-operator/controllers/common/analysis/types/types.go b/metrics-operator/controllers/common/analysis/types/types.go index 2c2752a45a..3670171524 100644 --- a/metrics-operator/controllers/common/analysis/types/types.go +++ b/metrics-operator/controllers/common/analysis/types/types.go @@ -34,6 +34,7 @@ type ObjectiveResult struct { Result TargetResult `json:"result"` Objective v1alpha3.Objective `json:"objective"` Value float64 `json:"value"` + Query string `json:"query"` Score float64 `json:"score"` Error error `json:"error,omitempty"` } diff --git a/test/testanalysis/analysis-controller-existing-status/01-assert.yaml b/test/testanalysis/analysis-controller-existing-status/01-assert.yaml index 889ec082ef..127fdf9e2e 100644 --- a/test/testanalysis/analysis-controller-existing-status/01-assert.yaml +++ b/test/testanalysis/analysis-controller-existing-status/01-assert.yaml @@ -9,4 +9,4 @@ spec: status: pass: true # yamllint disable-line rule:line-length - raw: '{"objectiveResults":[{"result":{"failResult":{"operator":{"lessThan":{"fixedValue":"2"}},"fulfilled":false},"warnResult":{"operator":{"lessThan":{"fixedValue":"3"}},"fulfilled":false},"warning":false,"pass":true},"objective":{"analysisValueTemplateRef":{"name":"ready","namespace":"testy"},"target":{"failure":{"lessThan":{"fixedValue":"2"}},"warning":{"lessThan":{"fixedValue":"3"}}},"weight":1},"value":4,"score":1}],"totalScore":1,"maximumScore":1,"pass":true,"warning":false}' + raw: '{"objectiveResults":[{"result":{"failResult":{"operator":{"lessThan":{"fixedValue":"2"}},"fulfilled":false},"warnResult":{"operator":{"lessThan":{"fixedValue":"3"}},"fulfilled":false},"warning":false,"pass":true},"objective":{"analysisValueTemplateRef":{"name":"ready","namespace":"testy"},"target":{"failure":{"lessThan":{"fixedValue":"2"}},"warning":{"lessThan":{"fixedValue":"3"}}},"weight":1},"value":4,"query":"sum(kube_pod_container_status_ready{namespace=\"keptn-lifecycle-toolkit-system\"})","score":1}],"totalScore":1,"maximumScore":1,"pass":true,"warning":false}' diff --git a/test/testanalysis/analysis-controller-multiple-providers/01-assert.yaml b/test/testanalysis/analysis-controller-multiple-providers/01-assert.yaml index bf8b8fde43..5e31de7b6f 100644 --- a/test/testanalysis/analysis-controller-multiple-providers/01-assert.yaml +++ b/test/testanalysis/analysis-controller-multiple-providers/01-assert.yaml @@ -8,4 +8,4 @@ spec: status: pass: true # yamllint disable-line rule:line-length - raw: '{"objectiveResults":[{"result":{"failResult":{"operator":{"lessThan":{"fixedValue":"5"}},"fulfilled":false},"warnResult":{"operator":{"lessThan":{"fixedValue":"4"}},"fulfilled":false},"warning":false,"pass":true},"objective":{"analysisValueTemplateRef":{"name":"value-1"},"target":{"failure":{"lessThan":{"fixedValue":"5"}},"warning":{"lessThan":{"fixedValue":"4"}}},"weight":2},"value":11,"score":2},{"result":{"failResult":{"operator":{"greaterThan":{"fixedValue":"20"}},"fulfilled":false},"warnResult":{"operator":{"greaterThan":{"fixedValue":"15"}},"fulfilled":true},"warning":true,"pass":false},"objective":{"analysisValueTemplateRef":{"name":"value-2"},"target":{"failure":{"greaterThan":{"fixedValue":"20"}},"warning":{"greaterThan":{"fixedValue":"15"}}},"weight":1},"value":20,"score":0.5},{"result":{"failResult":{"operator":{"notInRange":{"lowBound":"25","highBound":"35"}},"fulfilled":false},"warnResult":{"operator":{},"fulfilled":false},"warning":false,"pass":true},"objective":{"analysisValueTemplateRef":{"name":"value-3"},"target":{"failure":{"notInRange":{"lowBound":"25","highBound":"35"}}},"weight":1},"value":30,"score":1}],"totalScore":3.5,"maximumScore":4,"pass":true,"warning":false}' + raw: '{"objectiveResults":[{"result":{"failResult":{"operator":{"lessThan":{"fixedValue":"5"}},"fulfilled":false},"warnResult":{"operator":{"lessThan":{"fixedValue":"4"}},"fulfilled":false},"warning":false,"pass":true},"objective":{"analysisValueTemplateRef":{"name":"value-1"},"target":{"failure":{"lessThan":{"fixedValue":"5"}},"warning":{"lessThan":{"fixedValue":"4"}}},"weight":2},"value":11,"query":"query-1","score":2},{"result":{"failResult":{"operator":{"greaterThan":{"fixedValue":"20"}},"fulfilled":false},"warnResult":{"operator":{"greaterThan":{"fixedValue":"15"}},"fulfilled":true},"warning":true,"pass":false},"objective":{"analysisValueTemplateRef":{"name":"value-2"},"target":{"failure":{"greaterThan":{"fixedValue":"20"}},"warning":{"greaterThan":{"fixedValue":"15"}}},"weight":1},"value":20,"query":"query-2","score":0.5},{"result":{"failResult":{"operator":{"notInRange":{"lowBound":"25","highBound":"35"}},"fulfilled":false},"warnResult":{"operator":{},"fulfilled":false},"warning":false,"pass":true},"objective":{"analysisValueTemplateRef":{"name":"value-3"},"target":{"failure":{"notInRange":{"lowBound":"25","highBound":"35"}}},"weight":1},"value":30,"query":"query-3","score":1}],"totalScore":3.5,"maximumScore":4,"pass":true,"warning":false}' diff --git a/test/testanalysis/analysis-controller-with-duration-timeframe/01-assert.yaml b/test/testanalysis/analysis-controller-with-duration-timeframe/01-assert.yaml index ea6d053565..802a01286b 100644 --- a/test/testanalysis/analysis-controller-with-duration-timeframe/01-assert.yaml +++ b/test/testanalysis/analysis-controller-with-duration-timeframe/01-assert.yaml @@ -9,4 +9,4 @@ status: pass: true state: Completed # yamllint disable-line rule:line-length - raw: '{"objectiveResults":[{"result":{"failResult":{"operator":{"lessThan":{"fixedValue":"2"}},"fulfilled":false},"warnResult":{"operator":{"lessThan":{"fixedValue":"3"}},"fulfilled":false},"warning":false,"pass":true},"objective":{"analysisValueTemplateRef":{"name":"ready"},"target":{"failure":{"lessThan":{"fixedValue":"2"}},"warning":{"lessThan":{"fixedValue":"3"}}},"weight":1},"value":4,"score":1}],"totalScore":1,"maximumScore":1,"pass":true,"warning":false}' + raw: '{"objectiveResults":[{"result":{"failResult":{"operator":{"lessThan":{"fixedValue":"2"}},"fulfilled":false},"warnResult":{"operator":{"lessThan":{"fixedValue":"3"}},"fulfilled":false},"warning":false,"pass":true},"objective":{"analysisValueTemplateRef":{"name":"ready"},"target":{"failure":{"lessThan":{"fixedValue":"2"}},"warning":{"lessThan":{"fixedValue":"3"}}},"weight":1},"value":4,"query":"sum(kube_pod_container_status_ready{namespace=\"keptn-lifecycle-toolkit-system\"})","score":1}],"totalScore":1,"maximumScore":1,"pass":true,"warning":false}' diff --git a/test/testanalysis/analysis-controller/01-assert.yaml b/test/testanalysis/analysis-controller/01-assert.yaml index ea6d053565..802a01286b 100644 --- a/test/testanalysis/analysis-controller/01-assert.yaml +++ b/test/testanalysis/analysis-controller/01-assert.yaml @@ -9,4 +9,4 @@ status: pass: true state: Completed # yamllint disable-line rule:line-length - raw: '{"objectiveResults":[{"result":{"failResult":{"operator":{"lessThan":{"fixedValue":"2"}},"fulfilled":false},"warnResult":{"operator":{"lessThan":{"fixedValue":"3"}},"fulfilled":false},"warning":false,"pass":true},"objective":{"analysisValueTemplateRef":{"name":"ready"},"target":{"failure":{"lessThan":{"fixedValue":"2"}},"warning":{"lessThan":{"fixedValue":"3"}}},"weight":1},"value":4,"score":1}],"totalScore":1,"maximumScore":1,"pass":true,"warning":false}' + raw: '{"objectiveResults":[{"result":{"failResult":{"operator":{"lessThan":{"fixedValue":"2"}},"fulfilled":false},"warnResult":{"operator":{"lessThan":{"fixedValue":"3"}},"fulfilled":false},"warning":false,"pass":true},"objective":{"analysisValueTemplateRef":{"name":"ready"},"target":{"failure":{"lessThan":{"fixedValue":"2"}},"warning":{"lessThan":{"fixedValue":"3"}}},"weight":1},"value":4,"query":"sum(kube_pod_container_status_ready{namespace=\"keptn-lifecycle-toolkit-system\"})","score":1}],"totalScore":1,"maximumScore":1,"pass":true,"warning":false}'