From 6f30825593b9b92569cf0629b64b6e74a6040aee Mon Sep 17 00:00:00 2001 From: Corentin Leruth Date: Wed, 6 Sep 2023 16:27:55 -0700 Subject: [PATCH 1/3] allow to provide an additional url path --- pkg/plugin/driver.go | 1 + pkg/plugin/settings.go | 4 ++++ src/__mocks__/ConfigEditor.ts | 1 + src/__mocks__/datasource.ts | 1 + src/selectors.ts | 5 +++++ src/types.ts | 1 + src/views/CHConfigEditor.tsx | 13 +++++++++++++ 7 files changed, 26 insertions(+) diff --git a/pkg/plugin/driver.go b/pkg/plugin/driver.go index 43b41319..8e34b62d 100644 --- a/pkg/plugin/driver.go +++ b/pkg/plugin/driver.go @@ -146,6 +146,7 @@ func (h *Clickhouse) Connect(config backend.DataSourceInstanceSettings, message }, TLS: tlsConfig, Addr: []string{fmt.Sprintf("%s:%d", settings.Server, settings.Port)}, + HttpUrlPath: settings.Path, Auth: clickhouse.Auth{ Username: settings.Username, Password: settings.Password, diff --git a/pkg/plugin/settings.go b/pkg/plugin/settings.go index a5d35195..76ad20c8 100644 --- a/pkg/plugin/settings.go +++ b/pkg/plugin/settings.go @@ -15,6 +15,7 @@ import ( type Settings struct { Server string `json:"server,omitempty"` Port int64 `json:"port,omitempty"` + Path string `json:"path,omitempty"` Username string `json:"username,omitempty"` DefaultDatabase string `json:"defaultDatabase,omitempty"` InsecureSkipVerify bool `json:"tlsSkipVerify,omitempty"` @@ -70,6 +71,9 @@ func LoadSettings(config backend.DataSourceInstanceSettings) (settings Settings, if jsonData["username"] != nil { settings.Username = jsonData["username"].(string) } + if jsonData["path"] != nil { + settings.Path = jsonData["path"].(string) + } if jsonData["defaultDatabase"] != nil { settings.DefaultDatabase = jsonData["defaultDatabase"].(string) } diff --git a/src/__mocks__/ConfigEditor.ts b/src/__mocks__/ConfigEditor.ts index b490c611..799bd7bb 100644 --- a/src/__mocks__/ConfigEditor.ts +++ b/src/__mocks__/ConfigEditor.ts @@ -9,6 +9,7 @@ export const mockConfigEditorProps = (): Props => ({ jsonData: { server: 'foo.com', port: 443, + path: '', username: 'user', protocol: 'native', }, diff --git a/src/__mocks__/datasource.ts b/src/__mocks__/datasource.ts index 83d97bdc..edf2aa83 100644 --- a/src/__mocks__/datasource.ts +++ b/src/__mocks__/datasource.ts @@ -10,6 +10,7 @@ export const mockDatasource = new Datasource({ jsonData: { server: 'foo.com', port: 443, + path: '', username: 'user', defaultDatabase: 'foo', protocol: Protocol.NATIVE, diff --git a/src/selectors.ts b/src/selectors.ts index b97c5985..fb612de3 100644 --- a/src/selectors.ts +++ b/src/selectors.ts @@ -11,6 +11,11 @@ export const Components = { placeholder: (secure: string) => `Typically ${secure === 'true' ? '9440' : '9000'}`, tooltip: 'ClickHouse native TCP port. Typically 9000 for unsecure, 9440 for secure', }, + Path: { + label: 'Path', + placeholder: 'Additional URL path for HTTP requests', + tooltip: 'Additional URL path for HTTP requests', + }, Protocol: { label: 'Protocol', tooltip: 'Native or HTTP for transport', diff --git a/src/types.ts b/src/types.ts index a35fffd8..32c41ed4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,6 +7,7 @@ export interface CHConfig extends DataSourceJsonData { server: string; protocol: Protocol; port: number; + path: string; defaultDatabase?: string; tlsSkipVerify?: boolean; tlsAuth?: boolean; diff --git a/src/views/CHConfigEditor.tsx b/src/views/CHConfigEditor.tsx index 10a7de06..6c35c1c0 100644 --- a/src/views/CHConfigEditor.tsx +++ b/src/views/CHConfigEditor.tsx @@ -162,6 +162,19 @@ export const ConfigEditor: React.FC = (props) => { tooltip={Components.ConfigEditor.ServerPort.tooltip} /> +
+ +
{Components.ConfigEditor.Protocol.label} From 8a0dbf2fa7f659f4a9271cea05b65022346f28be Mon Sep 17 00:00:00 2001 From: Corentin Leruth Date: Wed, 6 Sep 2023 16:39:44 -0700 Subject: [PATCH 2/3] add a changelog entry --- CHANGELOG.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5e1d6e4..94558435 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,23 +1,34 @@ # Changelog +## Unreleased + +### Features + +- Add a new optional `path` setting to specify an additional URL path. [#512](https://github.com/grafana/clickhouse-datasource/pull/512) + ## 3.3.0 ### Features + - Support Point geo data type. ### Fixes + - Fix timeInterval_ms macro. - Fix Table summary and Parts over time panels in Data Analysis dashboard. ### Upgrades + - Upgrade [grafana-plugin-sdk-go](https://github.com/grafana/grafana-plugin-sdk-go). ## 3.2.0 ### Features + - Add `timeInterval_ms` macro to allow higher precision queries on DateTime64 columns. [#462](https://github.com/grafana/clickhouse-datasource/pull/462). ### Fixes + - Ensure databases, tables, and columns are escaped correctly. [#460](https://github.com/grafana/clickhouse-datasource/pull/460). - Fix conditionAll handling. [#459](https://github.com/grafana/clickhouse-datasource/pull/459). - Fix support for ad-hoc regexp filters: `=~`, `!~` [#414](https://github.com/grafana/clickhouse-datasource/pull/414). @@ -42,19 +53,20 @@ - Custom ClickHouse settings can be set in data source settings. [Allow passing custom ClickHouse settings in datasource](https://github.com/grafana/clickhouse-datasource/pull/366) - Histogram UI fixes [Histogram UI fixes](https://github.com/grafana/clickhouse-datasource/pull/363) - - Support filter/filter out logs view actions - - Fix undefined database name by default - - Reset level and time field properly on table/database change - - Make it possible to clear the level field (so the histogram will render without grouping by level) - - Fix filter value that gets stuck in the UI + - Support filter/filter out logs view actions + - Fix undefined database name by default + - Reset level and time field properly on table/database change + - Make it possible to clear the level field (so the histogram will render without grouping by level) + - Fix filter value that gets stuck in the UI - Tracing dashboard added to default dashboards. [Tracing dashboard ](https://github.com/grafana/clickhouse-datasource/pull/336) ## 3.0.1-beta -- Users on v8.x of Grafana are encouraged to continue to use v2.2.0 of the plugin. +- Users on v8.x of Grafana are encouraged to continue to use v2.2.0 of the plugin. - Users of Grafana v9.x can use v3 however it is beta and may contain bugs. ## 3.0.0 + - **Feature** - [Logs volume histogram support](https://github.com/grafana/clickhouse-datasource/pull/352) - **Chore** - Update clickhouse-go to v2.8.1 @@ -75,12 +87,12 @@ ## 2.1.0 - **Fix** - Quote table names with dots by @slvrtrn in https://github.com/grafana/clickhouse-datasource/pull/298 -- Add a predefined TimeRange filter if there is at least one DateTime* column by @slvrtrn in https://github.com/grafana/clickhouse-datasource/pull/304 +- Add a predefined TimeRange filter if there is at least one DateTime\* column by @slvrtrn in https://github.com/grafana/clickhouse-datasource/pull/304 ## 2.0.7 -- **Fix** - Empty template variables used with the conditionalAll macro work the same as selecting All. [Allow empty Inputs for $__conditionalAll](https://github.com/grafana/clickhouse-datasource/issues/262) -- **Fix** - Intervals are limited to 1 second. [limit $__interval_s to at least 1 second](https://github.com/grafana/clickhouse-datasource/pull/270) +- **Fix** - Empty template variables used with the conditionalAll macro work the same as selecting All. [Allow empty Inputs for $\_\_conditionalAll](https://github.com/grafana/clickhouse-datasource/issues/262) +- **Fix** - Intervals are limited to 1 second. [limit $\_\_interval_s to at least 1 second](https://github.com/grafana/clickhouse-datasource/pull/270) - **Chore** - Bump ClickHouse go API to v2.5.1 [Bump github.com/ClickHouse/clickhouse-go/v2 from 2.4.3 to 2.5.1](https://github.com/grafana/clickhouse-datasource/pull/283) ## 2.0.6 @@ -171,7 +183,7 @@ ## 0.12.0 -- **Feature** - Time series builder: use $__timeInterval macro on time field so buckets can be adjusted from query options. +- **Feature** - Time series builder: use $\_\_timeInterval macro on time field so buckets can be adjusted from query options. ## 0.11.0 @@ -191,7 +203,7 @@ ## 0.9.11 -- **Feature** - $__timeInterval(column) and $__interval_s macros +- **Feature** - $**timeInterval(column) and $**interval_s macros ## 0.9.10 From 6dacbed7a8aec0affe255b716c2fdf85859e584c Mon Sep 17 00:00:00 2001 From: Corentin Leruth Date: Thu, 7 Sep 2023 10:45:08 -0700 Subject: [PATCH 3/3] add tests --- pkg/plugin/driver_test.go | 6 ++++-- pkg/plugin/settings_test.go | 6 ++++-- src/views/CHConfigEditor.test.tsx | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/pkg/plugin/driver_test.go b/pkg/plugin/driver_test.go index 0f24d134..014cedb2 100644 --- a/pkg/plugin/driver_test.go +++ b/pkg/plugin/driver_test.go @@ -124,11 +124,12 @@ func TestConnect(t *testing.T) { ssl := getEnv("CLICKHOUSE_SSL", "false") queryTimeoutNumber := 3600 queryTimeoutString := "3600" + path := "custom-path" clickhouse := plugin.Clickhouse{} t.Run("should not error when valid settings passed", func(t *testing.T) { secure := map[string]string{} secure["password"] = password - settings := backend.DataSourceInstanceSettings{JSONData: []byte(fmt.Sprintf(`{ "server": "%s", "port": %s, "username": "%s", "secure": %s, "queryTimeout": "%s"}`, host, port, username, ssl, queryTimeoutString)), DecryptedSecureJSONData: secure} + settings := backend.DataSourceInstanceSettings{JSONData: []byte(fmt.Sprintf(`{ "server": "%s", "port": %s, "path": "%s", "username": "%s", "secure": %s, "queryTimeout": "%s"}`, host, port, path, username, ssl, queryTimeoutString)), DecryptedSecureJSONData: secure} _, err := clickhouse.Connect(settings, json.RawMessage{}) assert.Equal(t, nil, err) }) @@ -147,11 +148,12 @@ func TestHTTPConnect(t *testing.T) { username := getEnv("CLICKHOUSE_USERNAME", "default") password := getEnv("CLICKHOUSE_PASSWORD", "") ssl := getEnv("CLICKHOUSE_SSL", "false") + path := "custom-path" clickhouse := plugin.Clickhouse{} t.Run("should not error when valid settings passed", func(t *testing.T) { secure := map[string]string{} secure["password"] = password - settings := backend.DataSourceInstanceSettings{JSONData: []byte(fmt.Sprintf(`{ "server": "%s", "port": %s, "username": "%s", "secure": %s, "protocol": "http" }`, host, port, username, ssl)), DecryptedSecureJSONData: secure} + settings := backend.DataSourceInstanceSettings{JSONData: []byte(fmt.Sprintf(`{ "server": "%s", "port": %s, "path": "%s", "username": "%s", "secure": %s, "protocol": "http" }`, host, port, path, username, ssl)), DecryptedSecureJSONData: secure} _, err := clickhouse.Connect(settings, json.RawMessage{}) assert.Equal(t, nil, err) }) diff --git a/pkg/plugin/settings_test.go b/pkg/plugin/settings_test.go index 543af4dd..76a63f1e 100644 --- a/pkg/plugin/settings_test.go +++ b/pkg/plugin/settings_test.go @@ -28,13 +28,14 @@ func TestLoadSettings(t *testing.T) { args: args{ config: backend.DataSourceInstanceSettings{ UID: "ds-uid", - JSONData: []byte(`{ "server": "foo", "port": 443, "username": "baz", "defaultDatabase":"example", "tlsSkipVerify": true, "tlsAuth" : true, "tlsAuthWithCACert": true, "timeout": "10", "enableSecureSocksProxy": true}`), + JSONData: []byte(`{ "server": "foo", "port": 443, "path": "custom-path", "username": "baz", "defaultDatabase":"example", "tlsSkipVerify": true, "tlsAuth" : true, "tlsAuthWithCACert": true, "timeout": "10", "enableSecureSocksProxy": true}`), DecryptedSecureJSONData: map[string]string{"password": "bar", "tlsCACert": "caCert", "tlsClientCert": "clientCert", "tlsClientKey": "clientKey", "secureSocksProxyPassword": "test"}, }, }, wantSettings: Settings{ Server: "foo", Port: 443, + Path: "custom-path", Username: "baz", DefaultDatabase: "example", InsecureSkipVerify: true, @@ -64,13 +65,14 @@ func TestLoadSettings(t *testing.T) { name: "should converting string values to the correct type)", args: args{ config: backend.DataSourceInstanceSettings{ - JSONData: []byte(`{"server": "test", "port": "443", "tlsSkipVerify": "true", "tlsAuth" : "true", "tlsAuthWithCACert": "true"}`), + JSONData: []byte(`{"server": "test", "port": "443", "path": "custom-path", "tlsSkipVerify": "true", "tlsAuth" : "true", "tlsAuthWithCACert": "true"}`), DecryptedSecureJSONData: map[string]string{}, }, }, wantSettings: Settings{ Server: "test", Port: 443, + Path: "custom-path", InsecureSkipVerify: true, TlsClientAuth: true, TlsAuthWithCACert: true, diff --git a/src/views/CHConfigEditor.test.tsx b/src/views/CHConfigEditor.test.tsx index e48b902f..27b70e78 100644 --- a/src/views/CHConfigEditor.test.tsx +++ b/src/views/CHConfigEditor.test.tsx @@ -13,6 +13,7 @@ describe('ConfigEditor', () => { expect(screen.getByPlaceholderText(Components.ConfigEditor.ServerPort.placeholder('false'))).toBeInTheDocument(); expect(screen.getByPlaceholderText(Components.ConfigEditor.Username.placeholder)).toBeInTheDocument(); expect(screen.getByPlaceholderText(Components.ConfigEditor.Password.placeholder)).toBeInTheDocument(); + expect(screen.getByPlaceholderText(Components.ConfigEditor.Path.placeholder)).toBeInTheDocument(); expect(screen.getByPlaceholderText(Components.ConfigEditor.DefaultDatabase.placeholder)).toBeInTheDocument(); expect(screen.getByPlaceholderText(Components.ConfigEditor.Timeout.placeholder)).toBeInTheDocument(); expect(screen.getByPlaceholderText(Components.ConfigEditor.QueryTimeout.placeholder)).toBeInTheDocument(); @@ -37,6 +38,19 @@ describe('ConfigEditor', () => { expect(screen.getByPlaceholderText(Components.ConfigEditor.Timeout.placeholder)).toBeInTheDocument(); expect(screen.getByPlaceholderText(Components.ConfigEditor.QueryTimeout.placeholder)).toBeInTheDocument(); }); + it('with path', async () => { + const path = 'custom-path'; + render( + + ); + expect(screen.queryByPlaceholderText(Components.ConfigEditor.Path.placeholder)).toHaveValue(path); + }); it('with secure connection', async () => { render(