From 51a59a2089a1f7adcd036456880c9bc7779b6aa8 Mon Sep 17 00:00:00 2001 From: Ales Pour Date: Wed, 17 Jul 2024 11:24:21 +0200 Subject: [PATCH 01/13] fix: set active database from ON clause --- server/influx.go | 44 +++++++++++++++----- server/influx_test.go | 94 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 10 deletions(-) diff --git a/server/influx.go b/server/influx.go index 4ae2ee28b9..2359d6d9a6 100644 --- a/server/influx.go +++ b/server/influx.go @@ -173,26 +173,50 @@ func (s *Service) Write(w http.ResponseWriter, r *http.Request) { // setupQueryFromCommand set query parameters from its command func setupQueryFromCommand(req *chronograf.Query) { - // allow to set active database with USE command, examples: + // normalize whitespaces + req.Command = strings.Join(strings.Fields(req.Command), " ") + + // set active database (and retention policy) from the query + useDb := func(dbSpec string) error { + dbSpecReader := csv.NewReader(bytes.NewReader(([]byte)(dbSpec))) + dbSpecReader.Comma = '.' + if dbrp, err := dbSpecReader.Read(); err == nil { + fmt.Println(dbrp) + if len(dbrp) > 0 { + req.DB = dbrp[0] + } + if len(dbrp) > 1 { + req.RP = dbrp[1] + } + } else { + return err + } + return nil + } + + // allow to set active database with USE command or via ON clause, examples: // use mydb // use "mydb" // USE "mydb"."myrp" // use "mydb.myrp" // use mydb.myrp + // show tag keys on "mydb" + // SHOW TAG KEYS ON "mydb" if strings.HasPrefix(req.Command, "use ") || strings.HasPrefix(req.Command, "USE ") { if nextCommand := strings.IndexRune(req.Command, ';'); nextCommand > 4 { dbSpec := strings.TrimSpace(req.Command[4:nextCommand]) - dbSpecReader := csv.NewReader(bytes.NewReader(([]byte)(dbSpec))) - dbSpecReader.Comma = '.' - if dbrp, err := dbSpecReader.Read(); err == nil { - if len(dbrp) > 0 { - req.DB = dbrp[0] - } - if len(dbrp) > 1 { - req.RP = dbrp[1] - } + if useDb(dbSpec) == nil { req.Command = strings.TrimSpace(req.Command[nextCommand+1:]) } } + } else if strings.Contains(req.Command, " on ") || strings.Contains(req.Command, " ON ") { + fields := strings.Fields(req.Command) + for i, field := range fields { + if field == "on" || field == "ON" { + if i < len(fields)-1 { + _ = useDb(fields[i+1]) + } + } + } } } diff --git a/server/influx_test.go b/server/influx_test.go index 3cd88b3a5f..d43d32f759 100644 --- a/server/influx_test.go +++ b/server/influx_test.go @@ -217,6 +217,100 @@ func TestService_Influx_UseCommand(t *testing.T) { } } +// TestService_Influx_CommandWithOnClause tests preprocessing of command with ON clause +func TestService_Influx_CommandWithOnClause(t *testing.T) { + tests := []struct { + name string + db string + rp string + }{ + { + name: "/* no command */", + }, + { + name: "SHOW MEASUREMENTS", + }, + { + name: "SHOW TAG KEYS ON mydb", + db: "mydb", + }, + { + name: "SHOW TAG KEYS ON mydb FROM table", + db: "mydb", + }, + { + name: `show tag keys on "mydb"`, + db: "mydb", + }, + { + name: `show tag keys on "mydb" from "table"`, + db: "mydb", + }, + } + + h := &Service{ + Store: &mocks.Store{ + SourcesStore: &mocks.SourcesStore{ + GetF: func(ctx context.Context, ID int) (chronograf.Source, error) { + return chronograf.Source{ + ID: 1337, + URL: "http://any.url", + }, nil + }, + }, + }, + TimeSeriesClient: &mocks.TimeSeries{ + ConnectF: func(ctx context.Context, src *chronograf.Source) error { + return nil + }, + QueryF: func(ctx context.Context, query chronograf.Query) (chronograf.Response, error) { + return mocks.NewResponse( + fmt.Sprintf(`{"db":"%s","rp":"%s"}`, query.DB, query.RP), + nil, + ), + nil + }, + }, + Logger: log.New(log.ErrorLevel), + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + prefixCommand := strings.ReplaceAll(tt.name, "\"", "\\\"") + w := httptest.NewRecorder() + r := httptest.NewRequest( + "POST", + "http://any.url", + ioutil.NopCloser( + bytes.NewReader([]byte( + `{"uuid": "tst", "query":"`+prefixCommand+` ; DROP MEASUREMENT test"}`, + )), + ), + ) + r = r.WithContext(httprouter.WithParams( + context.Background(), + httprouter.Params{ + { + Key: "id", + Value: "1", + }, + }, + )) + + h.Influx(w, r) + + resp := w.Result() + body, _ := ioutil.ReadAll(resp.Body) + + want := fmt.Sprintf(`{"results":{"db":"%s","rp":"%s"},"uuid":"tst"}`, tt.db, tt.rp) + got := strings.TrimSpace(string(body)) + if got != want { + t.Errorf("%q. Influx() =\ngot ***%v***\nwant ***%v***\n", tt.name, got, want) + } + + }) + } +} + func TestService_Influx_Write(t *testing.T) { calledPath := "" ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { From 140d0be29b01f8a9c557dd4fd13b0f0cd431600e Mon Sep 17 00:00:00 2001 From: Ales Pour Date: Wed, 17 Jul 2024 12:01:34 +0200 Subject: [PATCH 02/13] fix: use first ON clause for settings active database --- server/influx.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/influx.go b/server/influx.go index 2359d6d9a6..12dc6758c6 100644 --- a/server/influx.go +++ b/server/influx.go @@ -216,6 +216,7 @@ func setupQueryFromCommand(req *chronograf.Query) { if i < len(fields)-1 { _ = useDb(fields[i+1]) } + break } } } From 95cb13c01e88eeb7eeeed8d81acbf27cfb231f57 Mon Sep 17 00:00:00 2001 From: Ales Pour Date: Wed, 17 Jul 2024 12:01:59 +0200 Subject: [PATCH 03/13] test: extend ON clause command test --- server/influx_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/influx_test.go b/server/influx_test.go index d43d32f759..52abd68c76 100644 --- a/server/influx_test.go +++ b/server/influx_test.go @@ -238,6 +238,10 @@ func TestService_Influx_CommandWithOnClause(t *testing.T) { name: "SHOW TAG KEYS ON mydb FROM table", db: "mydb", }, + { + name: "USE anotherdb; SHOW TAG KEYS ON mydb", + db: "anotherdb", + }, { name: `show tag keys on "mydb"`, db: "mydb", From bbbcce7e6e0fda11e3170bc26490e559aaf6909e Mon Sep 17 00:00:00 2001 From: Ales Pour Date: Wed, 17 Jul 2024 12:18:52 +0200 Subject: [PATCH 04/13] docs: update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c264ebbbc0..b161f7939f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## [unreleased] +### Bug Fixes + +1. [#6103](https://github.com/influxdata/chronograf/pull/6103): Set active database for InfluxQL meta queries with Cloud Serverless. + ### Other 1. [#6102](https://github.com/influxdata/chronograf/pull/6102): Upgrade golang to 1.21.12. From a2f7898aee91954c9536e46f7b4cc6c2fad2c4e5 Mon Sep 17 00:00:00 2001 From: Ales Pour Date: Wed, 17 Jul 2024 12:39:59 +0200 Subject: [PATCH 05/13] docs: update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b161f7939f..30bb8d26b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Bug Fixes -1. [#6103](https://github.com/influxdata/chronograf/pull/6103): Set active database for InfluxQL meta queries with Cloud Serverless. +1. [#6103](https://github.com/influxdata/chronograf/pull/6103): Set active database for InfluxQL meta queries. ### Other From ce18fb2d7c0815a577f43203e492c43d0b3d0e7e Mon Sep 17 00:00:00 2001 From: Ales Pour Date: Wed, 17 Jul 2024 19:35:50 +0200 Subject: [PATCH 06/13] fix: remove useless fmt.Println --- server/influx.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/influx.go b/server/influx.go index 12dc6758c6..7ae2016b76 100644 --- a/server/influx.go +++ b/server/influx.go @@ -181,7 +181,6 @@ func setupQueryFromCommand(req *chronograf.Query) { dbSpecReader := csv.NewReader(bytes.NewReader(([]byte)(dbSpec))) dbSpecReader.Comma = '.' if dbrp, err := dbSpecReader.Read(); err == nil { - fmt.Println(dbrp) if len(dbrp) > 0 { req.DB = dbrp[0] } From 3d4d056bd80c2aff1a80d56b00be58ebd1a8af06 Mon Sep 17 00:00:00 2001 From: Ales Pour Date: Wed, 17 Jul 2024 19:37:38 +0200 Subject: [PATCH 07/13] refactor: simplify if-else --- server/influx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/influx.go b/server/influx.go index 7ae2016b76..4480c40e46 100644 --- a/server/influx.go +++ b/server/influx.go @@ -187,10 +187,10 @@ func setupQueryFromCommand(req *chronograf.Query) { if len(dbrp) > 1 { req.RP = dbrp[1] } + return nil } else { return err } - return nil } // allow to set active database with USE command or via ON clause, examples: From 65f4aab287c48cd543d7182f8b01684ba91aee70 Mon Sep 17 00:00:00 2001 From: alespour <42931850+alespour@users.noreply.github.com> Date: Fri, 19 Jul 2024 08:44:41 +0200 Subject: [PATCH 08/13] test: extend with edge cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Bednář --- server/influx_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/server/influx_test.go b/server/influx_test.go index 52abd68c76..180331f2ac 100644 --- a/server/influx_test.go +++ b/server/influx_test.go @@ -250,6 +250,22 @@ func TestService_Influx_CommandWithOnClause(t *testing.T) { name: `show tag keys on "mydb" from "table"`, db: "mydb", }, + { + name: `show tag keys on "my_db" from "table"`, + db: "my_db", + }, + { + name: `show tag keys on "my-db" from "table"`, + db: "my-db", + }, + { + name: `show tag keys on "my/db" from "table"`, + db: "my/db", + }, + { + name: `show tag keys on "my db" from "table"`, + db: "my db", + }, } h := &Service{ From c056486e7f64f7d9fc4998bfb61dcd723466abb3 Mon Sep 17 00:00:00 2001 From: alespour <42931850+alespour@users.noreply.github.com> Date: Fri, 19 Jul 2024 08:45:29 +0200 Subject: [PATCH 09/13] test: extend with typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Bednář --- server/influx_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/influx_test.go b/server/influx_test.go index 180331f2ac..92d6b16a3e 100644 --- a/server/influx_test.go +++ b/server/influx_test.go @@ -246,6 +246,10 @@ func TestService_Influx_CommandWithOnClause(t *testing.T) { name: `show tag keys on "mydb"`, db: "mydb", }, + { + name: `show tag keys oN "mydb"`, + db: "mydb", + }, { name: `show tag keys on "mydb" from "table"`, db: "mydb", From e1a0fc02e1ca27cc664ba9639af8cbcd0496f589 Mon Sep 17 00:00:00 2001 From: alespour <42931850+alespour@users.noreply.github.com> Date: Fri, 19 Jul 2024 08:50:10 +0200 Subject: [PATCH 10/13] fix: always compare keywords in lowercase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Bednář --- server/influx.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/influx.go b/server/influx.go index 4480c40e46..3326ba5422 100644 --- a/server/influx.go +++ b/server/influx.go @@ -201,17 +201,18 @@ func setupQueryFromCommand(req *chronograf.Query) { // use mydb.myrp // show tag keys on "mydb" // SHOW TAG KEYS ON "mydb" - if strings.HasPrefix(req.Command, "use ") || strings.HasPrefix(req.Command, "USE ") { + command := strings.ToLower(req.Command) + if strings.HasPrefix(command, "use ") { if nextCommand := strings.IndexRune(req.Command, ';'); nextCommand > 4 { dbSpec := strings.TrimSpace(req.Command[4:nextCommand]) if useDb(dbSpec) == nil { req.Command = strings.TrimSpace(req.Command[nextCommand+1:]) } } - } else if strings.Contains(req.Command, " on ") || strings.Contains(req.Command, " ON ") { + } else if strings.Contains(command, " on ") { fields := strings.Fields(req.Command) for i, field := range fields { - if field == "on" || field == "ON" { + if strings.ToLower(field) == "on" { if i < len(fields)-1 { _ = useDb(fields[i+1]) } From 29f527e74d426a8c454d44d6a0ed979084bd8c39 Mon Sep 17 00:00:00 2001 From: Ales Pour Date: Fri, 19 Jul 2024 11:24:27 +0200 Subject: [PATCH 11/13] test: add case with more whitespace chars --- server/influx_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/influx_test.go b/server/influx_test.go index 92d6b16a3e..8892dc1177 100644 --- a/server/influx_test.go +++ b/server/influx_test.go @@ -270,6 +270,10 @@ func TestService_Influx_CommandWithOnClause(t *testing.T) { name: `show tag keys on "my db" from "table"`, db: "my db", }, + { + name: `show tag values on "my db" from "table" with key = "my key"`, + db: "my db", + }, } h := &Service{ From 79e735154a1393e25ef1bec5fa85712e1f76f998 Mon Sep 17 00:00:00 2001 From: Ales Pour Date: Fri, 19 Jul 2024 11:26:04 +0200 Subject: [PATCH 12/13] fix: handle queries with redundant or more whitespaces in values --- server/influx.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/server/influx.go b/server/influx.go index 3326ba5422..740d615b0b 100644 --- a/server/influx.go +++ b/server/influx.go @@ -173,14 +173,12 @@ func (s *Service) Write(w http.ResponseWriter, r *http.Request) { // setupQueryFromCommand set query parameters from its command func setupQueryFromCommand(req *chronograf.Query) { - // normalize whitespaces - req.Command = strings.Join(strings.Fields(req.Command), " ") - - // set active database (and retention policy) from the query + // sets active database (and retention policy) from the query useDb := func(dbSpec string) error { dbSpecReader := csv.NewReader(bytes.NewReader(([]byte)(dbSpec))) dbSpecReader.Comma = '.' if dbrp, err := dbSpecReader.Read(); err == nil { + fmt.Println(dbrp) if len(dbrp) > 0 { req.DB = dbrp[0] } @@ -210,13 +208,24 @@ func setupQueryFromCommand(req *chronograf.Query) { } } } else if strings.Contains(command, " on ") { - fields := strings.Fields(req.Command) - for i, field := range fields { - if strings.ToLower(field) == "on" { - if i < len(fields)-1 { - _ = useDb(fields[i+1]) + r := csv.NewReader(strings.NewReader(req.Command)) + r.Comma = ' ' + if tokens, err := r.Read(); err == nil { + // filter empty tokens (i.e. redundant whitespaces, using https://go.dev/wiki/SliceTricks#filtering-without-allocating) + fields := tokens[:0] + for _, field := range tokens { + if field != "" { + fields = append(fields, field) + } + } + // try to find ON clause and use its value to set the database + for i, field := range fields { + if strings.ToLower(field) == "on" { + if i < len(fields)-1 { + _ = useDb(fields[i+1]) + } + break } - break } } } From 991e2e4b632b9c9f79cc667dc3bd7ec63dc54c16 Mon Sep 17 00:00:00 2001 From: Ales Pour Date: Fri, 19 Jul 2024 11:54:25 +0200 Subject: [PATCH 13/13] fix: remove useless fmt.Println --- server/influx.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/influx.go b/server/influx.go index 740d615b0b..0c87ccb5b4 100644 --- a/server/influx.go +++ b/server/influx.go @@ -178,7 +178,6 @@ func setupQueryFromCommand(req *chronograf.Query) { dbSpecReader := csv.NewReader(bytes.NewReader(([]byte)(dbSpec))) dbSpecReader.Comma = '.' if dbrp, err := dbSpecReader.Read(); err == nil { - fmt.Println(dbrp) if len(dbrp) > 0 { req.DB = dbrp[0] }