From 5ed80a60e72804d6e89638dc9263259c646cd8cf Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Wed, 11 Aug 2021 13:32:37 +0300 Subject: [PATCH] Fix parsing timeout (use number instead of string), fixes #1254 --- pkg/datasource/datasource.go | 76 ++---------- pkg/datasource/models.go | 24 ---- pkg/datasource/zabbix_test.go | 3 +- pkg/settings/models.go | 27 ++++ pkg/{zabbix => settings}/settings.go | 46 ++++--- pkg/zabbix/testing.go | 7 +- pkg/zabbix/zabbix.go | 10 +- .../components/ConfigEditor.tsx | 116 +++++++++--------- src/datasource-zabbix/migrations.ts | 8 +- src/datasource-zabbix/types.ts | 2 +- 10 files changed, 143 insertions(+), 176 deletions(-) create mode 100644 pkg/settings/models.go rename pkg/{zabbix => settings}/settings.go (54%) diff --git a/pkg/datasource/datasource.go b/pkg/datasource/datasource.go index 035703e..62a852d 100644 --- a/pkg/datasource/datasource.go +++ b/pkg/datasource/datasource.go @@ -2,16 +2,11 @@ package datasource import ( "context" - "encoding/json" "errors" - "strconv" - "time" - - "github.com/alexanderzobnin/grafana-zabbix/pkg/gtime" "github.com/alexanderzobnin/grafana-zabbix/pkg/httpclient" + "github.com/alexanderzobnin/grafana-zabbix/pkg/settings" "github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix" "github.com/alexanderzobnin/grafana-zabbix/pkg/zabbixapi" - "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" @@ -33,7 +28,7 @@ type ZabbixDatasource struct { type ZabbixDatasourceInstance struct { zabbix *zabbix.Zabbix dsInfo *backend.DataSourceInstanceSettings - Settings *ZabbixDatasourceSettings + Settings *settings.ZabbixDatasourceSettings logger log.Logger } @@ -46,36 +41,36 @@ func NewZabbixDatasource() *ZabbixDatasource { } // newZabbixDatasourceInstance returns an initialized zabbix datasource instance -func newZabbixDatasourceInstance(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { +func newZabbixDatasourceInstance(dsSettings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { logger := log.New() logger.Debug("Initializing new data source instance") - zabbixSettings, err := readZabbixSettings(&settings) + zabbixSettings, err := settings.ReadZabbixSettings(&dsSettings) if err != nil { logger.Error("Error parsing Zabbix settings", "error", err) return nil, err } - client, err := httpclient.New(&settings, zabbixSettings.Timeout) + client, err := httpclient.New(&dsSettings, zabbixSettings.Timeout) if err != nil { logger.Error("Error initializing HTTP client", "error", err) return nil, err } - zabbixAPI, err := zabbixapi.New(settings.URL, client) + zabbixAPI, err := zabbixapi.New(dsSettings.URL, client) if err != nil { logger.Error("Error initializing Zabbix API", "error", err) return nil, err } - zabbixClient, err := zabbix.New(&settings, zabbixAPI) + zabbixClient, err := zabbix.New(&dsSettings, zabbixSettings, zabbixAPI) if err != nil { logger.Error("Error initializing Zabbix client", "error", err) return nil, err } return &ZabbixDatasourceInstance{ - dsInfo: &settings, + dsInfo: &dsSettings, zabbix: zabbixClient, Settings: zabbixSettings, logger: logger, @@ -153,58 +148,3 @@ func (ds *ZabbixDatasource) getDSInstance(pluginContext backend.PluginContext) ( } return instance.(*ZabbixDatasourceInstance), nil } - -func readZabbixSettings(dsInstanceSettings *backend.DataSourceInstanceSettings) (*ZabbixDatasourceSettings, error) { - zabbixSettingsDTO := &ZabbixDatasourceSettingsDTO{} - - err := json.Unmarshal(dsInstanceSettings.JSONData, &zabbixSettingsDTO) - if err != nil { - return nil, err - } - - if zabbixSettingsDTO.TrendsFrom == "" { - zabbixSettingsDTO.TrendsFrom = "7d" - } - if zabbixSettingsDTO.TrendsRange == "" { - zabbixSettingsDTO.TrendsRange = "4d" - } - if zabbixSettingsDTO.CacheTTL == "" { - zabbixSettingsDTO.CacheTTL = "1h" - } - - if zabbixSettingsDTO.Timeout == "" { - zabbixSettingsDTO.Timeout = "30" - } - - trendsFrom, err := gtime.ParseInterval(zabbixSettingsDTO.TrendsFrom) - if err != nil { - return nil, err - } - - trendsRange, err := gtime.ParseInterval(zabbixSettingsDTO.TrendsRange) - if err != nil { - return nil, err - } - - cacheTTL, err := gtime.ParseInterval(zabbixSettingsDTO.CacheTTL) - if err != nil { - return nil, err - } - - timeout, err := strconv.Atoi(zabbixSettingsDTO.Timeout) - if err != nil { - return nil, errors.New("failed to parse timeout: " + err.Error()) - } - - zabbixSettings := &ZabbixDatasourceSettings{ - Trends: zabbixSettingsDTO.Trends, - TrendsFrom: trendsFrom, - TrendsRange: trendsRange, - CacheTTL: cacheTTL, - Timeout: time.Duration(timeout) * time.Second, - DisableDataAlignment: zabbixSettingsDTO.DisableDataAlignment, - DisableReadOnlyUsersAck: zabbixSettingsDTO.DisableReadOnlyUsersAck, - } - - return zabbixSettings, nil -} diff --git a/pkg/datasource/models.go b/pkg/datasource/models.go index 8edeb30..b293102 100644 --- a/pkg/datasource/models.go +++ b/pkg/datasource/models.go @@ -21,30 +21,6 @@ const ( MODE_PROBLEMS = "5" ) -// ZabbixDatasourceSettingsDTO model -type ZabbixDatasourceSettingsDTO struct { - Trends bool `json:"trends"` - TrendsFrom string `json:"trendsFrom"` - TrendsRange string `json:"trendsRange"` - CacheTTL string `json:"cacheTTL"` - Timeout string `json:"timeout"` - - DisableDataAlignment bool `json:"disableDataAlignment"` - DisableReadOnlyUsersAck bool `json:"disableReadOnlyUsersAck"` -} - -// ZabbixDatasourceSettings model -type ZabbixDatasourceSettings struct { - Trends bool - TrendsFrom time.Duration - TrendsRange time.Duration - CacheTTL time.Duration - Timeout time.Duration - - DisableDataAlignment bool `json:"disableDataAlignment"` - DisableReadOnlyUsersAck bool `json:"disableReadOnlyUsersAck"` -} - type DBConnectionPostProcessingRequest struct { Query QueryModel `json:"query"` TimeRange TimeRangePostProcessingRequest `json:"timeRange"` diff --git a/pkg/datasource/zabbix_test.go b/pkg/datasource/zabbix_test.go index b06c17f..bffa375 100644 --- a/pkg/datasource/zabbix_test.go +++ b/pkg/datasource/zabbix_test.go @@ -1,6 +1,7 @@ package datasource import ( + "github.com/alexanderzobnin/grafana-zabbix/pkg/settings" "github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/log" @@ -23,7 +24,7 @@ func mockZabbixQuery(method string, params zabbix.ZabbixAPIParams) *zabbix.Zabbi } func MockZabbixDataSource(body string, statusCode int) *ZabbixDatasourceInstance { - zabbixSettings, _ := readZabbixSettings(basicDatasourceInfo) + zabbixSettings, _ := settings.ReadZabbixSettings(basicDatasourceInfo) zabbixClient, _ := zabbix.MockZabbixClient(basicDatasourceInfo, body, statusCode) return &ZabbixDatasourceInstance{ diff --git a/pkg/settings/models.go b/pkg/settings/models.go new file mode 100644 index 0000000..2566bae --- /dev/null +++ b/pkg/settings/models.go @@ -0,0 +1,27 @@ +package settings + +import "time" + +// ZabbixDatasourceSettingsDTO model +type ZabbixDatasourceSettingsDTO struct { + Trends bool `json:"trends"` + TrendsFrom string `json:"trendsFrom"` + TrendsRange string `json:"trendsRange"` + CacheTTL string `json:"cacheTTL"` + Timeout interface{} `json:"timeout"` + + DisableDataAlignment bool `json:"disableDataAlignment"` + DisableReadOnlyUsersAck bool `json:"disableReadOnlyUsersAck"` +} + +// ZabbixDatasourceSettings model +type ZabbixDatasourceSettings struct { + Trends bool + TrendsFrom time.Duration + TrendsRange time.Duration + CacheTTL time.Duration + Timeout time.Duration + + DisableDataAlignment bool `json:"disableDataAlignment"` + DisableReadOnlyUsersAck bool `json:"disableReadOnlyUsersAck"` +} diff --git a/pkg/zabbix/settings.go b/pkg/settings/settings.go similarity index 54% rename from pkg/zabbix/settings.go rename to pkg/settings/settings.go index 0b6d421..5d18efa 100644 --- a/pkg/zabbix/settings.go +++ b/pkg/settings/settings.go @@ -1,16 +1,15 @@ -package zabbix +package settings import ( "encoding/json" "errors" - "strconv" - "time" - "github.com/alexanderzobnin/grafana-zabbix/pkg/gtime" "github.com/grafana/grafana-plugin-sdk-go/backend" + "strconv" + "time" ) -func readZabbixSettings(dsInstanceSettings *backend.DataSourceInstanceSettings) (*ZabbixDatasourceSettings, error) { +func ReadZabbixSettings(dsInstanceSettings *backend.DataSourceInstanceSettings) (*ZabbixDatasourceSettings, error) { zabbixSettingsDTO := &ZabbixDatasourceSettingsDTO{} err := json.Unmarshal(dsInstanceSettings.JSONData, &zabbixSettingsDTO) @@ -28,9 +27,9 @@ func readZabbixSettings(dsInstanceSettings *backend.DataSourceInstanceSettings) zabbixSettingsDTO.CacheTTL = "1h" } - if zabbixSettingsDTO.Timeout == "" { - zabbixSettingsDTO.Timeout = "30" - } + //if zabbixSettingsDTO.Timeout == 0 { + // zabbixSettingsDTO.Timeout = 30 + //} trendsFrom, err := gtime.ParseInterval(zabbixSettingsDTO.TrendsFrom) if err != nil { @@ -47,17 +46,32 @@ func readZabbixSettings(dsInstanceSettings *backend.DataSourceInstanceSettings) return nil, err } - timeout, err := strconv.Atoi(zabbixSettingsDTO.Timeout) - if err != nil { - return nil, errors.New("failed to parse timeout: " + err.Error()) + var timeout int64 + switch t := zabbixSettingsDTO.Timeout.(type) { + case string: + if t == "" { + timeout = 30 + break + } + timeoutInt, err := strconv.Atoi(t) + if err != nil { + return nil, errors.New("failed to parse timeout: " + err.Error()) + } + timeout = int64(timeoutInt) + case float64: + timeout = int64(t) + default: + timeout = 30 } zabbixSettings := &ZabbixDatasourceSettings{ - Trends: zabbixSettingsDTO.Trends, - TrendsFrom: trendsFrom, - TrendsRange: trendsRange, - CacheTTL: cacheTTL, - Timeout: time.Duration(timeout) * time.Second, + Trends: zabbixSettingsDTO.Trends, + TrendsFrom: trendsFrom, + TrendsRange: trendsRange, + CacheTTL: cacheTTL, + Timeout: time.Duration(timeout) * time.Second, + DisableDataAlignment: zabbixSettingsDTO.DisableDataAlignment, + DisableReadOnlyUsersAck: zabbixSettingsDTO.DisableReadOnlyUsersAck, } return zabbixSettings, nil diff --git a/pkg/zabbix/testing.go b/pkg/zabbix/testing.go index bbb6dc5..f5e0d83 100644 --- a/pkg/zabbix/testing.go +++ b/pkg/zabbix/testing.go @@ -1,8 +1,10 @@ package zabbix import ( + "github.com/alexanderzobnin/grafana-zabbix/pkg/settings" "github.com/alexanderzobnin/grafana-zabbix/pkg/zabbixapi" "github.com/grafana/grafana-plugin-sdk-go/backend" + "time" ) func MockZabbixClient(dsInfo *backend.DataSourceInstanceSettings, body string, statusCode int) (*Zabbix, error) { @@ -10,8 +12,11 @@ func MockZabbixClient(dsInfo *backend.DataSourceInstanceSettings, body string, s if err != nil { return nil, err } + zabbixSettings := &settings.ZabbixDatasourceSettings{ + Timeout: 10 * time.Second, + } - client, err := New(dsInfo, zabbixAPI) + client, err := New(dsInfo, zabbixSettings, zabbixAPI) if err != nil { return nil, err } diff --git a/pkg/zabbix/zabbix.go b/pkg/zabbix/zabbix.go index 8543287..9684401 100644 --- a/pkg/zabbix/zabbix.go +++ b/pkg/zabbix/zabbix.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "github.com/alexanderzobnin/grafana-zabbix/pkg/settings" "github.com/alexanderzobnin/grafana-zabbix/pkg/zabbixapi" "github.com/bitly/go-simplejson" "github.com/grafana/grafana-plugin-sdk-go/backend" @@ -22,15 +23,8 @@ type Zabbix struct { } // New returns new instance of Zabbix client. -func New(dsInfo *backend.DataSourceInstanceSettings, zabbixAPI *zabbixapi.ZabbixAPI) (*Zabbix, error) { +func New(dsInfo *backend.DataSourceInstanceSettings, zabbixSettings *settings.ZabbixDatasourceSettings, zabbixAPI *zabbixapi.ZabbixAPI) (*Zabbix, error) { logger := log.New() - - zabbixSettings, err := readZabbixSettings(dsInfo) - if err != nil { - logger.Error("Error parsing Zabbix settings", "error", err) - return nil, err - } - zabbixCache := NewZabbixCache(zabbixSettings.CacheTTL, 10*time.Minute) return &Zabbix{ diff --git a/src/datasource-zabbix/components/ConfigEditor.tsx b/src/datasource-zabbix/components/ConfigEditor.tsx index 76fa69e..85dac17 100644 --- a/src/datasource-zabbix/components/ConfigEditor.tsx +++ b/src/datasource-zabbix/components/ConfigEditor.tsx @@ -1,10 +1,11 @@ import React, { useEffect, useState } from 'react'; import { getDataSourceSrv } from '@grafana/runtime'; import { DataSourcePluginOptionsEditorProps, DataSourceSettings, SelectableValue } from '@grafana/data'; -import { DataSourceHttpSettings, LegacyForms, Field, Input, Button, InlineFormLabel, Select } from '@grafana/ui'; -const { FormField, Switch } = LegacyForms; +import { Button, DataSourceHttpSettings, InlineFormLabel, LegacyForms, Select } from '@grafana/ui'; import { ZabbixDSOptions, ZabbixSecureJSONData } from '../types'; +const { FormField, Switch } = LegacyForms; + const SUPPORTED_SQL_DS = ['mysql', 'postgres', 'influxdb']; export type Props = DataSourcePluginOptionsEditorProps; @@ -34,7 +35,7 @@ export const ConfigEditor = (props: Props) => { trendsFrom: '', trendsRange: '', cacheTTL: '', - timeout: '', + timeout: undefined, disableDataAlignment: false, ...restJsonData, }, @@ -99,7 +100,7 @@ export const ConfigEditor = (props: Props) => { placeholder="Configured" /> - : + : { onChange={jsonDataSwitchHandler('trends', options, onOptionsChange)} /> {options.jsonData.trends && - <> -
- + -
-
- + -
- + /> + + }
{ { + onOptionsChange({ + ...options, + jsonData: { ...options.jsonData, timeout: parseInt(event.currentTarget.value, 10) }, + }); + }} tooltip="Zabbix API connection timeout in seconds. Default is 30." />
@@ -178,31 +184,31 @@ export const ConfigEditor = (props: Props) => { onChange={jsonDataSwitchHandler('dbConnectionEnable', options, onOptionsChange)} /> {options.jsonData.dbConnectionEnable && - <> -
- Data Source - +
+ {currentDSType === 'influxdb' && +
+ -
- } - + /> + + } + } diff --git a/src/datasource-zabbix/migrations.ts b/src/datasource-zabbix/migrations.ts index 3b1c58a..544841c 100644 --- a/src/datasource-zabbix/migrations.ts +++ b/src/datasource-zabbix/migrations.ts @@ -106,7 +106,7 @@ function convertToRegex(str) { } } -export const DS_CONFIG_SCHEMA = 2; +export const DS_CONFIG_SCHEMA = 3; export function migrateDSConfig(jsonData) { if (!jsonData) { @@ -127,6 +127,10 @@ export function migrateDSConfig(jsonData) { delete jsonData.dbConnection; } + if (oldVersion < 3) { + jsonData.timeout = (jsonData.timeout as string) === "" ? null : Number(jsonData.timeout as string); + } + return jsonData; } @@ -134,7 +138,7 @@ function shouldMigrateDSConfig(jsonData): boolean { if (jsonData.dbConnection && !_.isEmpty(jsonData.dbConnection)) { return true; } - if (jsonData.schema && jsonData.schema !== DS_CONFIG_SCHEMA) { + if (jsonData.schema && jsonData.schema < DS_CONFIG_SCHEMA) { return true; } return false; diff --git a/src/datasource-zabbix/types.ts b/src/datasource-zabbix/types.ts index 41284a8..8dc62e7 100644 --- a/src/datasource-zabbix/types.ts +++ b/src/datasource-zabbix/types.ts @@ -7,7 +7,7 @@ export interface ZabbixDSOptions extends DataSourceJsonData { trendsFrom: string; trendsRange: string; cacheTTL: string; - timeout?: string; + timeout?: number; dbConnectionEnable: boolean; dbConnectionDatasourceId?: number; dbConnectionDatasourceName?: string;