From 21f1d87dc1543863e53dd6f25f20640c55715a97 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Tue, 10 Aug 2021 12:34:18 +0300 Subject: [PATCH] Support item tags as variables --- .../components/VariableQueryEditor.tsx | 95 +++++++++++-------- src/datasource-zabbix/datasource.ts | 7 +- src/datasource-zabbix/query.controller.ts | 9 +- src/datasource-zabbix/types.ts | 2 + src/datasource-zabbix/zabbix/zabbix.ts | 38 ++++++-- 5 files changed, 101 insertions(+), 50 deletions(-) diff --git a/src/datasource-zabbix/components/VariableQueryEditor.tsx b/src/datasource-zabbix/components/VariableQueryEditor.tsx index bf9702d..2cbf650 100644 --- a/src/datasource-zabbix/components/VariableQueryEditor.tsx +++ b/src/datasource-zabbix/components/VariableQueryEditor.tsx @@ -1,15 +1,16 @@ import React, { PureComponent } from 'react'; import { parseLegacyVariableQuery } from '../utils'; import { SelectableValue } from '@grafana/data'; -import { VariableQuery, VariableQueryTypes, VariableQueryProps, VariableQueryData } from '../types'; +import { VariableQuery, VariableQueryData, VariableQueryProps, VariableQueryTypes } from '../types'; import { ZabbixInput } from './ZabbixInput'; -import { InlineFormLabel, Select, Input } from '@grafana/ui'; +import { InlineFormLabel, Input, Select } from '@grafana/ui'; export class ZabbixVariableQueryEditor extends PureComponent { queryTypes: Array> = [ - { value: VariableQueryTypes.Group, label: 'Group'}, + { value: VariableQueryTypes.Group, label: 'Group' }, { value: VariableQueryTypes.Host, label: 'Host' }, { value: VariableQueryTypes.Application, label: 'Application' }, + { value: VariableQueryTypes.ItemTag, label: 'Item tag' }, { value: VariableQueryTypes.Item, label: 'Item' }, { value: VariableQueryTypes.ItemValues, label: 'Item values' }, ]; @@ -20,6 +21,7 @@ export class ZabbixVariableQueryEditor extends PureComponent { - const { queryType, group, host, application, item } = this.state; - const queryModel = { queryType, group, host, application, item }; + const { queryType, group, host, application, itemTag, item } = this.state; + const queryModel = { queryType, group, host, application, itemTag, item }; this.props.onChange(queryModel, `Zabbix - ${queryType}`); - } + }; handleQueryTypeChange = (selectedItem: SelectableValue) => { this.setState({ @@ -79,14 +81,16 @@ export class ZabbixVariableQueryEditor extends PureComponent @@ -109,20 +113,32 @@ export class ZabbixVariableQueryEditor extends PureComponent {selectedQueryType.value !== VariableQueryTypes.Group && -
- Host - this.handleQueryUpdate(evt, 'host')} - onBlur={this.handleQueryChange} - /> -
+
+ Host + this.handleQueryUpdate(evt, 'host')} + onBlur={this.handleQueryChange} + /> +
} {(selectedQueryType.value === VariableQueryTypes.Application || + selectedQueryType.value === VariableQueryTypes.ItemTag || selectedQueryType.value === VariableQueryTypes.Item || selectedQueryType.value === VariableQueryTypes.ItemValues) && -
+
+ {supportsItemTags && ( +
+ Item tag + this.handleQueryUpdate(evt, 'itemTag')} + onBlur={this.handleQueryChange} + /> +
+ )} + {!supportsItemTags && (
Application
- {(selectedQueryType.value === VariableQueryTypes.Item || - selectedQueryType.value === VariableQueryTypes.ItemValues) && -
- Item - this.handleQueryUpdate(evt, 'item')} - onBlur={this.handleQueryChange} - /> -
- } + )} + {(selectedQueryType.value === VariableQueryTypes.Item || + selectedQueryType.value === VariableQueryTypes.ItemValues) && +
+ Item + this.handleQueryUpdate(evt, 'item')} + onBlur={this.handleQueryChange} + />
+ } +
} {legacyQuery && -
- Legacy Query - -
+
+ Legacy Query + +
} ); diff --git a/src/datasource-zabbix/datasource.ts b/src/datasource-zabbix/datasource.ts index 81919f4..eaaad3d 100644 --- a/src/datasource-zabbix/datasource.ts +++ b/src/datasource-zabbix/datasource.ts @@ -663,7 +663,7 @@ export class ZabbixDatasource extends DataSourceApi { if (target[p] && target[p].filter) { target[p].filter = this.replaceTemplateVars(target[p].filter, options.scopedVars); diff --git a/src/datasource-zabbix/query.controller.ts b/src/datasource-zabbix/query.controller.ts index 2615c1d..9131c41 100644 --- a/src/datasource-zabbix/query.controller.ts +++ b/src/datasource-zabbix/query.controller.ts @@ -315,7 +315,14 @@ export class ZabbixQueryController extends QueryCtrl { if (!this.metric?.tagList) { return []; } - return this.metric.tagList.map(t => itemTagToString(t)); + const tags = this.metric.tagList.map(t => itemTagToString(t)); + + // Add template variables + _.forEach(this.templateSrv.getVariables(), variable => { + tags.unshift('$' + variable.name); + }); + + return tags; }; getTemplateVariables() { diff --git a/src/datasource-zabbix/types.ts b/src/datasource-zabbix/types.ts index 651b48a..41284a8 100644 --- a/src/datasource-zabbix/types.ts +++ b/src/datasource-zabbix/types.ts @@ -150,6 +150,7 @@ export interface VariableQuery { group?: string; host?: string; application?: string; + itemTag?: string; item?: string; } @@ -159,6 +160,7 @@ export enum VariableQueryTypes { Group = 'group', Host = 'host', Application = 'application', + ItemTag = 'itemTag', Item = 'item', ItemValues = 'itemValues', } diff --git a/src/datasource-zabbix/zabbix/zabbix.ts b/src/datasource-zabbix/zabbix/zabbix.ts index 0434b19..ec53e03 100644 --- a/src/datasource-zabbix/zabbix/zabbix.ts +++ b/src/datasource-zabbix/zabbix/zabbix.ts @@ -2,7 +2,6 @@ import _ from 'lodash'; import moment from 'moment'; import semver from 'semver'; import * as utils from '../utils'; -import { itemTagToString } from '../utils'; import responseHandler from '../responseHandler'; import { CachingProxy } from './proxy/cachingProxy'; import { DBConnector } from './connectors/dbConnector'; @@ -11,7 +10,7 @@ import { SQLConnector } from './connectors/sql/sqlConnector'; import { InfluxDBConnector } from './connectors/influxdb/influxdbConnector'; import { ZabbixConnector } from './types'; import { joinTriggersWithEvents, joinTriggersWithProblems } from '../problemsHandler'; -import { ProblemDTO, ZBXItemTag } from '../types'; +import { ProblemDTO, ZBXItem, ZBXItemTag } from '../types'; interface AppsResponse extends Array { appFilterEmpty?: boolean; @@ -20,7 +19,7 @@ interface AppsResponse extends Array { const REQUESTS_TO_PROXYFY = [ 'getHistory', 'getTrend', 'getGroups', 'getHosts', 'getApps', 'getItems', 'getMacros', 'getItemsByIDs', - 'getEvents', 'getAlerts', 'getHostAlerts', 'getAcknowledges', 'getITService', 'getSLA', 'getVersion', 'getProxies', + 'getEvents', 'getAlerts', 'getHostAlerts', 'getAcknowledges', 'getITService', 'getSLA', 'getProxies', 'getEventAlerts', 'getExtendedEventData', 'getProblems', 'getEventsHistory', 'getTriggersByIds', 'getScripts', 'getValueMappings' ]; @@ -31,7 +30,7 @@ const REQUESTS_TO_CACHE = [ const REQUESTS_TO_BIND = [ 'getHistory', 'getTrend', 'getMacros', 'getItemsByIDs', 'getEvents', 'getAlerts', 'getHostAlerts', 'getAcknowledges', 'getITService', 'acknowledgeEvent', 'getProxies', 'getEventAlerts', - 'getExtendedEventData', 'getScripts', 'executeScript', 'getValueMappings', 'isZabbix54OrHigher' + 'getExtendedEventData', 'getScripts', 'executeScript', 'getValueMappings' ]; export class Zabbix implements ZabbixConnector { @@ -57,7 +56,6 @@ export class Zabbix implements ZabbixConnector { getExtendedEventData: (eventids) => Promise; getMacros: (hostids: any[]) => Promise; getValueMappings: () => Promise; - isZabbix54OrHigher: () => boolean; constructor(options) { const { @@ -172,13 +170,23 @@ export class Zabbix implements ZabbixConnector { async getVersion() { if (!this.version) { - this.version = await this.zabbixAPI.initVersion(); + if (this.zabbixAPI.version) { + this.version = this.zabbixAPI.version; + } else { + this.version = await this.zabbixAPI.initVersion(); + } } return this.version; } supportsApplications() { - return this.version ? semver.lt(this.version, '5.4.0') : true; + const version = this.version || this.zabbixAPI.version; + return version ? semver.lt(version, '5.4.0') : true; + } + + isZabbix54OrHigher() { + const version = this.version || this.zabbixAPI.version; + return version ? semver.gte(version, '5.4.0') : false; } getItemsFromTarget(target, options) { @@ -263,6 +271,20 @@ export class Zabbix implements ZabbixConnector { }); } + async getItemTags(groupFilter?, hostFilter?, itemTagFilter?) { + const items = await this.getAllItems(groupFilter, hostFilter, null, null, {}); + let tags: ZBXItemTag[] = _.flatten(items.map((item: ZBXItem) => { + if (item.tags) { + return item.tags; + } else { + return []; + } + })); + tags = _.uniqBy(tags, t => t.tag + t.value || ''); + const tagsStr = tags.map(t => ({ name: utils.itemTagToString(t) })); + return findByFilter(tagsStr, itemTagFilter); + } + async getAllItems(groupFilter, hostFilter, appFilter, itemTagFilter, options: any = {}) { const apps = await this.getApps(groupFilter, hostFilter, appFilter); let items: any[]; @@ -272,7 +294,7 @@ export class Zabbix implements ZabbixConnector { if (itemTagFilter) { items = items.filter(item => { if (item.tags) { - const tags: ZBXItemTag[] = item.tags.map(t => itemTagToString(t)); + const tags: ZBXItemTag[] = item.tags.map(t => utils.itemTagToString(t)); return tags.includes(itemTagFilter); } else { return false;