Auth: Able to use API tokens for authentication (#1662)
* Auth: Able to use API tokens for authentication * Update change log
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
## [4.4.0] - 2023-06-06
|
## [4.4.0] - Unreleased
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Enables PDC for zabbix datasource, [#1653](https://github.com/alexanderzobnin/grafana-zabbix/issues/1653)
|
- Support for secure socks proxy, [#1653](https://github.com/alexanderzobnin/grafana-zabbix/issues/1653)
|
||||||
|
- Able to use API tokens for authentication, [#1513](https://github.com/alexanderzobnin/grafana-zabbix/issues/1513)
|
||||||
|
|
||||||
## [4.3.1] - 2023-03-23
|
## [4.3.1] - 2023-03-23
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package datasource
|
|||||||
import (
|
import (
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/settings"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/settings"
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||||
)
|
)
|
||||||
@@ -13,7 +14,7 @@ var basicDatasourceInfo = &backend.DataSourceInstanceSettings{
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
Name: "TestDatasource",
|
Name: "TestDatasource",
|
||||||
URL: "http://zabbix.org/zabbix",
|
URL: "http://zabbix.org/zabbix",
|
||||||
JSONData: []byte(`{"username":"username", "password":"password", "cacheTTL":"10m"}`),
|
JSONData: []byte(`{"username":"username", "password":"password", "cacheTTL":"10m", "authType":"token"}`),
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockZabbixQuery(method string, params zabbix.ZabbixAPIParams) *zabbix.ZabbixAPIRequest {
|
func mockZabbixQuery(method string, params zabbix.ZabbixAPIParams) *zabbix.ZabbixAPIRequest {
|
||||||
|
|||||||
@@ -2,8 +2,14 @@ package settings
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
const (
|
||||||
|
AuthTypeUserLogin = "userLogin"
|
||||||
|
AuthTypeToken = "token"
|
||||||
|
)
|
||||||
|
|
||||||
// ZabbixDatasourceSettingsDTO model
|
// ZabbixDatasourceSettingsDTO model
|
||||||
type ZabbixDatasourceSettingsDTO struct {
|
type ZabbixDatasourceSettingsDTO struct {
|
||||||
|
AuthType string `json:"authType"`
|
||||||
Trends bool `json:"trends"`
|
Trends bool `json:"trends"`
|
||||||
TrendsFrom string `json:"trendsFrom"`
|
TrendsFrom string `json:"trendsFrom"`
|
||||||
TrendsRange string `json:"trendsRange"`
|
TrendsRange string `json:"trendsRange"`
|
||||||
@@ -16,6 +22,7 @@ type ZabbixDatasourceSettingsDTO struct {
|
|||||||
|
|
||||||
// ZabbixDatasourceSettings model
|
// ZabbixDatasourceSettings model
|
||||||
type ZabbixDatasourceSettings struct {
|
type ZabbixDatasourceSettings struct {
|
||||||
|
AuthType string
|
||||||
Trends bool
|
Trends bool
|
||||||
TrendsFrom time.Duration
|
TrendsFrom time.Duration
|
||||||
TrendsRange time.Duration
|
TrendsRange time.Duration
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ package settings
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/gtime"
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/gtime"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ReadZabbixSettings(dsInstanceSettings *backend.DataSourceInstanceSettings) (*ZabbixDatasourceSettings, error) {
|
func ReadZabbixSettings(dsInstanceSettings *backend.DataSourceInstanceSettings) (*ZabbixDatasourceSettings, error) {
|
||||||
@@ -17,6 +19,10 @@ func ReadZabbixSettings(dsInstanceSettings *backend.DataSourceInstanceSettings)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if zabbixSettingsDTO.AuthType == "" {
|
||||||
|
zabbixSettingsDTO.AuthType = AuthTypeUserLogin
|
||||||
|
}
|
||||||
|
|
||||||
if zabbixSettingsDTO.TrendsFrom == "" {
|
if zabbixSettingsDTO.TrendsFrom == "" {
|
||||||
zabbixSettingsDTO.TrendsFrom = "7d"
|
zabbixSettingsDTO.TrendsFrom = "7d"
|
||||||
}
|
}
|
||||||
@@ -65,6 +71,7 @@ func ReadZabbixSettings(dsInstanceSettings *backend.DataSourceInstanceSettings)
|
|||||||
}
|
}
|
||||||
|
|
||||||
zabbixSettings := &ZabbixDatasourceSettings{
|
zabbixSettings := &ZabbixDatasourceSettings{
|
||||||
|
AuthType: zabbixSettingsDTO.AuthType,
|
||||||
Trends: zabbixSettingsDTO.Trends,
|
Trends: zabbixSettingsDTO.Trends,
|
||||||
TrendsFrom: trendsFrom,
|
TrendsFrom: trendsFrom,
|
||||||
TrendsRange: trendsRange,
|
TrendsRange: trendsRange,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package zabbix
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ import (
|
|||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/settings"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/settings"
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbixapi"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbixapi"
|
||||||
"github.com/bitly/go-simplejson"
|
"github.com/bitly/go-simplejson"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||||
)
|
)
|
||||||
@@ -16,11 +18,12 @@ import (
|
|||||||
// Zabbix is a wrapper for Zabbix API. It wraps Zabbix API queries and performs authentication, adds caching,
|
// Zabbix is a wrapper for Zabbix API. It wraps Zabbix API queries and performs authentication, adds caching,
|
||||||
// deduplication and other performance optimizations.
|
// deduplication and other performance optimizations.
|
||||||
type Zabbix struct {
|
type Zabbix struct {
|
||||||
api *zabbixapi.ZabbixAPI
|
api *zabbixapi.ZabbixAPI
|
||||||
dsInfo *backend.DataSourceInstanceSettings
|
dsInfo *backend.DataSourceInstanceSettings
|
||||||
cache *ZabbixCache
|
settings *settings.ZabbixDatasourceSettings
|
||||||
version int
|
cache *ZabbixCache
|
||||||
logger log.Logger
|
version int
|
||||||
|
logger log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns new instance of Zabbix client.
|
// New returns new instance of Zabbix client.
|
||||||
@@ -29,10 +32,11 @@ func New(dsInfo *backend.DataSourceInstanceSettings, zabbixSettings *settings.Za
|
|||||||
zabbixCache := NewZabbixCache(zabbixSettings.CacheTTL, 10*time.Minute)
|
zabbixCache := NewZabbixCache(zabbixSettings.CacheTTL, 10*time.Minute)
|
||||||
|
|
||||||
return &Zabbix{
|
return &Zabbix{
|
||||||
api: zabbixAPI,
|
api: zabbixAPI,
|
||||||
dsInfo: dsInfo,
|
dsInfo: dsInfo,
|
||||||
cache: zabbixCache,
|
settings: zabbixSettings,
|
||||||
logger: logger,
|
cache: zabbixCache,
|
||||||
|
logger: logger,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,11 +94,12 @@ func (zabbix *Zabbix) request(ctx context.Context, method string, params ZabbixA
|
|||||||
|
|
||||||
result, err := zabbix.api.Request(ctx, method, params)
|
result, err := zabbix.api.Request(ctx, method, params)
|
||||||
notAuthorized := isNotAuthorized(err)
|
notAuthorized := isNotAuthorized(err)
|
||||||
if err == zabbixapi.ErrNotAuthenticated || notAuthorized {
|
isTokenAuth := zabbix.settings.AuthType == settings.AuthTypeToken
|
||||||
|
if err == zabbixapi.ErrNotAuthenticated || (notAuthorized && !isTokenAuth) {
|
||||||
if notAuthorized {
|
if notAuthorized {
|
||||||
zabbix.logger.Debug("Authentication token expired, performing re-login")
|
zabbix.logger.Debug("Authentication token expired, performing re-login")
|
||||||
}
|
}
|
||||||
err = zabbix.Login(ctx)
|
err = zabbix.Authenticate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -106,12 +111,27 @@ func (zabbix *Zabbix) request(ctx context.Context, method string, params ZabbixA
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zabbix *Zabbix) Login(ctx context.Context) error {
|
func (zabbix *Zabbix) Authenticate(ctx context.Context) error {
|
||||||
jsonData, err := simplejson.NewJson(zabbix.dsInfo.JSONData)
|
jsonData, err := simplejson.NewJson(zabbix.dsInfo.JSONData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
authType := zabbix.settings.AuthType
|
||||||
|
if authType == settings.AuthTypeToken {
|
||||||
|
token, exists := zabbix.dsInfo.DecryptedSecureJSONData["apiToken"]
|
||||||
|
if !exists {
|
||||||
|
return errors.New("cannot find Zabbix API token")
|
||||||
|
}
|
||||||
|
err = zabbix.api.AuthenticateWithToken(ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
zabbix.logger.Error("Zabbix authentication error", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
zabbix.logger.Debug("Using API token for authentication")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
zabbixLogin := jsonData.Get("username").MustString()
|
zabbixLogin := jsonData.Get("username").MustString()
|
||||||
var zabbixPassword string
|
var zabbixPassword string
|
||||||
if securePassword, exists := zabbix.dsInfo.DecryptedSecureJSONData["password"]; exists {
|
if securePassword, exists := zabbix.dsInfo.DecryptedSecureJSONData["password"]; exists {
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
)
|
)
|
||||||
|
|
||||||
var basicDatasourceInfo = &backend.DataSourceInstanceSettings{
|
var basicDatasourceInfo = &backend.DataSourceInstanceSettings{
|
||||||
@@ -19,7 +20,7 @@ var emptyParams = map[string]interface{}{}
|
|||||||
|
|
||||||
func TestLogin(t *testing.T) {
|
func TestLogin(t *testing.T) {
|
||||||
zabbixClient, _ := MockZabbixClient(basicDatasourceInfo, `{"result":"secretauth"}`, 200)
|
zabbixClient, _ := MockZabbixClient(basicDatasourceInfo, `{"result":"secretauth"}`, 200)
|
||||||
err := zabbixClient.Login(context.Background())
|
err := zabbixClient.Authenticate(context.Background())
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "secretauth", zabbixClient.api.GetAuth())
|
assert.Equal(t, "secretauth", zabbixClient.api.GetAuth())
|
||||||
@@ -27,7 +28,7 @@ func TestLogin(t *testing.T) {
|
|||||||
|
|
||||||
func TestLoginError(t *testing.T) {
|
func TestLoginError(t *testing.T) {
|
||||||
zabbixClient, _ := MockZabbixClient(basicDatasourceInfo, `{"result":""}`, 500)
|
zabbixClient, _ := MockZabbixClient(basicDatasourceInfo, `{"result":""}`, 500)
|
||||||
err := zabbixClient.Login(context.Background())
|
err := zabbixClient.Authenticate(context.Background())
|
||||||
|
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, "", zabbixClient.api.GetAuth())
|
assert.Equal(t, "", zabbixClient.api.GetAuth())
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ import (
|
|||||||
|
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/metrics"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/metrics"
|
||||||
"github.com/bitly/go-simplejson"
|
"github.com/bitly/go-simplejson"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
|
||||||
"golang.org/x/net/context/ctxhttp"
|
"golang.org/x/net/context/ctxhttp"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -168,6 +169,15 @@ func (api *ZabbixAPI) Authenticate(ctx context.Context, username string, passwor
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthenticateWithToken performs authentication with API token.
|
||||||
|
func (api *ZabbixAPI) AuthenticateWithToken(ctx context.Context, token string) error {
|
||||||
|
if token == "" {
|
||||||
|
return errors.New("API token is empty")
|
||||||
|
}
|
||||||
|
api.SetAuth(token)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func isDeprecatedUserParamError(err error) bool {
|
func isDeprecatedUserParamError(err error) bool {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -2,13 +2,18 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import { getDataSourceSrv, config } from '@grafana/runtime';
|
import { getDataSourceSrv, config } from '@grafana/runtime';
|
||||||
import { DataSourcePluginOptionsEditorProps, DataSourceSettings, SelectableValue } from '@grafana/data';
|
import { DataSourcePluginOptionsEditorProps, DataSourceSettings, SelectableValue } from '@grafana/data';
|
||||||
import { Button, DataSourceHttpSettings, InlineFormLabel, LegacyForms, Select } from '@grafana/ui';
|
import { Button, DataSourceHttpSettings, InlineFormLabel, LegacyForms, Select } from '@grafana/ui';
|
||||||
import { ZabbixDSOptions, ZabbixSecureJSONData } from '../types';
|
import { ZabbixAuthType, ZabbixDSOptions, ZabbixSecureJSONData } from '../types';
|
||||||
import { gte } from 'semver';
|
import { gte } from 'semver';
|
||||||
|
|
||||||
const { FormField, Switch } = LegacyForms;
|
const { FormField, Switch } = LegacyForms;
|
||||||
|
|
||||||
const SUPPORTED_SQL_DS = ['mysql', 'postgres', 'influxdb'];
|
const SUPPORTED_SQL_DS = ['mysql', 'postgres', 'influxdb'];
|
||||||
|
|
||||||
|
const authOptions: Array<SelectableValue<ZabbixAuthType>> = [
|
||||||
|
{ label: 'User and password', value: ZabbixAuthType.UserLogin },
|
||||||
|
{ label: 'API token', value: ZabbixAuthType.Token },
|
||||||
|
];
|
||||||
|
|
||||||
export type Props = DataSourcePluginOptionsEditorProps<ZabbixDSOptions, ZabbixSecureJSONData>;
|
export type Props = DataSourcePluginOptionsEditorProps<ZabbixDSOptions, ZabbixSecureJSONData>;
|
||||||
export const ConfigEditor = (props: Props) => {
|
export const ConfigEditor = (props: Props) => {
|
||||||
const { options, onOptionsChange } = props;
|
const { options, onOptionsChange } = props;
|
||||||
@@ -32,6 +37,7 @@ export const ConfigEditor = (props: Props) => {
|
|||||||
onOptionsChange({
|
onOptionsChange({
|
||||||
...options,
|
...options,
|
||||||
jsonData: {
|
jsonData: {
|
||||||
|
authType: ZabbixAuthType.UserLogin,
|
||||||
trends: true,
|
trends: true,
|
||||||
trendsFrom: '',
|
trendsFrom: '',
|
||||||
trendsRange: '',
|
trendsRange: '',
|
||||||
@@ -82,41 +88,84 @@ export const ConfigEditor = (props: Props) => {
|
|||||||
|
|
||||||
<div className="gf-form-group">
|
<div className="gf-form-group">
|
||||||
<h3 className="page-heading">Zabbix API details</h3>
|
<h3 className="page-heading">Zabbix API details</h3>
|
||||||
<div className="gf-form max-width-25">
|
<div className="gf-form">
|
||||||
<FormField
|
<InlineFormLabel width={7} tooltip="Token authentication available in Zabbix version 5.4 and higher.">
|
||||||
labelWidth={7}
|
Auth type
|
||||||
inputWidth={15}
|
</InlineFormLabel>
|
||||||
label="Username"
|
<Select
|
||||||
value={options.jsonData.username || ''}
|
width={30}
|
||||||
onChange={jsonDataChangeHandler('username', options, onOptionsChange)}
|
options={authOptions}
|
||||||
required
|
value={options.jsonData.authType}
|
||||||
|
onChange={jsonDataSelectHandler('authType', options, onOptionsChange)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="gf-form max-width-25">
|
{options.jsonData?.authType === ZabbixAuthType.Token ? (
|
||||||
{options.secureJsonFields?.password ? (
|
<>
|
||||||
<>
|
<div className="gf-form max-width-25">
|
||||||
|
{options.secureJsonFields?.apiToken ? (
|
||||||
|
<>
|
||||||
|
<FormField
|
||||||
|
labelWidth={7}
|
||||||
|
inputWidth={15}
|
||||||
|
label="API token"
|
||||||
|
disabled={true}
|
||||||
|
value=""
|
||||||
|
placeholder="Configured"
|
||||||
|
/>
|
||||||
|
<Button onClick={resetSecureJsonField('apiToken', options, onOptionsChange)}>Reset</Button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<FormField
|
||||||
|
labelWidth={7}
|
||||||
|
inputWidth={15}
|
||||||
|
label="API token"
|
||||||
|
type="password"
|
||||||
|
value={options.secureJsonData?.apiToken || ''}
|
||||||
|
onChange={secureJsonDataChangeHandler('apiToken', options, onOptionsChange)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className="gf-form max-width-25">
|
||||||
<FormField
|
<FormField
|
||||||
labelWidth={7}
|
labelWidth={7}
|
||||||
inputWidth={15}
|
inputWidth={15}
|
||||||
label="Password"
|
label="Username"
|
||||||
disabled={true}
|
value={options.jsonData.username || ''}
|
||||||
value=""
|
onChange={jsonDataChangeHandler('username', options, onOptionsChange)}
|
||||||
placeholder="Configured"
|
required
|
||||||
/>
|
/>
|
||||||
<Button onClick={resetSecureJsonField('password', options, onOptionsChange)}>Reset</Button>
|
</div>
|
||||||
</>
|
<div className="gf-form max-width-25">
|
||||||
) : (
|
{options.secureJsonFields?.password ? (
|
||||||
<FormField
|
<>
|
||||||
labelWidth={7}
|
<FormField
|
||||||
inputWidth={15}
|
labelWidth={7}
|
||||||
label="Password"
|
inputWidth={15}
|
||||||
type="password"
|
label="Password"
|
||||||
value={options.secureJsonData?.password || options.jsonData.password || ''}
|
disabled={true}
|
||||||
onChange={secureJsonDataChangeHandler('password', options, onOptionsChange)}
|
value=""
|
||||||
required
|
placeholder="Configured"
|
||||||
/>
|
/>
|
||||||
)}
|
<Button onClick={resetSecureJsonField('password', options, onOptionsChange)}>Reset</Button>
|
||||||
</div>
|
</>
|
||||||
|
) : (
|
||||||
|
<FormField
|
||||||
|
labelWidth={7}
|
||||||
|
inputWidth={15}
|
||||||
|
label="Password"
|
||||||
|
type="password"
|
||||||
|
value={options.secureJsonData?.password || options.jsonData.password || ''}
|
||||||
|
onChange={secureJsonDataChangeHandler('password', options, onOptionsChange)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Switch
|
<Switch
|
||||||
label="Trends"
|
label="Trends"
|
||||||
labelClass="width-7"
|
labelClass="width-7"
|
||||||
@@ -222,7 +271,7 @@ export const ConfigEditor = (props: Props) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="gf-form-group">
|
<div className="gf-form-group">
|
||||||
<h3 className="page-heading">Other</h3>
|
<h3 className="page-heading">Other</h3>
|
||||||
<Switch
|
<Switch
|
||||||
label="Disable acknowledges for read-only users"
|
label="Disable acknowledges for read-only users"
|
||||||
@@ -273,6 +322,22 @@ const jsonDataChangeHandler =
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const jsonDataSelectHandler =
|
||||||
|
(
|
||||||
|
key: keyof ZabbixDSOptions,
|
||||||
|
value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
|
||||||
|
onChange: Props['onOptionsChange']
|
||||||
|
) =>
|
||||||
|
(option: SelectableValue) => {
|
||||||
|
onChange({
|
||||||
|
...value,
|
||||||
|
jsonData: {
|
||||||
|
...value.jsonData,
|
||||||
|
[key]: option.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const jsonDataSwitchHandler =
|
const jsonDataSwitchHandler =
|
||||||
(
|
(
|
||||||
key: keyof ZabbixDSOptions,
|
key: keyof ZabbixDSOptions,
|
||||||
@@ -291,7 +356,7 @@ const jsonDataSwitchHandler =
|
|||||||
|
|
||||||
const secureJsonDataChangeHandler =
|
const secureJsonDataChangeHandler =
|
||||||
(
|
(
|
||||||
key: keyof ZabbixDSOptions,
|
key: keyof ZabbixSecureJSONData,
|
||||||
value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
|
value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
|
||||||
onChange: Props['onOptionsChange']
|
onChange: Props['onOptionsChange']
|
||||||
) =>
|
) =>
|
||||||
@@ -307,7 +372,7 @@ const secureJsonDataChangeHandler =
|
|||||||
|
|
||||||
const resetSecureJsonField =
|
const resetSecureJsonField =
|
||||||
(
|
(
|
||||||
key: keyof ZabbixDSOptions,
|
key: keyof ZabbixSecureJSONData,
|
||||||
value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
|
value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
|
||||||
onChange: Props['onOptionsChange']
|
onChange: Props['onOptionsChange']
|
||||||
) =>
|
) =>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { BusEventWithPayload, DataQuery, DataSourceJsonData, DataSourceRef, SelectableValue } from '@grafana/data';
|
import { BusEventWithPayload, DataQuery, DataSourceJsonData, DataSourceRef, SelectableValue } from '@grafana/data';
|
||||||
|
|
||||||
export interface ZabbixDSOptions extends DataSourceJsonData {
|
export interface ZabbixDSOptions extends DataSourceJsonData {
|
||||||
|
authType?: ZabbixAuthType;
|
||||||
username: string;
|
username: string;
|
||||||
password?: string;
|
password?: string;
|
||||||
trends: boolean;
|
trends: boolean;
|
||||||
@@ -19,6 +20,7 @@ export interface ZabbixDSOptions extends DataSourceJsonData {
|
|||||||
|
|
||||||
export interface ZabbixSecureJSONData {
|
export interface ZabbixSecureJSONData {
|
||||||
password?: string;
|
password?: string;
|
||||||
|
apiToken?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ZabbixConnectionInfo {
|
export interface ZabbixConnectionInfo {
|
||||||
@@ -408,3 +410,8 @@ export interface ZBXAlert {
|
|||||||
export class ZBXQueryUpdatedEvent extends BusEventWithPayload<any> {
|
export class ZBXQueryUpdatedEvent extends BusEventWithPayload<any> {
|
||||||
static type = 'zbx-query-updated';
|
static type = 'zbx-query-updated';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ZabbixAuthType {
|
||||||
|
UserLogin = 'userLogin',
|
||||||
|
Token = 'token',
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user