From 09e02bd64545d8b8efc0f2596cb75d5fce45ca2d Mon Sep 17 00:00:00 2001 From: Bharadwajshivam28 Date: Wed, 2 Oct 2024 05:29:33 +0530 Subject: [PATCH 1/6] feat: Integrating ELK provider Signed-off-by: Bharadwajshivam28 --- .../controllers/common/providers/elk/elk.go | 121 ++++++++++++++++++ metrics-operator/go.mod | 4 + metrics-operator/go.sum | 6 + 3 files changed, 131 insertions(+) create mode 100644 metrics-operator/controllers/common/providers/elk/elk.go diff --git a/metrics-operator/controllers/common/providers/elk/elk.go b/metrics-operator/controllers/common/providers/elk/elk.go new file mode 100644 index 0000000000..636f520c49 --- /dev/null +++ b/metrics-operator/controllers/common/providers/elk/elk.go @@ -0,0 +1,121 @@ +package elasticsearch + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/go-logr/logr" + metricsapi "github.com/keptn/lifecycle-toolkit/metrics-operator/api/v1" + elastic "github.com/elastic/go-elasticsearch/v8" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + warningLogStringElastic = "%s API returned warnings: %s" +) + +type KeptnElasticProvider struct { + Log logr.Logger + K8sClient client.Client + Elastic *elastic.Client +} + +func NewElasticProvider(log logr.Logger, k8sClient client.Client, elasticURL string) (*KeptnElasticProvider, error) { + cfg := elastic.Config{ + Addresses: []string{ + elasticURL, + }, + } + es, err := elastic.NewClient(cfg) + if err != nil { + return nil, fmt.Errorf("failed to create elasticsearch client: %w", err) + } + + return &KeptnElasticProvider{ + Log: log, + K8sClient: k8sClient, + Elastic: es, + }, nil +} + +func (r *KeptnElasticProvider) FetchAnalysisValue(ctx context.Context, query string, analysis metricsapi.Analysis, provider *metricsapi.KeptnMetricsProvider) (string, error) { + ctx, cancel := context.WithTimeout(ctx, 20*time.Second) + defer cancel() + + result, err := r.runElasticQuery(ctx, query, analysis.GetFrom(), analysis.GetTo()) + if err != nil { + return "", err + } + + r.Log.Info(fmt.Sprintf("Elasticsearch query result: %v", result)) + return r.extractMetric(result) +} + +func (r *KeptnElasticProvider) EvaluateQuery(ctx context.Context, metric metricsapi.KeptnMetric, provider metricsapi.KeptnMetricsProvider) (string, []byte, error) { + ctx, cancel := context.WithTimeout(ctx, 20*time.Second) + defer cancel() + + result, err := r.runElasticQuery(ctx, metric.Spec.Query, time.Now().Add(-30*time.Minute), time.Now()) + if err != nil { + return "", nil, err + } + + metricValue, err := r.extractMetric(result) + if err != nil { + return "", nil, err + } + + return metricValue, []byte{}, nil +} + +func (r *KeptnElasticProvider) runElasticQuery(ctx context.Context, query string, from, to time.Time) (map[string]interface{}, error) { + queryBody := fmt.Sprintf(` + { + "query": { + "range": { + "@timestamp": { + "gte": "%s", + "lte": "%s" + } + } + } + }`, from.Format(time.RFC3339), to.Format(time.RFC3339)) + + res, err := r.Elastic.Search( + r.Elastic.Search.WithContext(ctx), + r.Elastic.Search.WithBody(strings.NewReader(queryBody)), + ) + if err != nil { + return nil, fmt.Errorf("failed to execute Elasticsearch query: %w", err) + } + defer res.Body.Close() + + if warnings, ok := res.Header["Warning"]; ok { + r.Log.Info(fmt.Sprintf(warningLogStringElastic, "Elasticsearch", warnings)) + } + + var result map[string]interface{} + if err := json.NewDecoder(res.Body).Decode(&result); err != nil { + return nil, fmt.Errorf("failed to parse Elasticsearch response: %w", err) + } + return result, nil +} + +func (r *KeptnElasticProvider) extractMetric(result map[string]interface{}) (string, error) { + hits, ok := result["hits"].(map[string]interface{}) + if !ok { + return "", fmt.Errorf("invalid result format: missing 'hits' field") + } + + totalHits, ok := hits["total"].(map[string]interface{}) + if !ok { + return "", fmt.Errorf("invalid result format: missing 'total' field in 'hits'") + } + + value := fmt.Sprintf("%v", totalHits["value"]) + + return value, nil +} diff --git a/metrics-operator/go.mod b/metrics-operator/go.mod index 2f46c4cbaa..d0e882330b 100644 --- a/metrics-operator/go.mod +++ b/metrics-operator/go.mod @@ -31,6 +31,8 @@ require ( sigs.k8s.io/yaml v1.4.0 ) +require github.com/elastic/elastic-transport-go/v8 v8.6.0 // indirect + require ( github.com/DataDog/zstd v1.5.2 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect @@ -43,6 +45,8 @@ require ( github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/elastic/go-elasticsearch/v7 v7.17.10 + github.com/elastic/go-elasticsearch/v8 v8.15.0 github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.7.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect diff --git a/metrics-operator/go.sum b/metrics-operator/go.sum index a36a64200d..bc99a9c842 100644 --- a/metrics-operator/go.sum +++ b/metrics-operator/go.sum @@ -29,6 +29,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/elastic/elastic-transport-go/v8 v8.6.0 h1:Y2S/FBjx1LlCv5m6pWAF2kDJAHoSjSRSJCApolgfthA= +github.com/elastic/elastic-transport-go/v8 v8.6.0/go.mod h1:YLHer5cj0csTzNFXoNQ8qhtGY1GTvSqPnKWKaqQE3Hk= +github.com/elastic/go-elasticsearch/v7 v7.17.10 h1:TCQ8i4PmIJuBunvBS6bwT2ybzVFxxUhhltAs3Gyu1yo= +github.com/elastic/go-elasticsearch/v7 v7.17.10/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4= +github.com/elastic/go-elasticsearch/v8 v8.15.0 h1:IZyJhe7t7WI3NEFdcHnf6IJXqpRf+8S8QWLtZYYyBYk= +github.com/elastic/go-elasticsearch/v8 v8.15.0/go.mod h1:HCON3zj4btpqs2N1jjsAy4a/fiAul+YBP00mBH4xik8= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= From 176ae1cfc77aad81c00a92d0bf570a9cf97e469d Mon Sep 17 00:00:00 2001 From: Bharadwajshivam28 Date: Thu, 3 Oct 2024 15:48:40 +0530 Subject: [PATCH 2/6] fix: fixed spell check issues and removed v7 in go.mod Signed-off-by: Bharadwajshivam28 --- .github/actions/spelling/expect.txt | 3 +++ metrics-operator/go.mod | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 76f9c64c93..4aaa8677e6 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -158,6 +158,8 @@ dynamicinformer dynatrace ecr elasticquota +elasticsearch +Elasticsearch elif ENABLEGITINFO endblock @@ -391,6 +393,7 @@ Lifcycle lifecyclekeptnsh linenums linkedin +lte linkedtrace livenessprobe loadtests diff --git a/metrics-operator/go.mod b/metrics-operator/go.mod index d0e882330b..fed5d2cbac 100644 --- a/metrics-operator/go.mod +++ b/metrics-operator/go.mod @@ -45,7 +45,6 @@ require ( github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/elastic/go-elasticsearch/v7 v7.17.10 github.com/elastic/go-elasticsearch/v8 v8.15.0 github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.7.0+incompatible // indirect From 37e11bc26c8ac9b24835f3b884caff0975c1c202 Mon Sep 17 00:00:00 2001 From: Bharadwajshivam28 Date: Thu, 3 Oct 2024 15:51:59 +0530 Subject: [PATCH 3/6] fix: Removed Elasticsearch from expect.tct Signed-off-by: Bharadwajshivam28 --- .github/actions/spelling/expect.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 4aaa8677e6..654967cb85 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -159,7 +159,6 @@ dynatrace ecr elasticquota elasticsearch -Elasticsearch elif ENABLEGITINFO endblock From 14d7005cae03684a836303675a5762991eebfc96 Mon Sep 17 00:00:00 2001 From: Bharadwajshivam28 Date: Thu, 3 Oct 2024 17:02:34 +0530 Subject: [PATCH 4/6] feat: created Test cases for all the methods in elk provider Signed-off-by: Bharadwajshivam28 --- .../common/providers/elk/elk_test.go | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 metrics-operator/controllers/common/providers/elk/elk_test.go diff --git a/metrics-operator/controllers/common/providers/elk/elk_test.go b/metrics-operator/controllers/common/providers/elk/elk_test.go new file mode 100644 index 0000000000..bbbc1fd7d6 --- /dev/null +++ b/metrics-operator/controllers/common/providers/elk/elk_test.go @@ -0,0 +1,232 @@ +package elasticsearch + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/elastic/go-elasticsearch/v8" + "github.com/go-logr/logr" + metricsapi "github.com/keptn/lifecycle-toolkit/metrics-operator/api/v1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +func TestNewElasticProvider(t *testing.T) { + log := logr.Discard() + scheme := runtime.NewScheme() + k8sClient := fake.NewClientBuilder().WithScheme(scheme).Build() + elasticURL := "http://localhost:9200" + + provider, err := NewElasticProvider(log, k8sClient, elasticURL) + + assert.NoError(t, err) + assert.NotNil(t, provider) + assert.Equal(t, log, provider.Log) + assert.Equal(t, k8sClient, provider.K8sClient) + assert.NotNil(t, provider.Elastic) +} + +func TestKeptnElasticProvider_FetchAnalysisValue(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + response := `{ + "hits": { + "total": { + "value": 42 + } + } + }` + _, _ = w.Write([]byte(response)) + })) + defer server.Close() + + cfg := elasticsearch.Config{ + Addresses: []string{server.URL}, + } + es, err := elasticsearch.NewClient(cfg) + require.NoError(t, err) + + scheme := runtime.NewScheme() + k8sClient := fake.NewClientBuilder().WithScheme(scheme).Build() + + provider := &KeptnElasticProvider{ + Log: logr.Discard(), + K8sClient: k8sClient, + Elastic: es, + } + + ctx := context.Background() + query := "test_query" + analysis := metricsapi.Analysis{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-analysis", + }, + Spec: metricsapi.AnalysisSpec{ + Timeframe: metricsapi.Timeframe{ + From: metav1.NewTime(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)), + To: metav1.NewTime(time.Date(2023, 1, 2, 0, 0, 0, 0, time.UTC)), + }, + }, + } + metricProvider := &metricsapi.KeptnMetricsProvider{} + + result, err := provider.FetchAnalysisValue(ctx, query, analysis, metricProvider) + + assert.NoError(t, err) + assert.Equal(t, "42", result) +} + +func TestKeptnElasticProvider_EvaluateQuery(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + response := `{ + "hits": { + "total": { + "value": 100 + } + } + }` + _, _ = w.Write([]byte(response)) + })) + defer server.Close() + + cfg := elasticsearch.Config{ + Addresses: []string{server.URL}, + } + es, err := elasticsearch.NewClient(cfg) + require.NoError(t, err) + + scheme := runtime.NewScheme() + k8sClient := fake.NewClientBuilder().WithScheme(scheme).Build() + + provider := &KeptnElasticProvider{ + Log: logr.Discard(), + K8sClient: k8sClient, + Elastic: es, + } + + ctx := context.Background() + metric := metricsapi.KeptnMetric{ + Spec: metricsapi.KeptnMetricSpec{ + Query: "test_query", + }, + } + metricProvider := metricsapi.KeptnMetricsProvider{} + + result, _, err := provider.EvaluateQuery(ctx, metric, metricProvider) + + assert.NoError(t, err) + assert.Equal(t, "100", result) +} + +func TestKeptnElasticProvider_runElasticQuery(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + response := `{ + "hits": { + "total": { + "value": 200 + } + } + }` + _, _ = w.Write([]byte(response)) + })) + defer server.Close() + + cfg := elasticsearch.Config{ + Addresses: []string{server.URL}, + } + es, err := elasticsearch.NewClient(cfg) + require.NoError(t, err) + + scheme := runtime.NewScheme() + k8sClient := fake.NewClientBuilder().WithScheme(scheme).Build() + + provider := &KeptnElasticProvider{ + Log: logr.Discard(), + K8sClient: k8sClient, + Elastic: es, + } + + ctx := context.Background() + query := "test_query" + from := time.Now().Add(-1 * time.Hour) + to := time.Now() + + result, err := provider.runElasticQuery(ctx, query, from, to) + + assert.NoError(t, err) + assert.NotNil(t, result) + + hits, ok := result["hits"].(map[string]interface{}) + assert.True(t, ok) + + total, ok := hits["total"].(map[string]interface{}) + assert.True(t, ok) + + value, ok := total["value"].(float64) + assert.True(t, ok) + assert.Equal(t, float64(200), value) +} + +func TestKeptnElasticProvider_extractMetric(t *testing.T) { + provider := &KeptnElasticProvider{ + Log: logr.Discard(), + } + + testCases := []struct { + name string + input map[string]interface{} + expectedValue string + expectedError string + }{ + { + name: "Valid input", + input: map[string]interface{}{ + "hits": map[string]interface{}{ + "total": map[string]interface{}{ + "value": 42, + }, + }, + }, + expectedValue: "42", + expectedError: "", + }, + { + name: "Missing hits", + input: map[string]interface{}{}, + expectedValue: "", + expectedError: "invalid result format: missing 'hits' field", + }, + { + name: "Missing total", + input: map[string]interface{}{ + "hits": map[string]interface{}{}, + }, + expectedValue: "", + expectedError: "invalid result format: missing 'total' field in 'hits'", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + value, err := provider.extractMetric(tc.input) + + if tc.expectedError != "" { + assert.EqualError(t, err, tc.expectedError) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.expectedValue, value) + } + }) + } +} \ No newline at end of file From bd0f3bb849a04a3aa5439255cf88853c4d425bad Mon Sep 17 00:00:00 2001 From: Bharadwajshivam28 Date: Sat, 5 Oct 2024 06:42:54 +0530 Subject: [PATCH 5/6] feat: modified 30 min time slot and made it dynmaic and formated extract metric method Signed-off-by: Bharadwajshivam28 --- .../controllers/common/providers/elk/elk.go | 212 ++++++++++-------- 1 file changed, 121 insertions(+), 91 deletions(-) diff --git a/metrics-operator/controllers/common/providers/elk/elk.go b/metrics-operator/controllers/common/providers/elk/elk.go index 636f520c49..7b03c1fd9d 100644 --- a/metrics-operator/controllers/common/providers/elk/elk.go +++ b/metrics-operator/controllers/common/providers/elk/elk.go @@ -1,121 +1,151 @@ package elasticsearch import ( - "context" - "encoding/json" - "fmt" - "strings" - "time" - - "github.com/go-logr/logr" - metricsapi "github.com/keptn/lifecycle-toolkit/metrics-operator/api/v1" - elastic "github.com/elastic/go-elasticsearch/v8" - "sigs.k8s.io/controller-runtime/pkg/client" + "context" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/go-logr/logr" + metricsapi "github.com/keptn/lifecycle-toolkit/metrics-operator/api/v1" + elastic "github.com/elastic/go-elasticsearch/v8" + "sigs.k8s.io/controller-runtime/pkg/client" ) const ( - warningLogStringElastic = "%s API returned warnings: %s" + warningLogStringElastic = "%s API returned warnings: %s" + defaultTimeRange = 30 * time.Minute ) type KeptnElasticProvider struct { - Log logr.Logger - K8sClient client.Client - Elastic *elastic.Client + Log logr.Logger + K8sClient client.Client + Elastic *elastic.Client +} + +type ElasticsearchResponse struct { + Hits struct { + Total struct { + Value int `json:"value"` + } `json:"total"` + } `json:"hits"` } func NewElasticProvider(log logr.Logger, k8sClient client.Client, elasticURL string) (*KeptnElasticProvider, error) { - cfg := elastic.Config{ - Addresses: []string{ - elasticURL, - }, - } - es, err := elastic.NewClient(cfg) - if err != nil { - return nil, fmt.Errorf("failed to create elasticsearch client: %w", err) - } - - return &KeptnElasticProvider{ - Log: log, - K8sClient: k8sClient, - Elastic: es, - }, nil + cfg := elastic.Config{ + Addresses: []string{ + elasticURL, + }, + } + es, err := elastic.NewClient(cfg) + if err != nil { + return nil, fmt.Errorf("failed to create elasticsearch client: %w", err) + } + return &KeptnElasticProvider{ + Log: log, + K8sClient: k8sClient, + Elastic: es, + }, nil } func (r *KeptnElasticProvider) FetchAnalysisValue(ctx context.Context, query string, analysis metricsapi.Analysis, provider *metricsapi.KeptnMetricsProvider) (string, error) { - ctx, cancel := context.WithTimeout(ctx, 20*time.Second) - defer cancel() + ctx, cancel := context.WithTimeout(ctx, 20*time.Second) + defer cancel() - result, err := r.runElasticQuery(ctx, query, analysis.GetFrom(), analysis.GetTo()) - if err != nil { - return "", err - } + result, err := r.runElasticQuery(ctx, query, analysis.GetFrom(), analysis.GetTo()) + if err != nil { + return "", err + } - r.Log.Info(fmt.Sprintf("Elasticsearch query result: %v", result)) - return r.extractMetric(result) + r.Log.Info(fmt.Sprintf("Elasticsearch query result: %v", result)) + return r.extractMetric(result) } func (r *KeptnElasticProvider) EvaluateQuery(ctx context.Context, metric metricsapi.KeptnMetric, provider metricsapi.KeptnMetricsProvider) (string, []byte, error) { - ctx, cancel := context.WithTimeout(ctx, 20*time.Second) - defer cancel() + ctx, cancel := context.WithTimeout(ctx, 20*time.Second) + defer cancel() - result, err := r.runElasticQuery(ctx, metric.Spec.Query, time.Now().Add(-30*time.Minute), time.Now()) - if err != nil { - return "", nil, err - } + timeRange := getTimeRangeFromSpec(metric.Spec.Range) - metricValue, err := r.extractMetric(result) - if err != nil { - return "", nil, err - } + result, err := r.runElasticQuery(ctx, metric.Spec.Query, time.Now().Add(-timeRange), time.Now()) + if err != nil { + return "", nil, err + } - return metricValue, []byte{}, nil -} + metricValue, err := r.extractMetric(result) + if err != nil { + return "", nil, err + } -func (r *KeptnElasticProvider) runElasticQuery(ctx context.Context, query string, from, to time.Time) (map[string]interface{}, error) { - queryBody := fmt.Sprintf(` - { - "query": { - "range": { - "@timestamp": { - "gte": "%s", - "lte": "%s" - } - } - } - }`, from.Format(time.RFC3339), to.Format(time.RFC3339)) - - res, err := r.Elastic.Search( - r.Elastic.Search.WithContext(ctx), - r.Elastic.Search.WithBody(strings.NewReader(queryBody)), - ) - if err != nil { - return nil, fmt.Errorf("failed to execute Elasticsearch query: %w", err) - } - defer res.Body.Close() - - if warnings, ok := res.Header["Warning"]; ok { - r.Log.Info(fmt.Sprintf(warningLogStringElastic, "Elasticsearch", warnings)) - } - - var result map[string]interface{} - if err := json.NewDecoder(res.Body).Decode(&result); err != nil { - return nil, fmt.Errorf("failed to parse Elasticsearch response: %w", err) - } - return result, nil + return metricValue, []byte{}, nil } -func (r *KeptnElasticProvider) extractMetric(result map[string]interface{}) (string, error) { - hits, ok := result["hits"].(map[string]interface{}) - if !ok { - return "", fmt.Errorf("invalid result format: missing 'hits' field") - } +func getTimeRangeFromSpec(rangeSpec *metricsapi.RangeSpec) time.Duration { + if rangeSpec == nil || rangeSpec.Interval == "" { + return defaultTimeRange + } - totalHits, ok := hits["total"].(map[string]interface{}) - if !ok { - return "", fmt.Errorf("invalid result format: missing 'total' field in 'hits'") - } + duration, err := time.ParseDuration(rangeSpec.Interval) + if err != nil { + return defaultTimeRange + } - value := fmt.Sprintf("%v", totalHits["value"]) + return duration +} - return value, nil +func (r *KeptnElasticProvider) runElasticQuery(ctx context.Context, query string, from, to time.Time) (map[string]interface{}, error) { + queryBody := fmt.Sprintf(` + { + "query": { + "bool": { + "must": [ + %s, + { + "range": { + "@timestamp": { + "gte": "%s", + "lte": "%s" + } + } + } + ] + } + } + }`, query, from.Format(time.RFC3339), to.Format(time.RFC3339)) + + res, err := r.Elastic.Search( + r.Elastic.Search.WithContext(ctx), + r.Elastic.Search.WithBody(strings.NewReader(queryBody)), + ) + if err != nil { + return nil, fmt.Errorf("failed to execute Elasticsearch query: %w", err) + } + defer res.Body.Close() + + if warnings, ok := res.Header["Warning"]; ok { + r.Log.Info(fmt.Sprintf(warningLogStringElastic, "Elasticsearch", warnings)) + } + + var result map[string]interface{} + if err := json.NewDecoder(res.Body).Decode(&result); err != nil { + return nil, fmt.Errorf("failed to parse Elasticsearch response: %w", err) + } + + return result, nil } + +func (r *KeptnElasticProvider) extractMetric(result map[string]interface{}) (string, error) { + var response ElasticsearchResponse + jsonData, err := json.Marshal(result) + if err != nil { + return "", fmt.Errorf("failed to marshal result: %w", err) + } + + if err := json.Unmarshal(jsonData, &response); err != nil { + return "", fmt.Errorf("failed to unmarshal result into struct: %w", err) + } + + value := fmt.Sprintf("%d", response.Hits.Total.Value) + return value, nil +} \ No newline at end of file From 8daeb287b590c7855f9a96ee49132551b8bd2429 Mon Sep 17 00:00:00 2001 From: Bharadwajshivam28 Date: Tue, 8 Oct 2024 15:22:55 +0530 Subject: [PATCH 6/6] feat: formatted elk files Signed-off-by: Bharadwajshivam28 --- metrics-operator/controllers/common/providers/elk/elk.go | 4 ++-- metrics-operator/controllers/common/providers/elk/elk_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/metrics-operator/controllers/common/providers/elk/elk.go b/metrics-operator/controllers/common/providers/elk/elk.go index 7b03c1fd9d..154759b7ef 100644 --- a/metrics-operator/controllers/common/providers/elk/elk.go +++ b/metrics-operator/controllers/common/providers/elk/elk.go @@ -7,9 +7,9 @@ import ( "strings" "time" + elastic "github.com/elastic/go-elasticsearch/v8" "github.com/go-logr/logr" metricsapi "github.com/keptn/lifecycle-toolkit/metrics-operator/api/v1" - elastic "github.com/elastic/go-elasticsearch/v8" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -148,4 +148,4 @@ func (r *KeptnElasticProvider) extractMetric(result map[string]interface{}) (str value := fmt.Sprintf("%d", response.Hits.Total.Value) return value, nil -} \ No newline at end of file +} diff --git a/metrics-operator/controllers/common/providers/elk/elk_test.go b/metrics-operator/controllers/common/providers/elk/elk_test.go index bbbc1fd7d6..9484f4cb1d 100644 --- a/metrics-operator/controllers/common/providers/elk/elk_test.go +++ b/metrics-operator/controllers/common/providers/elk/elk_test.go @@ -229,4 +229,4 @@ func TestKeptnElasticProvider_extractMetric(t *testing.T) { } }) } -} \ No newline at end of file +}