Adds support for host tags (#2140)

## Sumary
When dealing with multiple hosts, it can be hard for customers filter
through and figure out which host to query metric data from. This PR
aims to make this easier by adding support for host tags so that there
is another layer of filtering / grouping applied for hosts.

## Detailed explanation
- Adds new UI components to allow adding one or more host tag filter,
and a switch to choose between `AND/OR` and `OR` operators when using
more than one filter following Zabbix's UI:
  

https://github.com/user-attachments/assets/c971f5eb-7e93-4238-bd6b-902cc657c014


https://github.com/user-attachments/assets/5f8996de-684e-4ffa-b98e-8e205c4fc1df

- Modifies the existing `getHosts` function to make a call to the
backend with a few additional parameters to `extend` (essentially
extract) the host tags for a given selected group. No backend changes
were required for this.

## Why
To make it easier for customers to query metric data when dealing with
multiple hosts.

## How to test
- Go to explore or a dashboard and create a Zabbix query where the query
type is `Metrics`
- The easiest way to test is by selecting `/.*/` for Groups, checking
the returned `Hosts` they should all be there
- Add a host tag filter and change the keys and operators as well as
switching from `AND/OR` to `OR` you should see how the values returned
for `Host` changes

## Future work
Adding variable support for host tags once this is completed.

Fixes:
https://github.com/orgs/grafana/projects/457/views/40?pane=issue&itemId=3609900134&issue=grafana%7Coss-big-tent-squad%7C126
and https://github.com/grafana/grafana-zabbix/issues/927

---------

Co-authored-by: ismail simsek <ismailsimsek09@gmail.com>
This commit is contained in:
Jocelyn Collado-Kuri
2026-01-05 05:30:55 -08:00
committed by GitHub
parent 3d0895c008
commit 0d64736e86
15 changed files with 515 additions and 38 deletions

View File

@@ -0,0 +1,151 @@
import { Tooltip, Button, Combobox, ComboboxOption, Stack, Input, RadioButtonGroup } from '@grafana/ui';
import React, { FormEvent, useCallback, useEffect, useState } from 'react';
import { HostTagOperatorLabel, HostTagOperatorValue } from './types';
import { HostTagFilter, ZabbixTagEvalType } from 'datasource/types/query';
import { getHostTagOptionLabel } from './utils';
interface Props {
hostTagOptions: ComboboxOption[];
hostTagOptionsLoading: boolean;
version: string;
evalTypeValue?: ZabbixTagEvalType;
onHostTagFilterChange?: (hostTags: HostTagFilter[]) => void;
onHostTagEvalTypeChange?: (evalType: ZabbixTagEvalType) => void;
}
export const HostTagQueryEditor = ({
hostTagOptions,
hostTagOptionsLoading,
version,
evalTypeValue,
onHostTagFilterChange,
onHostTagEvalTypeChange,
}: Props) => {
const [hostTagFilters, setHostTagFilters] = useState<HostTagFilter[]>([]);
const [hostTagValueDrafts, setHostTagValueDrafts] = useState<string[]>([]);
const operatorOptions: ComboboxOption[] = [
{ value: HostTagOperatorValue.Exists, label: HostTagOperatorLabel.Exists },
{ value: HostTagOperatorValue.Equals, label: HostTagOperatorLabel.Equals },
{ value: HostTagOperatorValue.Contains, label: HostTagOperatorLabel.Contains },
{
value: HostTagOperatorValue.DoesNotExist,
label: getHostTagOptionLabel(HostTagOperatorValue.DoesNotExist, version),
},
{
value: HostTagOperatorValue.DoesNotEqual,
label: getHostTagOptionLabel(HostTagOperatorValue.DoesNotEqual, version),
},
{
value: HostTagOperatorValue.DoesNotContain,
label: getHostTagOptionLabel(HostTagOperatorValue.DoesNotContain, version),
},
];
const onAddHostTagFilter = useCallback(() => {
setHostTagFilters((prevFilters) => [
...prevFilters,
{ tag: '', value: '', operator: HostTagOperatorValue.Contains },
]);
setHostTagValueDrafts((prevDrafts) => [...prevDrafts, '']);
}, []);
const onRemoveHostTagFilter = useCallback((index: number) => {
setHostTagFilters((prevFilters) => prevFilters.filter((_, i) => i !== index));
setHostTagValueDrafts((prevDrafts) => prevDrafts.filter((_, i) => i !== index));
}, []);
const setHostTagFilterName = useCallback((index: number, name: string) => {
setHostTagFilters((prevFilters) =>
prevFilters.map((filter, i) => (i === index ? { ...filter, tag: name } : filter))
);
}, []);
const setHostTagFilterValue = useCallback((index: number, value: string) => {
if (value !== undefined) {
setHostTagFilters((prevFilters) =>
prevFilters.map((filter, i) => (i === index ? { ...filter, value: value } : filter))
);
}
}, []);
const setHostTagFilterOperator = useCallback((index: number, operator: HostTagOperatorValue) => {
setHostTagFilters((prevFilters) =>
prevFilters.map((filter, i) => (i === index ? { ...filter, operator } : filter))
);
}, []);
useEffect(() => {
onHostTagFilterChange(hostTagFilters);
}, [hostTagFilters]);
return (
<div>
<Stack direction="row">
<Tooltip content="Add host tag filter">
<Button icon="plus" variant="secondary" aria-label="Add new host tag filter" onClick={onAddHostTagFilter} />
</Tooltip>
{hostTagFilters.length > 0 && (
<RadioButtonGroup
options={[
{ label: 'AND/OR', value: '0' }, // Default
{ label: 'OR', value: '2' },
]}
onChange={onHostTagEvalTypeChange}
value={evalTypeValue ?? '0'}
/>
)}
</Stack>
<Stack direction="column">
{hostTagFilters.map((filter, index) => {
return (
<Stack key={`host-tag-filter-${index}`} direction="row">
<Combobox
value={filter.tag}
onChange={(option: ComboboxOption) => setHostTagFilterName(index, option.value)}
options={hostTagOptions ?? []}
width={19}
loading={hostTagOptionsLoading}
/>
<Combobox
value={filter.operator}
onChange={(option: ComboboxOption<HostTagOperatorValue>) =>
setHostTagFilterOperator(index, option.value)
}
options={operatorOptions}
width={19}
/>
{filter.operator !== HostTagOperatorValue.Exists &&
filter.operator !== HostTagOperatorValue.DoesNotExist && (
<Input
value={hostTagValueDrafts[index] ?? filter.value}
onChange={(evt: FormEvent<HTMLInputElement>) => {
const value = evt?.currentTarget?.value ?? '';
setHostTagValueDrafts((prevDrafts) => {
const nextDrafts = [...prevDrafts];
nextDrafts[index] = value;
return nextDrafts;
});
}}
onBlur={(evt: FormEvent<HTMLInputElement>) =>
setHostTagFilterValue(index, evt?.currentTarget?.value)
}
width={19}
placeholder="Host tag value"
/>
)}
<Tooltip content="Remove host tag filter">
<Button
key={`remove-host-tag-${index}`}
icon="minus"
variant="secondary"
aria-label="Remove host tag filter"
onClick={() => onRemoveHostTagFilter(index)}
/>
</Tooltip>
</Stack>
);
})}
</Stack>
</div>
);
};

View File

@@ -1,15 +1,16 @@
import _ from 'lodash';
import React, { useEffect } from 'react';
import { flatten, uniqBy } from 'lodash';
import React, { useCallback, useEffect } from 'react';
import { useAsyncFn } from 'react-use';
import { InlineField, ComboboxOption } from '@grafana/ui';
import { QueryEditorRow } from './QueryEditorRow';
import { MetricPicker } from '../../../components';
import { getVariableOptions } from './utils';
import { getVariableOptions, processHostTags } from './utils';
import { ZabbixDatasource } from '../../datasource';
import { ZabbixMetricsQuery } from '../../types/query';
import { HostTagFilter, ZabbixMetricsQuery, ZabbixTagEvalType } from '../../types/query';
import { ZBXItem, ZBXItemTag } from '../../types';
import { itemTagToString } from '../../utils';
import { HostTagQueryEditor } from './HostTagQueryEditor';
import { useInterpolatedQuery } from '../../hooks/useInterpolatedQuery';
export interface Props {
@@ -28,6 +29,9 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
value: group.name,
label: group.name,
}));
if (options.length > 0) {
options.unshift({ value: '/.*/' });
}
options.unshift(...getVariableOptions());
return options;
};
@@ -37,22 +41,44 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
return options;
}, []);
const loadHostOptions = async (group: string) => {
const hosts = await datasource.zabbix.getAllHosts(group);
const loadHostTagOptions = async (group: string) => {
const hostsWithTags = await datasource.zabbix.getAllHosts(group, true);
const hostTags = processHostTags(hostsWithTags ?? []);
let options: Array<ComboboxOption<string>> = hostTags?.map((tag) => ({
value: tag.tag,
label: tag.tag,
}));
return options;
};
const loadHostOptions = async (group: string, hostTags?: HostTagFilter[], evalType?: ZabbixTagEvalType) => {
const hosts = await datasource.zabbix.getAllHosts(group, false, hostTags, evalType);
let options: Array<ComboboxOption<string>> = hosts?.map((host) => ({
value: host.name,
label: host.name,
}));
options = _.uniqBy(options, (o) => o.value);
options.unshift({ value: '/.*/' });
options = uniqBy(options, (o) => o.value);
if (options.length > 0) {
options.unshift({ value: '/.*/' });
}
options.unshift(...getVariableOptions());
return options;
};
const [{ loading: hostsLoading, value: hostOptions }, fetchHosts] = useAsyncFn(async () => {
const options = await loadHostOptions(interpolatedQuery.group.filter);
const [{ loading: hostTagsLoading, value: hostTagsOptions }, fetchHostTags] = useAsyncFn(async () => {
const options = await loadHostTagOptions(query.group.filter);
return options;
}, [interpolatedQuery.group.filter]);
}, [query.group.filter]);
const [{ loading: hostsLoading, value: hostOptions }, fetchHosts] = useAsyncFn(async () => {
const options = await loadHostOptions(
interpolatedQuery.group.filter,
interpolatedQuery.hostTags,
interpolatedQuery.evaltype
);
return options;
}, [interpolatedQuery.group.filter, interpolatedQuery.hostTags, interpolatedQuery.evaltype]);
const loadAppOptions = async (group: string, host: string) => {
const apps = await datasource.zabbix.getAllApps(group, host);
@@ -60,7 +86,7 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
value: app.name,
label: app.name,
}));
options = _.uniqBy(options, (o) => o.value);
options = uniqBy(options, (o) => o.value);
options.unshift(...getVariableOptions());
return options;
};
@@ -77,15 +103,15 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
}
const items = await datasource.zabbix.getAllItems(group, host, null, null, {});
const tags: ZBXItemTag[] = _.flatten(items.map((item: ZBXItem) => item.tags || []));
const tags: ZBXItemTag[] = flatten(items.map((item: ZBXItem) => item.tags || []));
// const tags: ZBXItemTag[] = await datasource.zabbix.getItemTags(groupFilter, hostFilter, null);
const tagList = _.uniqBy(tags, (t) => t.tag + t.value || '').map((t) => itemTagToString(t));
const tagList = uniqBy(tags, (t) => t.tag + t.value || '').map((t) => itemTagToString(t));
let options: Array<ComboboxOption<string>> = tagList?.map((tag) => ({
value: tag,
label: tag,
}));
options = _.uniqBy(options, (o) => o.value);
options = uniqBy(options, (o) => o.value);
options.unshift(...getVariableOptions());
return options;
};
@@ -123,7 +149,7 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
value: item.name,
label: item.name,
}));
itemOptions = _.uniqBy(itemOptions, (o) => o.value);
itemOptions = uniqBy(itemOptions, (o) => o.value);
itemOptions.unshift(...getVariableOptions());
return itemOptions;
};
@@ -147,6 +173,8 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
// Update suggestions on every metric change
const groupFilter = interpolatedQuery.group?.filter;
const hostTagFilters = interpolatedQuery.hostTags;
const evalType = interpolatedQuery.evaltype;
const hostFilter = interpolatedQuery.host?.filter;
const appFilter = interpolatedQuery.application?.filter;
const tagFilter = interpolatedQuery.itemTag?.filter;
@@ -157,9 +185,13 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
}, []);
useEffect(() => {
fetchHosts();
fetchHostTags();
}, [groupFilter]);
useEffect(() => {
fetchHosts();
}, [groupFilter, hostTagFilters, evalType]);
useEffect(() => {
fetchApps();
}, [groupFilter, hostFilter]);
@@ -180,6 +212,20 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
};
};
const onHostTagFilterChange = useCallback(
(hostTags: HostTagFilter[]) => {
onChange({ ...query, hostTags: hostTags });
},
[onChange, query]
);
const onHostTagEvalTypeChange = useCallback(
(evalType: ZabbixTagEvalType) => {
onChange({ ...query, evaltype: evalType });
},
[onChange, query]
);
const supportsApplications = datasource.zabbix.supportsApplications();
return (
@@ -195,6 +241,16 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
placeholder="Group name"
/>
</InlineField>
<InlineField label="Host tag" labelWidth={12}>
<HostTagQueryEditor
hostTagOptions={hostTagsOptions}
evalTypeValue={query.evaltype}
hostTagOptionsLoading={hostTagsLoading}
onHostTagFilterChange={onHostTagFilterChange}
onHostTagEvalTypeChange={onHostTagEvalTypeChange}
version={datasource.zabbix.version}
/>
</InlineField>
<InlineField label="Host" labelWidth={12}>
<MetricPicker
width={24}

View File

@@ -0,0 +1,23 @@
export enum HostTagOperatorLabel {
Exists = 'Exists',
Equals = 'Equals',
Contains = 'Contains',
DoesNotExist = 'Does not exist',
DoesNotEqual = 'Does not equal',
DoesNotContain = 'Does not contain',
}
export enum HostTagOperatorValue {
Contains = '0', // default
Equals = '1',
DoesNotContain = '2',
DoesNotEqual = '3',
Exists = '4',
DoesNotExist = '5',
}
export enum HostTagOperatorLabelBefore70 {
NotExist = 'Not exists',
NotEqual = 'Not equal',
NotLike = 'Not like',
}

View File

@@ -0,0 +1,89 @@
import { getTemplateSrv } from '@grafana/runtime';
import { getHostTagOptionLabel, getVariableOptions, processHostTags } from './utils';
import { HostTagOperatorLabel, HostTagOperatorLabelBefore70, HostTagOperatorValue } from './types';
jest.mock(
'@grafana/runtime',
() => ({
getTemplateSrv: jest.fn(),
}),
{ virtual: true }
);
describe('QueryEditor utils', () => {
describe('getVariableOptions', () => {
it('returns template variables except datasource and interval types', () => {
(getTemplateSrv as jest.Mock).mockReturnValue({
getVariables: jest.fn().mockReturnValue([
{ name: 'env', type: 'query' },
{ name: 'ds', type: 'datasource' },
{ name: 'step', type: 'interval' },
{ name: 'region', type: 'custom' },
]),
});
const options = getVariableOptions();
expect(options).toEqual([
{ label: '$env', value: '$env' },
{ label: '$region', value: '$region' },
]);
});
});
describe('processHostTags', () => {
it('deduplicates tags by tag key', () => {
const tags = processHostTags([
{
host: 'a',
name: 'a',
tags: [
{ tag: 'env', value: 'prod' },
{ tag: 'role', value: 'api' },
],
},
{
host: 'b',
name: 'b',
tags: [
{ tag: 'env', value: 'stage' },
{ tag: 'region', value: 'eu' },
],
},
{ host: 'c', name: 'c' },
]);
expect(tags).toEqual([
{ tag: 'env', value: 'prod' },
{ tag: 'role', value: 'api' },
{ tag: 'region', value: 'eu' },
]);
});
});
describe('getHostTagOptionLabel', () => {
it('returns pre-7.0 labels for legacy versions', () => {
expect(getHostTagOptionLabel(HostTagOperatorValue.DoesNotExist, '6.4.0')).toBe(
HostTagOperatorLabelBefore70.NotExist
);
expect(getHostTagOptionLabel(HostTagOperatorValue.DoesNotEqual, '6.0.0')).toBe(
HostTagOperatorLabelBefore70.NotEqual
);
expect(getHostTagOptionLabel(HostTagOperatorValue.DoesNotContain, '5.0.0')).toBe(
HostTagOperatorLabelBefore70.NotLike
);
});
it('returns current labels for 7.0 and newer', () => {
expect(getHostTagOptionLabel(HostTagOperatorValue.DoesNotExist, '7.0.0')).toBe(HostTagOperatorLabel.DoesNotExist);
expect(getHostTagOptionLabel(HostTagOperatorValue.DoesNotEqual, '7.1.0')).toBe(HostTagOperatorLabel.DoesNotEqual);
expect(getHostTagOptionLabel(HostTagOperatorValue.DoesNotContain, '7.2.0')).toBe(
HostTagOperatorLabel.DoesNotContain
);
});
it('returns empty string for unsupported values', () => {
expect(getHostTagOptionLabel(HostTagOperatorValue.Equals, '7.2.0')).toBe('');
});
});
});

View File

@@ -1,4 +1,7 @@
import { uniqBy } from 'lodash';
import { getTemplateSrv } from '@grafana/runtime';
import { Host, Tag } from 'datasource/zabbix/types';
import { HostTagOperatorLabel, HostTagOperatorLabelBefore70, HostTagOperatorValue } from './types';
export const getVariableOptions = () => {
const variables = getTemplateSrv()
@@ -11,3 +14,28 @@ export const getVariableOptions = () => {
label: `$${v.name}`,
}));
};
export function processHostTags(hosts: Host[]): Tag[] {
const hostTags = hosts.map((host) => host.tags || []).flat();
// deduplicate tags
const uniqueHostTags = uniqBy(hostTags, (tag) => tag.tag);
return uniqueHostTags;
}
/**
* Get the label for a host tag option
* Zabbix changed some of the operator labels in version 7.0.0 but the value equivalents remained the same.
* this function helps fetch the right label value for those that are different.
*/
export function getHostTagOptionLabel(value: HostTagOperatorValue, version: string): string {
switch (value) {
case HostTagOperatorValue.DoesNotExist:
return version < '7.0.0' ? HostTagOperatorLabelBefore70.NotExist : HostTagOperatorLabel.DoesNotExist;
case HostTagOperatorValue.DoesNotEqual:
return version < '7.0.0' ? HostTagOperatorLabelBefore70.NotEqual : HostTagOperatorLabel.DoesNotEqual;
case HostTagOperatorValue.DoesNotContain:
return version < '7.0.0' ? HostTagOperatorLabelBefore70.NotLike : HostTagOperatorLabel.DoesNotContain;
default:
return '';
}
}

View File

@@ -1,5 +1,6 @@
import { DataQuery } from '@grafana/schema';
import * as c from './../constants';
import { HostTagOperatorValue } from 'datasource/components/QueryEditor/types';
export type QueryType =
| typeof c.MODE_METRICS
@@ -24,6 +25,7 @@ export type ZabbixMetricsQuery = {
mode: number;
itemids: string;
useCaptureGroups: boolean;
hostTags?: HostTagFilter[];
proxy?: { filter: string };
trigger?: { filter: string };
itServiceFilter?: string;
@@ -108,3 +110,9 @@ export enum ZabbixTagEvalType {
AndOr = '0',
Or = '2',
}
export interface HostTagFilter {
tag: string;
value: string;
operator: HostTagOperatorValue;
}

View File

@@ -1,4 +1,6 @@
import { ZabbixAPIConnector } from './zabbixAPIConnector';
import { HostTagOperatorValue } from '../../../components/QueryEditor/types';
import { ZabbixTagEvalType } from 'datasource/types/query';
describe('Zabbix API connector', () => {
describe('getProxies function', () => {
@@ -154,6 +156,80 @@ describe('Zabbix API connector', () => {
expect(params.applicationids).toBeUndefined();
});
});
describe('getHosts', () => {
it('passes base params and group ids', () => {
const zabbixAPIConnector = new ZabbixAPIConnector(true, true, 123);
zabbixAPIConnector.request = jest.fn();
zabbixAPIConnector.getHosts(['1', '2']);
expect(zabbixAPIConnector.request).toHaveBeenCalledWith('host.get', {
output: ['hostid', 'name', 'host'],
sortfield: 'name',
groupids: ['1', '2'],
});
});
it('requests tags when getHostTags is true', () => {
const zabbixAPIConnector = new ZabbixAPIConnector(true, true, 123);
zabbixAPIConnector.request = jest.fn();
zabbixAPIConnector.getHosts(undefined, true);
expect(zabbixAPIConnector.request).toHaveBeenCalledWith('host.get', {
output: ['hostid', 'name', 'host', 'tags'],
sortfield: 'name',
selectTags: 'extend',
});
});
it('builds tag filters with numeric operator and evaltype', () => {
const zabbixAPIConnector = new ZabbixAPIConnector(true, true, 123);
zabbixAPIConnector.request = jest.fn();
zabbixAPIConnector.getHosts(
undefined,
false,
[
{ tag: 'role', value: 'api', operator: HostTagOperatorValue.Contains },
{ tag: '', value: 'ignore me', operator: HostTagOperatorValue.Equals },
],
ZabbixTagEvalType.Or
);
expect(zabbixAPIConnector.request).toHaveBeenCalledWith('host.get', {
output: ['hostid', 'name', 'host'],
sortfield: 'name',
selectTags: 'extend',
evaltype: 2,
tags: [{ tag: 'role', value: 'api', operator: 0 }],
});
});
it('builds tag filters with numeric operator and default evaltype when using unsupported evalType', () => {
const zabbixAPIConnector = new ZabbixAPIConnector(true, true, 123);
zabbixAPIConnector.request = jest.fn();
zabbixAPIConnector.getHosts(
undefined,
false,
[
{ tag: 'role', value: 'api', operator: HostTagOperatorValue.Contains },
{ tag: '', value: 'ignore me', operator: HostTagOperatorValue.Equals },
],
'3' as ZabbixTagEvalType
);
expect(zabbixAPIConnector.request).toHaveBeenCalledWith('host.get', {
output: ['hostid', 'name', 'host'],
sortfield: 'name',
selectTags: 'extend',
evaltype: 0,
tags: [{ tag: 'role', value: 'api', operator: 0 }],
});
});
});
});
const triggers = [

View File

@@ -3,7 +3,7 @@ import semver from 'semver';
import kbn from 'grafana/app/core/utils/kbn';
import * as utils from '../../../utils';
import { MIN_SLA_INTERVAL, ZBX_ACK_ACTION_ADD_MESSAGE, ZBX_ACK_ACTION_NONE } from '../../../constants';
import { ShowProblemTypes } from '../../../types/query';
import { HostTagFilter, ShowProblemTypes, ZabbixTagEvalType } from '../../../types/query';
import { ZBXProblem, ZBXTrigger } from '../../../types';
import { APIExecuteScriptResponse, JSONRPCError, ZBXScript } from './types';
import { BackendSrvRequest, getBackendSrv } from '@grafana/runtime';
@@ -149,7 +149,12 @@ export class ZabbixAPIConnector {
return this.request('hostgroup.get', params);
}
getHosts(groupids): Promise<any[]> {
getHosts(
groupids: string[],
getHostTags?: boolean,
hostTagFilters?: HostTagFilter[],
evalType?: ZabbixTagEvalType
): Promise<any[]> {
const params: any = {
output: ['hostid', 'name', 'host'],
sortfield: 'name',
@@ -158,6 +163,23 @@ export class ZabbixAPIConnector {
params.groupids = groupids;
}
if (getHostTags) {
params.output.push('tags');
params.selectTags = 'extend';
}
if (hostTagFilters && hostTagFilters.length > 0) {
params.selectTags = 'extend';
params.evaltype = evalType === ZabbixTagEvalType.Or || evalType === ZabbixTagEvalType.AndOr ? +evalType : 0;
// ensure only non empty tag keys are being sent
// convert operator to number since that is the expected type in Zabbix.
params.tags = hostTagFilters
.filter((tagFilter) => tagFilter.tag !== '')
.map((tagFilter) => {
return { ...tagFilter, operator: +tagFilter.operator };
});
}
return this.request('host.get', params);
}

View File

@@ -50,3 +50,15 @@ export interface ZabbixConnector {
supportsApplications: () => boolean;
}
export interface Host {
host: string;
name: string;
hostid?: string;
tags?: Tag[];
}
export interface Tag {
tag: string;
value: string;
}

View File

@@ -9,9 +9,9 @@ import { DBConnector } from './connectors/dbConnector';
import { ZabbixAPIConnector } from './connectors/zabbix_api/zabbixAPIConnector';
import { SQLConnector } from './connectors/sql/sqlConnector';
import { InfluxDBConnector } from './connectors/influxdb/influxdbConnector';
import { ZabbixConnector } from './types';
import { Host, ZabbixConnector } from './types';
import { joinTriggersWithEvents, joinTriggersWithProblems } from '../problemsHandler';
import { ZabbixMetricsQuery } from '../types/query';
import { HostTagFilter, ZabbixMetricsQuery, ZabbixTagEvalType } from '../types/query';
import { ProblemDTO, ZBXApp, ZBXHost, ZBXItem, ZBXItemTag, ZBXTrigger } from '../types';
interface AppsResponse extends Array<any> {
@@ -296,6 +296,7 @@ export class Zabbix implements ZabbixConnector {
}
getAllGroups() {
console.log(this.zabbixAPI.getGroups());
return this.zabbixAPI.getGroups();
}
@@ -306,10 +307,15 @@ export class Zabbix implements ZabbixConnector {
/**
* Get list of host belonging to given groups.
*/
getAllHosts(groupFilter): Promise<any[]> {
getAllHosts(
groupFilter: string,
getHostTags?: boolean,
hostTagFilters?: HostTagFilter[],
evalType?: ZabbixTagEvalType
): Promise<Host[]> {
return this.getGroups(groupFilter).then((groups) => {
const groupids = _.map(groups, 'groupid');
return this.zabbixAPI.getHosts(groupids);
return this.zabbixAPI.getHosts(groupids, getHostTags, hostTagFilters, evalType);
});
}