Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update datasource config field types #96

Merged
merged 8 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 9 additions & 12 deletions pkg/plugin/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import (
"database/sql"
"encoding/json"
"fmt"
sdkproxy "github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/lib/pq"
"golang.org/x/net/proxy"
"net"
"strconv"
"strings"
"time"

sdkproxy "github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/lib/pq"
"golang.org/x/net/proxy"

"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana-plugin-sdk-go/build"
Expand Down Expand Up @@ -106,14 +107,10 @@ func GenerateConnectionString(settings Settings, version string) (string, error)
connStr += fmt.Sprintf(" application_name='%s'", version)
}

if len(settings.Timeout) > 0 {
t, err := strconv.Atoi(settings.Timeout)
if err != nil {
return "", errors.New(fmt.Sprintf("invalid timeout: %s", settings.Timeout))
}

if t > -1 {
connStr += fmt.Sprintf(" connect_timeout=%d", t)
if settings.Timeout > 0 {
t := strconv.Itoa(int(settings.Timeout))
if i, err := strconv.Atoi(t); err == nil && i > -1 {
connStr += fmt.Sprintf(" connect_timeout=%d", i)
}
}

Expand Down Expand Up @@ -220,7 +217,7 @@ func (h *QuestDB) Settings(config backend.DataSourceInstanceSettings) sqlds.Driv
settings, err := LoadSettings(config)
timeout := 60
if err == nil {
t, err := strconv.Atoi(settings.QueryTimeout)
t, err := strconv.Atoi(strconv.FormatInt(settings.QueryTimeout, 10))
if err == nil {
timeout = t
}
Expand Down
28 changes: 17 additions & 11 deletions pkg/plugin/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ type Settings struct {
TlsClientCert string
TlsClientKey string

Timeout string `json:"timeout,omitempty"`
QueryTimeout string `json:"queryTimeout,omitempty"`
Timeout int64 `json:"timeout,omitempty"`
QueryTimeout int64 `json:"queryTimeout,omitempty"`
ProxyOptions *proxy.Options
MaxOpenConnections int64 `json:"maxOpenConnections,omitempty"`
MaxIdleConnections int64 `json:"maxIdleConnections,omitempty"`
Expand Down Expand Up @@ -83,22 +83,28 @@ func LoadSettings(config backend.DataSourceInstanceSettings) (settings Settings,
}

if jsonData["timeout"] != nil {
settings.Timeout = jsonData["timeout"].(string)
if val, ok := jsonData["timeout"].(string); ok {
timeout, err := strconv.ParseInt(val, 0, 64)
if err != nil {
return settings, fmt.Errorf("could not parse timeout value: %w", err)
}
settings.Timeout = timeout
}
if val, ok := jsonData["timeout"].(float64); ok {
settings.Timeout = int64(val)
}
}
if jsonData["queryTimeout"] != nil {
if val, ok := jsonData["queryTimeout"].(string); ok {
if val, ok := jsonData["queryTimeout"].(int64); ok {
settings.QueryTimeout = val
}
if val, ok := jsonData["queryTimeout"].(float64); ok {
settings.QueryTimeout = fmt.Sprintf("%d", int64(val))
settings.QueryTimeout = int64(val)
}
}

if strings.TrimSpace(settings.Timeout) == "" {
settings.Timeout = "10"
}
if strings.TrimSpace(settings.QueryTimeout) == "" {
settings.QueryTimeout = "60"
if strings.TrimSpace(strconv.FormatInt(settings.QueryTimeout, 10)) == "" {
settings.QueryTimeout = 60
}
password, ok := config.DecryptedSecureJSONData["password"]
if ok {
Expand Down Expand Up @@ -140,7 +146,7 @@ func LoadSettings(config backend.DataSourceInstanceSettings) (settings Settings,

if err == nil && proxyOpts != nil {
// the sdk expects the timeout to not be a string
timeout, err := strconv.ParseFloat(settings.Timeout, 64)
timeout, err := strconv.ParseFloat(strconv.FormatInt(settings.Timeout, 10), 64)
if err == nil {
proxyOpts.Timeouts.Timeout = (time.Duration(timeout) * time.Second)
}
Expand Down
24 changes: 12 additions & 12 deletions pkg/plugin/settings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestLoadSettings(t *testing.T) {
args: args{
config: backend.DataSourceInstanceSettings{
UID: "ds-uid",
JSONData: []byte(`{ "server": "test", "port": 8812, "username": "john", "timeout": "10", "queryTimeout": "50",
JSONData: []byte(`{ "server": "test", "port": 8812, "username": "john", "timeout": 10, "queryTimeout": 50,
"enableSecureSocksProxy": false, "tlsMode": "disable",
"maxOpenConnections": 100, "maxIdleConnections": 100, "maxConnectionLifetime": 14400 }`),
DecryptedSecureJSONData: map[string]string{"password": "doe"},
Expand All @@ -39,8 +39,8 @@ func TestLoadSettings(t *testing.T) {
Port: 8812,
Username: "john",
Password: "doe",
Timeout: "10",
QueryTimeout: "50",
Timeout: 10,
QueryTimeout: 50,
MaxOpenConnections: 100,
MaxIdleConnections: 100,
MaxConnectionLifetime: 14400,
Expand All @@ -53,7 +53,7 @@ func TestLoadSettings(t *testing.T) {
args: args{
config: backend.DataSourceInstanceSettings{
UID: "ds-uid",
JSONData: []byte(`{ "server": "test", "port": 1000, "username": "john", "timeout": "10", "queryTimeout": "50",
JSONData: []byte(`{ "server": "test", "port": 1000, "username": "john", "timeout": 10, "queryTimeout": 50,
"enableSecureSocksProxy": true, "tlsMode": "verify-full", "tlsConfigurationMethod": "file-content",
"maxOpenConnections": 100, "maxIdleConnections": 100, "maxConnectionLifetime": 14400 }`),
DecryptedSecureJSONData: map[string]string{"password": "doe", "tlsCACert": "caCert", "tlsClientCert": "clientCert", "tlsClientKey": "clientKey", "secureSocksProxyPassword": "test"},
Expand All @@ -67,8 +67,8 @@ func TestLoadSettings(t *testing.T) {
TlsCACert: "caCert",
TlsClientCert: "clientCert",
TlsClientKey: "clientKey",
Timeout: "10",
QueryTimeout: "50",
Timeout: 10,
QueryTimeout: 50,
MaxOpenConnections: 100,
MaxIdleConnections: 100,
MaxConnectionLifetime: 14400,
Expand Down Expand Up @@ -96,7 +96,7 @@ func TestLoadSettings(t *testing.T) {
JSONData: []byte(`{ "server": "test", "port": 8812, "username": "john",
"enableSecureSocksProxy": true, "tlsMode": "verify-ca", "tlsConfigurationMethod": "file-path",
"tlsCACertFile": "/var/caCertFile", "tlsClientCertFile": "/var/clientCertFile", "tlsClientKeyFile": "/var/clientKeyFile",
"timeout": "10", "queryTimeout": "50", "maxOpenConnections": 100, "maxIdleConnections": 100, "maxConnectionLifetime": 14400 }`),
"timeout": 10, "queryTimeout": 50, "maxOpenConnections": 100, "maxIdleConnections": 100, "maxConnectionLifetime": 14400 }`),
DecryptedSecureJSONData: map[string]string{"password": "rambo", "secureSocksProxyPassword": "test"},
},
},
Expand All @@ -108,8 +108,8 @@ func TestLoadSettings(t *testing.T) {
TlsCACertFile: "/var/caCertFile",
TlsClientCertFile: "/var/clientCertFile",
TlsClientKeyFile: "/var/clientKeyFile",
Timeout: "10",
QueryTimeout: "50",
Timeout: 10,
QueryTimeout: 50,
MaxOpenConnections: 100,
MaxIdleConnections: 100,
MaxConnectionLifetime: 14400,
Expand All @@ -133,7 +133,7 @@ func TestLoadSettings(t *testing.T) {
name: "should converting string values to the correct type",
args: args{
config: backend.DataSourceInstanceSettings{
JSONData: []byte(`{"server": "test", "username": "u", "port": "1234", "timeout": "15", "queryTimeout": "25", "maxOpenConnections": 10, "maxIdleConnections": 5, "maxConnectionLifetime": 3600 }`),
JSONData: []byte(`{"server": "test", "username": "u", "port": "1234", "timeout": 15, "queryTimeout": 25, "maxOpenConnections": 10, "maxIdleConnections": 5, "maxConnectionLifetime": 3600 }`),
DecryptedSecureJSONData: map[string]string{"password": "p"},
},
},
Expand All @@ -142,8 +142,8 @@ func TestLoadSettings(t *testing.T) {
Port: 1234,
Username: "u",
Password: "p",
Timeout: "15",
QueryTimeout: "25",
Timeout: 15,
QueryTimeout: 25,
MaxOpenConnections: 10,
MaxIdleConnections: 5,
MaxConnectionLifetime: 3600,
Expand Down
10 changes: 5 additions & 5 deletions src/__mocks__/datasource.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { PluginType } from '@grafana/data';
import {QuestDBQuery, QueryType} from '../types';
import { QuestDBQuery, QueryType, Format } from '../types';
import { Datasource } from '../data/QuestDbDatasource';

export const mockDatasource = new Datasource({
id: 1,
uid: 'questdb_ds',
type: 'questdb-questdb-datasource',
type: 'grafana-questdb-datasource',
name: 'QuestDB',
jsonData: {
server: 'foo.com',
port: 443,
username: 'user'
username: 'user',
},
readOnly: true,
access: 'direct',
meta: {
id: 'questdb-grafana-datasource',
id: 'questdb-questdb-datasource',
name: 'QuestDB',
type: PluginType.datasource,
module: '',
Expand All @@ -42,5 +42,5 @@ export const mockQuery: QuestDBQuery = {
refId: '',
format: 1,
queryType: QueryType.SQL,
selectedFormat: 4,
selectedFormat: Format.AUTO,
};
34 changes: 20 additions & 14 deletions src/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,18 @@ export const Components = {

TLSCACertFile: {
label: 'TLS/SSL Root Certificate File',
placeholder: 'If the selected TLS/SSL mode requires a server root certificate, provide the path to the file here.',
placeholder:
'If the selected TLS/SSL mode requires a server root certificate, provide the path to the file here.',
},
TLSClientCertFile: {
label: 'TLS/SSL Client Certificate File',
placeholder: 'To authenticate with an TLS/SSL client certificate, provide the path to the file here. Be sure that the file is readable by the user executing the grafana process.',
placeholder:
'To authenticate with an TLS/SSL client certificate, provide the path to the file here. Be sure that the file is readable by the user executing the grafana process.',
},
TLSClientKeyFile: {
label: 'TLS/SSL Client Key File',
placeholder: 'To authenticate with a client TLS/SSL certificate, provide the path to the corresponding key file here. Be sure that the file is only readable by the user executing the grafana process.'
placeholder:
'To authenticate with a client TLS/SSL certificate, provide the path to the corresponding key file here. Be sure that the file is only readable by the user executing the grafana process.',
},

Timeout: {
Expand All @@ -59,18 +62,20 @@ export const Components = {
},
TlsMode: {
label: 'TLS/SSL Mode',
tooltip: 'This option determines whether or with what priority a secure TLS/SSL TCP/IP connection will be negotiated with the server',
placeholder: "TLS/SSL Mode"
tooltip:
'This option determines whether or with what priority a secure TLS/SSL TCP/IP connection will be negotiated with the server. For QuestDB Cloud, use "require". For self-hosted QuestDB, use "disable".',
placeholder: 'TLS/SSL Mode',
},
TlsMethod: {
label: 'TLS/SSL Method',
tooltip: 'This option determines how TLS/SSL certifications are configured. Selecting ' +
'"File system path" will allow you to configure certificates by specifying paths to existing ' +
'certificates on the local file system where Grafana is running. Be sure that the file is ' +
'readable by the user executing the Grafana process. ' +
'Selecting "Certificate content" will allow you to configure certificates by specifying its ' +
'content. The content will be stored encrypted in Grafana\'s database.',
placeholder: 'TLS/SSL Method'
tooltip:
'This option determines how TLS/SSL certifications are configured. Selecting ' +
'"File system path" will allow you to configure certificates by specifying paths to existing ' +
'certificates on the local file system where Grafana is running. Be sure that the file is ' +
'readable by the user executing the Grafana process. ' +
'Selecting "Certificate content" will allow you to configure certificates by specifying its ' +
"content. The content will be stored encrypted in Grafana's database.",
placeholder: 'TLS/SSL Method',
},
SecureSocksProxy: {
label: 'Enable Secure Socks Proxy',
Expand All @@ -89,7 +94,8 @@ export const Components = {
MaxConnectionLifetime: {
label: 'Max lifetime',
placeholder: '14400',
tooltip: 'The maximum amount of time (in seconds) a connection may be reused. If set to 0, connections are reused forever.',
tooltip:
'The maximum amount of time (in seconds) a connection may be reused. If set to 0, connections are reused forever.',
},
},
QueryEditor: {
Expand Down Expand Up @@ -199,7 +205,7 @@ export const Components = {
},
DESIGNATED_TIMESTAMP: {
label: 'Designated timestamp',
tooltip: 'Select table\'s designated timestamp',
tooltip: "Select table's designated timestamp",
},
ALIGN_TO: {
label: 'Align to',
Expand Down
26 changes: 17 additions & 9 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export interface QuestDBConfig extends DataSourceJsonData {
tlsAuthWithCACert?: boolean;
secure?: boolean;
validate?: boolean;
timeout?: string;
queryTimeout?: string;
timeout?: number;
queryTimeout?: number;
enableSecureSocksProxy?: boolean;
maxOpenConnections?: number;
maxIdleConnections?: number;
Expand Down Expand Up @@ -92,17 +92,17 @@ export enum BuilderMode {
}

export enum SampleByFillMode {
None= 'NONE',
None = 'NONE',
Null = 'NULL',
Prev = 'PREV',
Linear = 'LINEAR'
Linear = 'LINEAR',
}

export enum SampleByAlignToMode {
FirstObservation = 'FIRST OBSERVATION',
Calendar = 'CALENDAR',
CalendarTimeZone = 'CALENDAR TIME ZONE',
CalendarOffset = 'CALENDAR WITH OFFSET'
CalendarOffset = 'CALENDAR WITH OFFSET',
}

export const modeRequiresValue = (mode: SampleByAlignToMode): boolean => {
Expand All @@ -119,7 +119,7 @@ export interface SqlBuilderOptionsList {
table?: string;
fields?: string[];
filters?: Filter[];
partitionBy?: string[]
partitionBy?: string[];
orderBy?: OrderBy[];
limit?: string;
timeField: string;
Expand Down Expand Up @@ -227,7 +227,7 @@ export enum FilterOperator {
ContainedBy = '<<',
ContainedByOrEqual = '<<=',
WithInGrafanaTimeRange = 'WITH IN DASHBOARD TIME RANGE',
OutsideGrafanaTimeRange = 'OUTSIDE DASHBOARD TIME RANGE'
OutsideGrafanaTimeRange = 'OUTSIDE DASHBOARD TIME RANGE',
}

export interface CommonFilterProps {
Expand All @@ -248,7 +248,15 @@ export interface BooleanFilter extends CommonFilterProps {
}

export interface StringFilter extends CommonFilterProps {
operator: FilterOperator.Equals | FilterOperator.NotEquals | FilterOperator.Like | FilterOperator.NotLike | FilterOperator.ILike | FilterOperator.NotILike | FilterOperator.Match | FilterOperator.NotMatch;
operator:
| FilterOperator.Equals
| FilterOperator.NotEquals
| FilterOperator.Like
| FilterOperator.NotLike
| FilterOperator.ILike
| FilterOperator.NotILike
| FilterOperator.Match
| FilterOperator.NotMatch;
value: string;
}

Expand Down Expand Up @@ -307,7 +315,7 @@ export const defaultBuilderQuery: Omit<QuestDBBuilderQuery, 'refId'> = {
mode: BuilderMode.List,
fields: [],
limit: '100',
timeField: ''
timeField: '',
},
format: Format.TABLE,
selectedFormat: Format.AUTO,
Expand Down
Loading
Loading