Move health check to the backend (#2120)
This PR moves the health check to backend only leaving in the frontend the functionality to test the dbconnector datasource. Leaving the `dbconnector.testDataSource` should be fine since the datasource types we allow for db connection with Zabbix already are backend datasources, and so their health requests would go through the backend. Verified: Clicking test and seeing a `health` request go out. IMPORTANT: While testing this in the UI, I found a bug with the config editor - whenever a change is made in the UI and tested, the changes don't take effect (i.e. disabling trends, keeps `trends` set to `true`, enabling db connection keep `dbConnectionEnabled` set to `false` and so on.). Created a separate [issue](https://github.com/orgs/grafana/projects/457/views/40?pane=issue&itemId=3627315751&issue=grafana%7Coss-big-tent-squad%7C132) to fix this Fixes https://github.com/grafana/oss-big-tent-squad/issues/124 Fixes https://github.com/grafana/grafana-zabbix/issues/2004
This commit is contained in:
committed by
GitHub
parent
631d3bdc4f
commit
89ae290942
5
.changeset/orange-owls-tie.md
Normal file
5
.changeset/orange-owls-tie.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'grafana-zabbix': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Moves health check to the backend
|
||||||
@@ -3,6 +3,7 @@ package datasource
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/httpclient"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/httpclient"
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/metrics"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/metrics"
|
||||||
@@ -99,7 +100,7 @@ func (ds *ZabbixDatasource) CheckHealth(ctx context.Context, req *backend.CheckH
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.Status = backend.HealthStatusOk
|
res.Status = backend.HealthStatusOk
|
||||||
res.Message = message
|
res.Message = fmt.Sprintf("Zabbix API version %s", message)
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,13 +36,12 @@ func (ds *ZabbixDatasourceInstance) TestConnection(ctx context.Context) (string,
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := ds.zabbix.Request(ctx, &zabbix.ZabbixAPIRequest{Method: "apiinfo.version"})
|
zabbixVersion, err := ds.zabbix.GetFullVersion(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
resultByte, _ := response.MarshalJSON()
|
return zabbixVersion, nil
|
||||||
return string(resultByte), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *ZabbixDatasourceInstance) queryNumericItems(ctx context.Context, query *QueryModel) ([]*data.Frame, error) {
|
func (ds *ZabbixDatasourceInstance) queryNumericItems(ctx context.Context, query *QueryModel) ([]*data.Frame, error) {
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ type ZabbixDatasourceSettingsDTO struct {
|
|||||||
CacheTTL string `json:"cacheTTL"`
|
CacheTTL string `json:"cacheTTL"`
|
||||||
Timeout interface{} `json:"timeout"`
|
Timeout interface{} `json:"timeout"`
|
||||||
|
|
||||||
DisableDataAlignment bool `json:"disableDataAlignment"`
|
DisableDataAlignment bool `json:"disableDataAlignment"`
|
||||||
DisableReadOnlyUsersAck bool `json:"disableReadOnlyUsersAck"`
|
DisableReadOnlyUsersAck bool `json:"disableReadOnlyUsersAck"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZabbixDatasourceSettings model
|
// ZabbixDatasourceSettings model
|
||||||
@@ -29,6 +29,6 @@ type ZabbixDatasourceSettings struct {
|
|||||||
CacheTTL time.Duration
|
CacheTTL time.Duration
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
|
|
||||||
DisableDataAlignment bool `json:"disableDataAlignment"`
|
DisableDataAlignment bool `json:"disableDataAlignment"`
|
||||||
DisableReadOnlyUsersAck bool `json:"disableReadOnlyUsersAck"`
|
DisableReadOnlyUsersAck bool `json:"disableReadOnlyUsersAck"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -524,19 +524,28 @@ func (ds *Zabbix) GetValueMappings(ctx context.Context) ([]ValueMap, error) {
|
|||||||
return valuemaps, err
|
return valuemaps, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *Zabbix) GetVersion(ctx context.Context) (int, error) {
|
func (ds *Zabbix) GetFullVersion(ctx context.Context) (string, error) {
|
||||||
result, err := ds.request(ctx, "apiinfo.version", ZabbixAPIParams{})
|
result, err := ds.request(ctx, "apiinfo.version", ZabbixAPIParams{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var version string
|
var version string
|
||||||
err = convertTo(result, &version)
|
err = convertTo(result, &version)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ds *Zabbix) GetVersion(ctx context.Context) (int, error) {
|
||||||
|
fullStringVersion, err := ds.GetFullVersion(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
version = strings.Replace(version[0:3], ".", "", 1)
|
version := strings.Replace(fullStringVersion[0:3], ".", "", 1)
|
||||||
versionNum, err := strconv.Atoi(version)
|
versionNum, err := strconv.Atoi(version)
|
||||||
return versionNum, err
|
return versionNum, err
|
||||||
}
|
}
|
||||||
|
|||||||
400
pkg/zabbix/methods_test.go
Normal file
400
pkg/zabbix/methods_test.go
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
package zabbix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetFullVersion(t *testing.T) {
|
||||||
|
zabbixClient, err := MockZabbixClient(BasicDatasourceInfo, `{"result":"5.0.12"}`, 200)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
version, err := zabbixClient.GetFullVersion(context.Background())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "5.0.12", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFullVersionInvalidPayload(t *testing.T) {
|
||||||
|
zabbixClient, err := MockZabbixClient(BasicDatasourceInfo, `{"result":{"version":"5.0.12"}}`, 200)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
version, err := zabbixClient.GetFullVersion(context.Background())
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, "", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetVersion(t *testing.T) {
|
||||||
|
zabbixClient, err := MockZabbixClient(BasicDatasourceInfo, `{"result":"5.4.3"}`, 200)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
version, err := zabbixClient.GetVersion(context.Background())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 54, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetVersionReturnsError(t *testing.T) {
|
||||||
|
zabbixClient, err := MockZabbixClient(BasicDatasourceInfo, `{"result":"a.b.c"}`, 200)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
version, err := zabbixClient.GetVersion(context.Background())
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, 0, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetHistory(t *testing.T) {
|
||||||
|
var historyCalls []int
|
||||||
|
client := NewZabbixClientWithHandler(t, func(payload ApiRequestPayload) string {
|
||||||
|
if payload.Method == "history.get" {
|
||||||
|
historyCalls = append(historyCalls, int(payload.Params["history"].(float64)))
|
||||||
|
return `{"result":[{"itemid":"1","clock":"1","value":"1.2","ns":"0"}]}`
|
||||||
|
}
|
||||||
|
return `{"result":null}`
|
||||||
|
})
|
||||||
|
|
||||||
|
items := []*Item{
|
||||||
|
{ID: "10", ValueType: 0},
|
||||||
|
{ID: "20", ValueType: 3},
|
||||||
|
}
|
||||||
|
tr := backend.TimeRange{
|
||||||
|
From: time.Unix(0, 0),
|
||||||
|
To: time.Unix(10, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
history, err := client.GetHistory(context.Background(), items, tr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, history, 2)
|
||||||
|
assert.ElementsMatch(t, []int{0, 3}, historyCalls)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetTrend(t *testing.T) {
|
||||||
|
var capturedIDs []string
|
||||||
|
client := NewZabbixClientWithHandler(t, func(payload ApiRequestPayload) string {
|
||||||
|
if payload.Method == "trend.get" {
|
||||||
|
for _, raw := range payload.Params["itemids"].([]interface{}) {
|
||||||
|
capturedIDs = append(capturedIDs, raw.(string))
|
||||||
|
}
|
||||||
|
return `{"result":[{"itemid":"1","clock":"1","value_min":"0","value_avg":"1","value_max":"2"}]}`
|
||||||
|
}
|
||||||
|
return `{"result":null}`
|
||||||
|
})
|
||||||
|
|
||||||
|
items := []*Item{{ID: "100"}, {ID: "200"}}
|
||||||
|
tr := backend.TimeRange{
|
||||||
|
From: time.Unix(0, 0),
|
||||||
|
To: time.Unix(10, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
trend, err := client.GetTrend(context.Background(), items, tr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, trend, 1)
|
||||||
|
assert.ElementsMatch(t, []string{"100", "200"}, capturedIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetItems(t *testing.T) {
|
||||||
|
client := NewZabbixClientWithResponses(t, map[string]string{
|
||||||
|
"hostgroup.get": `{"result":[{"groupid":"1","name":"Servers"}]}`,
|
||||||
|
"host.get": `{"result":[{"hostid":"10","name":"web01"}]}`,
|
||||||
|
"item.get": `{
|
||||||
|
"result":[
|
||||||
|
{"itemid":"100","name":"CPU usage"},
|
||||||
|
{"itemid":"200","name":"Memory usage"}
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
items, err := client.GetItems(context.Background(), "Servers", "web01", "", "/CPU/", "num", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
if assert.Len(t, items, 1) {
|
||||||
|
assert.Equal(t, "100", items[0].ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetItemsBefore54(t *testing.T) {
|
||||||
|
client := NewZabbixClientWithResponses(t, map[string]string{
|
||||||
|
"hostgroup.get": `{"result":[{"groupid":"1","name":"Servers"}]}`,
|
||||||
|
"host.get": `{"result":[{"hostid":"10","name":"web01"}]}`,
|
||||||
|
"application.get": `{
|
||||||
|
"result":[
|
||||||
|
{"applicationid":"50","name":"Databases"},
|
||||||
|
{"applicationid":"60","name":"Apps"}
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
"item.get": `{
|
||||||
|
"result":[
|
||||||
|
{"itemid":"500","name":"DB Size"},
|
||||||
|
{"itemid":"600","name":"API latency"}
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
items, err := client.GetItemsBefore54(context.Background(), "Servers", "web01", "Databases", "/DB/", "num", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
if assert.Len(t, items, 1) {
|
||||||
|
assert.Equal(t, "500", items[0].ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterItemsByQuery(t *testing.T) {
|
||||||
|
items := []*Item{
|
||||||
|
{Name: "CPU usage"},
|
||||||
|
{Name: "Memory usage"},
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered, err := filterItemsByQuery(items, "/CPU/")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, filtered, 1)
|
||||||
|
assert.Equal(t, "CPU usage", filtered[0].Name)
|
||||||
|
|
||||||
|
filtered, err = filterItemsByQuery(items, "Memory usage")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, filtered, 1)
|
||||||
|
assert.Equal(t, "Memory usage", filtered[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetApps(t *testing.T) {
|
||||||
|
client := NewZabbixClientWithResponses(t, map[string]string{
|
||||||
|
"hostgroup.get": `{"result":[{"groupid":"1","name":"Servers"}]}`,
|
||||||
|
"host.get": `{"result":[{"hostid":"10","name":"web01"}]}`,
|
||||||
|
"application.get": `{
|
||||||
|
"result":[
|
||||||
|
{"applicationid":"50","name":"API"},
|
||||||
|
{"applicationid":"60","name":"DB"}
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
apps, err := client.GetApps(context.Background(), "Servers", "web01", "/^API/")
|
||||||
|
require.NoError(t, err)
|
||||||
|
if assert.Len(t, apps, 1) {
|
||||||
|
assert.Equal(t, "50", apps[0].ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterAppsByQuery(t *testing.T) {
|
||||||
|
apps := []Application{
|
||||||
|
{Name: "API"},
|
||||||
|
{Name: "DB"},
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered, err := filterAppsByQuery(apps, "/^A/")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, filtered, 1)
|
||||||
|
assert.Equal(t, "API", filtered[0].Name)
|
||||||
|
|
||||||
|
filtered, err = filterAppsByQuery(apps, "DB")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, filtered, 1)
|
||||||
|
assert.Equal(t, "DB", filtered[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetItemTags(t *testing.T) {
|
||||||
|
client := NewZabbixClientWithResponses(t, map[string]string{
|
||||||
|
"hostgroup.get": `{"result":[{"groupid":"1","name":"Servers"}]}`,
|
||||||
|
"host.get": `{"result":[{"hostid":"10","name":"web01"}]}`,
|
||||||
|
"item.get": `{
|
||||||
|
"result":[
|
||||||
|
{"itemid":"1","name":"CPU","tags":[{"tag":"Env","value":"prod"},{"tag":"Application","value":"api"}]},
|
||||||
|
{"itemid":"2","name":"Mem","tags":[{"tag":"Env","value":"stage"},{"tag":"Env","value":"prod"}]}
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
tags, err := client.GetItemTags(context.Background(), "Servers", "web01", "/^Env/")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.ElementsMatch(t, []ItemTag{
|
||||||
|
{Tag: "Env", Value: "prod"},
|
||||||
|
{Tag: "Env", Value: "stage"},
|
||||||
|
}, tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterTags(t *testing.T) {
|
||||||
|
tags := []ItemTag{
|
||||||
|
{Tag: "Env", Value: "prod"},
|
||||||
|
{Tag: "Application", Value: "api"},
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered, err := filterTags(tags, "/^Env/")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, filtered, 1)
|
||||||
|
assert.Equal(t, "Env", filtered[0].Tag)
|
||||||
|
|
||||||
|
filtered, err = filterTags(tags, "Application: api")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, filtered, 1)
|
||||||
|
assert.Equal(t, "Application", filtered[0].Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetHosts(t *testing.T) {
|
||||||
|
client := NewZabbixClientWithResponses(t, map[string]string{
|
||||||
|
"hostgroup.get": `{"result":[{"groupid":"1","name":"Servers"}]}`,
|
||||||
|
"host.get": `{
|
||||||
|
"result":[
|
||||||
|
{"hostid":"10","name":"web01"},
|
||||||
|
{"hostid":"20","name":"db01"}
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
hosts, err := client.GetHosts(context.Background(), "Servers", "/web/")
|
||||||
|
require.NoError(t, err)
|
||||||
|
if assert.Len(t, hosts, 1) {
|
||||||
|
assert.Equal(t, "web01", hosts[0].Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterHostsByQuery(t *testing.T) {
|
||||||
|
hosts := []Host{
|
||||||
|
{Name: "web01"},
|
||||||
|
{Name: "db01"},
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered, err := filterHostsByQuery(hosts, "/^web/")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, filtered, 1)
|
||||||
|
assert.Equal(t, "web01", filtered[0].Name)
|
||||||
|
|
||||||
|
filtered, err = filterHostsByQuery(hosts, "db01")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, filtered, 1)
|
||||||
|
assert.Equal(t, "db01", filtered[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetGroups(t *testing.T) {
|
||||||
|
client := NewZabbixClientWithResponses(t, map[string]string{
|
||||||
|
"hostgroup.get": `{"result":[{"groupid":"1","name":"Servers"},{"groupid":"2","name":"Apps"}]}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
groups, err := client.GetGroups(context.Background(), "/Apps/")
|
||||||
|
require.NoError(t, err)
|
||||||
|
if assert.Len(t, groups, 1) {
|
||||||
|
assert.Equal(t, "Apps", groups[0].Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterGroupsByQuery(t *testing.T) {
|
||||||
|
groups := []Group{
|
||||||
|
{Name: "Servers"},
|
||||||
|
{Name: "Apps"},
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered, err := filterGroupsByQuery(groups, "/Apps/")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, filtered, 1)
|
||||||
|
assert.Equal(t, "Apps", filtered[0].Name)
|
||||||
|
|
||||||
|
filtered, err = filterGroupsByQuery(groups, "Servers")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, filtered, 1)
|
||||||
|
assert.Equal(t, "Servers", filtered[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAllItemsBuildsParams(t *testing.T) {
|
||||||
|
var lastRequest ApiRequestPayload
|
||||||
|
client := NewZabbixClientWithHandler(t, func(payload ApiRequestPayload) string {
|
||||||
|
if payload.Method == "item.get" {
|
||||||
|
lastRequest = payload
|
||||||
|
return `{"result":[{"itemid":"1","name":"CPU $1","key_":"system.cpu[user]","value_type":"0","hosts":[{"hostid":"10","name":"web"}]}]}`
|
||||||
|
}
|
||||||
|
return `{"result":null}`
|
||||||
|
})
|
||||||
|
|
||||||
|
items, err := client.GetAllItems(
|
||||||
|
context.Background(),
|
||||||
|
[]string{"10"},
|
||||||
|
nil,
|
||||||
|
"num",
|
||||||
|
false,
|
||||||
|
"Env: prod, Application: api",
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
if assert.Len(t, items, 1) {
|
||||||
|
assert.Equal(t, "CPU user", items[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, "item.get", lastRequest.Method)
|
||||||
|
params := lastRequest.Params
|
||||||
|
assert.Equal(t, []interface{}{"10"}, params["hostids"])
|
||||||
|
assert.Equal(t, true, params["monitored"])
|
||||||
|
filter := params["filter"].(map[string]interface{})
|
||||||
|
assert.ElementsMatch(t, []interface{}{float64(0), float64(3)}, filter["value_type"].([]interface{}))
|
||||||
|
tags := params["tags"].([]interface{})
|
||||||
|
if assert.Len(t, tags, 2) {
|
||||||
|
first := tags[0].(map[string]interface{})
|
||||||
|
second := tags[1].(map[string]interface{})
|
||||||
|
assert.Equal(t, "Application", first["tag"])
|
||||||
|
assert.Equal(t, "Env", second["tag"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetItemsByIDs(t *testing.T) {
|
||||||
|
var lastRequest ApiRequestPayload
|
||||||
|
client := NewZabbixClientWithHandler(t, func(payload ApiRequestPayload) string {
|
||||||
|
if payload.Method == "item.get" {
|
||||||
|
lastRequest = payload
|
||||||
|
return `{"result":[{"itemid":"1","name":"CPU"}]}`
|
||||||
|
}
|
||||||
|
return `{"result":null}`
|
||||||
|
})
|
||||||
|
|
||||||
|
items, err := client.GetItemsByIDs(context.Background(), []string{"1"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, items, 1)
|
||||||
|
assert.Equal(t, []interface{}{"1"}, lastRequest.Params["itemids"].([]interface{}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAllApps(t *testing.T) {
|
||||||
|
client := NewZabbixClientWithResponses(t, map[string]string{
|
||||||
|
"application.get": `{"result":[{"applicationid":"10","name":"API"}]}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
apps, err := client.GetAllApps(context.Background(), []string{"1"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, apps, 1)
|
||||||
|
assert.Equal(t, "API", apps[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAllHosts(t *testing.T) {
|
||||||
|
client := NewZabbixClientWithResponses(t, map[string]string{
|
||||||
|
"host.get": `{"result":[{"hostid":"10","name":"web01"}]}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
hosts, err := client.GetAllHosts(context.Background(), []string{"1"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, hosts, 1)
|
||||||
|
assert.Equal(t, "web01", hosts[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAllGroups(t *testing.T) {
|
||||||
|
client := NewZabbixClientWithResponses(t, map[string]string{
|
||||||
|
"hostgroup.get": `{"result":[{"groupid":"1","name":"Servers"}]}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
groups, err := client.GetAllGroups(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, groups, 1)
|
||||||
|
assert.Equal(t, "Servers", groups[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetValueMappings(t *testing.T) {
|
||||||
|
client := NewZabbixClientWithResponses(t, map[string]string{
|
||||||
|
"valuemap.get": `{
|
||||||
|
"result":[
|
||||||
|
{
|
||||||
|
"valuemapid":"1",
|
||||||
|
"name":"Status",
|
||||||
|
"mappings":[{"value":"0","newvalue":"down"}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
valueMaps, err := client.GetValueMappings(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, valueMaps, 1)
|
||||||
|
assert.Equal(t, "Status", valueMaps[0].Name)
|
||||||
|
}
|
||||||
@@ -1,12 +1,31 @@
|
|||||||
package zabbix
|
package zabbix
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"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/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"time"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var BasicDatasourceInfo = &backend.DataSourceInstanceSettings{
|
||||||
|
ID: 1,
|
||||||
|
Name: "TestDatasource",
|
||||||
|
URL: "http://zabbix.org/zabbix",
|
||||||
|
JSONData: []byte(`{"username":"username", "password":"password", "cacheTTL":"10m"}`),
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApiRequestPayload struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Params map[string]interface{} `json:"params"`
|
||||||
|
}
|
||||||
|
|
||||||
func MockZabbixClient(dsInfo *backend.DataSourceInstanceSettings, body string, statusCode int) (*Zabbix, error) {
|
func MockZabbixClient(dsInfo *backend.DataSourceInstanceSettings, body string, statusCode int) (*Zabbix, error) {
|
||||||
zabbixAPI, err := zabbixapi.MockZabbixAPI(body, statusCode)
|
zabbixAPI, err := zabbixapi.MockZabbixAPI(body, statusCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -34,3 +53,50 @@ func MockZabbixClientResponse(client *Zabbix, body string, statusCode int) (*Zab
|
|||||||
|
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewZabbixClientWithHandler(t *testing.T, handler func(ApiRequestPayload) string) *Zabbix {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
httpClient := zabbixapi.NewTestClient(func(req *http.Request) *http.Response {
|
||||||
|
body, err := io.ReadAll(req.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var payload ApiRequestPayload
|
||||||
|
require.NoError(t, json.Unmarshal(body, &payload))
|
||||||
|
|
||||||
|
responseBody := handler(payload)
|
||||||
|
if responseBody == "" {
|
||||||
|
responseBody = `{"result":null}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return &http.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Body: io.NopCloser(strings.NewReader(responseBody)),
|
||||||
|
Header: make(http.Header),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
dsSettings := *BasicDatasourceInfo
|
||||||
|
zabbixAPI, err := zabbixapi.New(dsSettings, httpClient)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
zabbixSettings := &settings.ZabbixDatasourceSettings{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
client, err := New(BasicDatasourceInfo, zabbixSettings, zabbixAPI)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
client.api.SetAuth("test")
|
||||||
|
client.version = 60
|
||||||
|
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewZabbixClientWithResponses(t *testing.T, responses map[string]string) *Zabbix {
|
||||||
|
return NewZabbixClientWithHandler(t, func(payload ApiRequestPayload) string {
|
||||||
|
if resp, ok := responses[payload.Method]; ok {
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
return `{"result":null}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,21 +7,12 @@ import (
|
|||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/settings"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/settings"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var basicDatasourceInfo = &backend.DataSourceInstanceSettings{
|
|
||||||
ID: 1,
|
|
||||||
Name: "TestDatasource",
|
|
||||||
URL: "http://zabbix.org/zabbix",
|
|
||||||
JSONData: []byte(`{"username":"username", "password":"password", "cacheTTL":"10m"}`),
|
|
||||||
}
|
|
||||||
|
|
||||||
var emptyParams = map[string]interface{}{}
|
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.Authenticate(context.Background())
|
err := zabbixClient.Authenticate(context.Background())
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -29,7 +20,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.Authenticate(context.Background())
|
err := zabbixClient.Authenticate(context.Background())
|
||||||
|
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
@@ -37,7 +28,7 @@ func TestLoginError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestZabbixAPIQuery(t *testing.T) {
|
func TestZabbixAPIQuery(t *testing.T) {
|
||||||
zabbixClient, _ := MockZabbixClient(basicDatasourceInfo, `{"result":"test"}`, 200)
|
zabbixClient, _ := MockZabbixClient(BasicDatasourceInfo, `{"result":"test"}`, 200)
|
||||||
resp, err := zabbixClient.Request(context.Background(), &ZabbixAPIRequest{Method: "test.get", Params: emptyParams})
|
resp, err := zabbixClient.Request(context.Background(), &ZabbixAPIRequest{Method: "test.get", Params: emptyParams})
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -50,7 +41,7 @@ func TestZabbixAPIQuery(t *testing.T) {
|
|||||||
func TestCachedQuery(t *testing.T) {
|
func TestCachedQuery(t *testing.T) {
|
||||||
// Using methods with caching enabled
|
// Using methods with caching enabled
|
||||||
query := &ZabbixAPIRequest{Method: "host.get", Params: emptyParams}
|
query := &ZabbixAPIRequest{Method: "host.get", Params: emptyParams}
|
||||||
zabbixClient, _ := MockZabbixClient(basicDatasourceInfo, `{"result":"testOld"}`, 200)
|
zabbixClient, _ := MockZabbixClient(BasicDatasourceInfo, `{"result":"testOld"}`, 200)
|
||||||
|
|
||||||
// Run query first time
|
// Run query first time
|
||||||
resp, err := zabbixClient.Request(context.Background(), query)
|
resp, err := zabbixClient.Request(context.Background(), query)
|
||||||
@@ -72,7 +63,7 @@ func TestCachedQuery(t *testing.T) {
|
|||||||
func TestNonCachedQuery(t *testing.T) {
|
func TestNonCachedQuery(t *testing.T) {
|
||||||
// Using methods with caching disabled
|
// Using methods with caching disabled
|
||||||
query := &ZabbixAPIRequest{Method: "history.get", Params: emptyParams}
|
query := &ZabbixAPIRequest{Method: "history.get", Params: emptyParams}
|
||||||
zabbixClient, _ := MockZabbixClient(basicDatasourceInfo, `{"result":"testOld"}`, 200)
|
zabbixClient, _ := MockZabbixClient(BasicDatasourceInfo, `{"result":"testOld"}`, 200)
|
||||||
|
|
||||||
// Run query first time
|
// Run query first time
|
||||||
resp, err := zabbixClient.Request(context.Background(), query)
|
resp, err := zabbixClient.Request(context.Background(), query)
|
||||||
@@ -93,7 +84,7 @@ func TestNonCachedQuery(t *testing.T) {
|
|||||||
|
|
||||||
func TestItemTagCache(t *testing.T) {
|
func TestItemTagCache(t *testing.T) {
|
||||||
zabbixClient, _ := MockZabbixClient(
|
zabbixClient, _ := MockZabbixClient(
|
||||||
basicDatasourceInfo,
|
BasicDatasourceInfo,
|
||||||
`{"result":[{"itemid":"1","name":"test1"}]}`,
|
`{"result":[{"itemid":"1","name":"test1"}]}`,
|
||||||
200,
|
200,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
toDataQueryResponse,
|
toDataQueryResponse,
|
||||||
getDataSourceSrv,
|
getDataSourceSrv,
|
||||||
HealthCheckError,
|
HealthCheckError,
|
||||||
|
DataSourceWithBackend,
|
||||||
} from '@grafana/runtime';
|
} from '@grafana/runtime';
|
||||||
import {
|
import {
|
||||||
DataFrame,
|
DataFrame,
|
||||||
@@ -55,6 +56,7 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
dbConnectionRetentionPolicy: string;
|
dbConnectionRetentionPolicy: string;
|
||||||
enableDebugLog: boolean;
|
enableDebugLog: boolean;
|
||||||
datasourceId: number;
|
datasourceId: number;
|
||||||
|
instanceSettings: DataSourceInstanceSettings<ZabbixDSOptions>;
|
||||||
zabbix: Zabbix;
|
zabbix: Zabbix;
|
||||||
|
|
||||||
replaceTemplateVars: (target: any, scopedVars?: any) => any;
|
replaceTemplateVars: (target: any, scopedVars?: any) => any;
|
||||||
@@ -62,6 +64,7 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
constructor(instanceSettings: DataSourceInstanceSettings<ZabbixDSOptions>) {
|
constructor(instanceSettings: DataSourceInstanceSettings<ZabbixDSOptions>) {
|
||||||
super(instanceSettings);
|
super(instanceSettings);
|
||||||
|
|
||||||
|
this.instanceSettings = instanceSettings;
|
||||||
this.enableDebugLog = config.buildInfo.env === 'development';
|
this.enableDebugLog = config.buildInfo.env === 'development';
|
||||||
|
|
||||||
this.annotations = {
|
this.annotations = {
|
||||||
@@ -767,17 +770,20 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
* Test connection to Zabbix API and external history DB.
|
* Test connection to Zabbix API and external history DB.
|
||||||
*/
|
*/
|
||||||
async testDatasource() {
|
async testDatasource() {
|
||||||
|
const backendDS = new DataSourceWithBackend(this.instanceSettings);
|
||||||
try {
|
try {
|
||||||
const { zabbixVersion, dbConnectorStatus } = await this.zabbix.testDataSource();
|
const testResult = await backendDS.testDatasource();
|
||||||
let message = `Zabbix API version: ${zabbixVersion}`;
|
return this.zabbix.testDataSource().then((dbConnectorStatus) => {
|
||||||
if (dbConnectorStatus) {
|
let message = testResult.message;
|
||||||
message += `, DB connector type: ${dbConnectorStatus.dsType}`;
|
if (dbConnectorStatus) {
|
||||||
}
|
message += `, DB connector type: ${dbConnectorStatus.dsType}`;
|
||||||
return {
|
}
|
||||||
status: 'success',
|
return {
|
||||||
title: 'Success',
|
status: testResult.status,
|
||||||
message: message,
|
message: message,
|
||||||
};
|
title: testResult.status,
|
||||||
|
};
|
||||||
|
});
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error instanceof ZabbixAPIError) {
|
if (error instanceof ZabbixAPIError) {
|
||||||
return Promise.reject({
|
return Promise.reject({
|
||||||
|
|||||||
@@ -208,32 +208,21 @@ export class Zabbix implements ZabbixConnector {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
testDataSource() {
|
testDataSource() {
|
||||||
let zabbixVersion;
|
|
||||||
let dbConnectorStatus;
|
let dbConnectorStatus;
|
||||||
return this.getVersion()
|
|
||||||
.then((version) => {
|
if (this.enableDirectDBConnection) {
|
||||||
zabbixVersion = version;
|
return this.dbConnector.testDataSource().then((testResult) => {
|
||||||
return this.getAllGroups();
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
if (this.enableDirectDBConnection) {
|
|
||||||
return this.dbConnector.testDataSource();
|
|
||||||
} else {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
return Promise.reject(error);
|
|
||||||
})
|
|
||||||
.then((testResult) => {
|
|
||||||
if (testResult) {
|
if (testResult) {
|
||||||
dbConnectorStatus = {
|
dbConnectorStatus = {
|
||||||
dsType: this.dbConnector.datasourceTypeName || this.dbConnector.datasourceTypeId,
|
dsType: this.dbConnector.datasourceTypeName || this.dbConnector.datasourceTypeId,
|
||||||
dsName: this.dbConnector.datasourceName,
|
dsName: this.dbConnector.datasourceName,
|
||||||
};
|
};
|
||||||
|
return dbConnectorStatus;
|
||||||
}
|
}
|
||||||
return { zabbixVersion, dbConnectorStatus };
|
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getVersion() {
|
async getVersion() {
|
||||||
|
|||||||
Reference in New Issue
Block a user