Support item tags, fixes #1258

This commit is contained in:
Alexander Zobnin
2021-08-09 14:57:49 +03:00
parent c6441cccf0
commit 915973829d
15 changed files with 574 additions and 364 deletions

View File

@@ -75,6 +75,7 @@ type QueryModel struct {
Group QueryFilter `json:"group"`
Host QueryFilter `json:"host"`
Application QueryFilter `json:"application"`
ItemTag QueryFilter `json:"itemTag"`
Item QueryFilter `json:"item"`
// Item ID mode

View File

@@ -47,9 +47,10 @@ func (ds *ZabbixDatasourceInstance) queryNumericItems(ctx context.Context, query
groupFilter := query.Group.Filter
hostFilter := query.Host.Filter
appFilter := query.Application.Filter
itemTagFilter := query.ItemTag.Filter
itemFilter := query.Item.Filter
items, err := ds.zabbix.GetItems(ctx, groupFilter, hostFilter, appFilter, itemFilter, "num")
items, err := ds.zabbix.GetItems(ctx, groupFilter, hostFilter, appFilter, itemTagFilter, itemFilter, "num")
if err != nil {
return nil, err
}

View File

@@ -2,6 +2,8 @@ package zabbix
import (
"context"
"strconv"
"strings"
"github.com/grafana/grafana-plugin-sdk-go/backend"
)
@@ -78,7 +80,7 @@ func (ds *Zabbix) getTrend(ctx context.Context, itemids []string, timeRange back
return trend, err
}
func (ds *Zabbix) GetItems(ctx context.Context, groupFilter string, hostFilter string, appFilter string, itemFilter string, itemType string) ([]*Item, error) {
func (ds *Zabbix) GetItems(ctx context.Context, groupFilter string, hostFilter string, appFilter string, itemTagFilter string, itemFilter string, itemType string) ([]*Item, error) {
hosts, err := ds.GetHosts(ctx, groupFilter, hostFilter)
if err != nil {
return nil, err
@@ -90,7 +92,8 @@ func (ds *Zabbix) GetItems(ctx context.Context, groupFilter string, hostFilter s
apps, err := ds.GetApps(ctx, groupFilter, hostFilter, appFilter)
// Apps not supported in Zabbix 5.4 and higher
if isAppMethodNotFoundError(err) {
isZabbix54orHigher := isAppMethodNotFoundError(err)
if isZabbix54orHigher {
apps = []Application{}
} else if err != nil {
return nil, err
@@ -107,9 +110,50 @@ func (ds *Zabbix) GetItems(ctx context.Context, groupFilter string, hostFilter s
allItems, err = ds.GetAllItems(ctx, nil, appids, itemType)
}
if isZabbix54orHigher && itemTagFilter != "" {
allItems, err = filterItemsByTag(allItems, itemTagFilter)
if err != nil {
return nil, err
}
}
return filterItemsByQuery(allItems, itemFilter)
}
func filterItemsByTag(items []*Item, filter string) ([]*Item, error) {
re, err := parseFilter(filter)
if err != nil {
return nil, err
}
var filteredItems []*Item
for _, i := range items {
if len(i.Tags) == 0 && filter == "/.*/" {
filteredItems = append(filteredItems, i)
}
if len(i.Tags) > 0 {
var tags []string
for _, t := range i.Tags {
tags = append(tags, itemTagToString(t))
}
for _, t := range tags {
if re != nil {
if re.MatchString(t) {
filteredItems = append(filteredItems, i)
break
}
} else if t == filter {
filteredItems = append(filteredItems, i)
break
}
}
}
}
return filteredItems, nil
}
func filterItemsByQuery(items []*Item, filter string) ([]*Item, error) {
re, err := parseFilter(filter)
if err != nil {
@@ -259,6 +303,10 @@ func (ds *Zabbix) GetAllItems(ctx context.Context, hostids []string, appids []st
filter["value_type"] = []int{1, 2, 4}
}
if ds.version >= 54 {
params["selectTags"] = "extend"
}
result, err := ds.Request(ctx, &ZabbixAPIRequest{Method: "item.get", Params: params})
if err != nil {
return nil, err
@@ -347,6 +395,23 @@ func (ds *Zabbix) GetAllGroups(ctx context.Context) ([]Group, error) {
return groups, err
}
func (ds *Zabbix) GetVersion(ctx context.Context) (int, error) {
result, err := ds.request(ctx, "apiinfo.version", ZabbixAPIParams{})
if err != nil {
return 0, err
}
var version string
err = convertTo(result, &version)
if err != nil {
return 0, err
}
version = strings.Replace(version[0:3], ".", "", 1)
versionNum, err := strconv.Atoi(version)
return versionNum, err
}
func isAppMethodNotFoundError(err error) bool {
if err == nil {
return false

View File

@@ -51,6 +51,7 @@ type Item struct {
Delay string `json:"delay,omitempty"`
Units string `json:"units,omitempty"`
ValueMapID string `json:"valuemapid,omitempty"`
Tags []ItemTag `json:"tags,omitempty"`
}
type ItemHost struct {
@@ -58,6 +59,11 @@ type ItemHost struct {
Name string `json:"name,omitempty"`
}
type ItemTag struct {
Tag string `json:"tag,omitempty"`
Value string `json:"value,omitempty"`
}
type Trend []TrendPoint
type TrendPoint struct {

View File

@@ -85,3 +85,11 @@ func parseFilter(filter string) (*regexp.Regexp, error) {
return regexp.Compile(pattern)
}
func itemTagToString(tag ItemTag) string {
if tag.Value != "" {
return fmt.Sprintf("%s: %s", tag.Tag, tag.Value)
} else {
return tag.Tag
}
}

View File

@@ -14,10 +14,11 @@ import (
// Zabbix is a wrapper for Zabbix API. It wraps Zabbix API queries and performs authentication, adds caching,
// deduplication and other performance optimizations.
type Zabbix struct {
api *zabbixapi.ZabbixAPI
dsInfo *backend.DataSourceInstanceSettings
cache *ZabbixCache
logger log.Logger
api *zabbixapi.ZabbixAPI
dsInfo *backend.DataSourceInstanceSettings
cache *ZabbixCache
version int
logger log.Logger
}
// New returns new instance of Zabbix client.
@@ -49,6 +50,16 @@ func (ds *Zabbix) Request(ctx context.Context, apiReq *ZabbixAPIRequest) (*simpl
var resultJson *simplejson.Json
var err error
if ds.version == 0 {
version, err := ds.GetVersion(ctx)
if err != nil {
ds.logger.Error("Error querying Zabbix version", "error", err)
} else {
ds.logger.Debug("Got Zabbix version", "version", version)
ds.version = version
}
}
cachedResult, queryExistInCache := ds.cache.GetAPIRequest(apiReq)
if !queryExistInCache {
resultJson, err = ds.request(ctx, apiReq.Method, apiReq.Params)