Fix compatibility with Zabbix 5.4 (skip applications filter) (#1214)
* Fix queries in Zabbix 5.4 (applications not supported) * Fix alerting queries in Zabbix 5.4
This commit is contained in:
@@ -167,7 +167,10 @@ func (ds *ZabbixDatasourceInstance) getItems(ctx context.Context, groupFilter st
|
|||||||
}
|
}
|
||||||
|
|
||||||
apps, err := ds.getApps(ctx, groupFilter, hostFilter, appFilter)
|
apps, err := ds.getApps(ctx, groupFilter, hostFilter, appFilter)
|
||||||
if err != nil {
|
// Apps not supported in Zabbix 5.4 and higher
|
||||||
|
if isAppMethodNotFoundError(err) {
|
||||||
|
apps = []map[string]interface{}{}
|
||||||
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var appids []string
|
var appids []string
|
||||||
@@ -505,3 +508,12 @@ func isNotAuthorized(err error) bool {
|
|||||||
strings.Contains(message, "Not authorised.") ||
|
strings.Contains(message, "Not authorised.") ||
|
||||||
strings.Contains(message, "Not authorized.")
|
strings.Contains(message, "Not authorized.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isAppMethodNotFoundError(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
message := err.Error()
|
||||||
|
return message == `Method not found. Incorrect API "application".`
|
||||||
|
}
|
||||||
|
|||||||
@@ -122,6 +122,7 @@
|
|||||||
<label class="gf-form-label query-keyword width-7">Application</label>
|
<label class="gf-form-label query-keyword width-7">Application</label>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
ng-model="ctrl.target.application.filter"
|
ng-model="ctrl.target.application.filter"
|
||||||
|
ng-disabled="ctrl.appFilterDisabled()"
|
||||||
bs-typeahead="ctrl.getApplicationNames"
|
bs-typeahead="ctrl.getApplicationNames"
|
||||||
ng-blur="ctrl.onTargetBlur()"
|
ng-blur="ctrl.onTargetBlur()"
|
||||||
data-min-length=0
|
data-min-length=0
|
||||||
|
|||||||
@@ -512,4 +512,8 @@ export class ZabbixQueryController extends QueryCtrl {
|
|||||||
this.init();
|
this.init();
|
||||||
this.targetChanged();
|
this.targetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appFilterDisabled() {
|
||||||
|
return !this.zabbix.supportsApplications();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,12 +46,14 @@ export class ZabbixAPIConnector {
|
|||||||
//////////////////////////
|
//////////////////////////
|
||||||
|
|
||||||
request(method: string, params?: any) {
|
request(method: string, params?: any) {
|
||||||
return this.backendAPIRequest(method, params).then(response => {
|
if (!this.version) {
|
||||||
return response?.data?.result;
|
return this.initVersion().then(() => this.request(method, params));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
backendAPIRequest(method: string, params: any = {}) {
|
return this.backendAPIRequest(method, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
async backendAPIRequest(method: string, params: any = {}) {
|
||||||
const requestOptions: BackendSrvRequest = {
|
const requestOptions: BackendSrvRequest = {
|
||||||
url: this.backendAPIUrl,
|
url: this.backendAPIUrl,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -74,14 +76,15 @@ export class ZabbixAPIConnector {
|
|||||||
requestOptions.headers.Authorization = this.requestOptions.basicAuth;
|
requestOptions.headers.Authorization = this.requestOptions.basicAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getBackendSrv().datasourceRequest(requestOptions);
|
const response = await getBackendSrv().datasourceRequest(requestOptions);
|
||||||
|
return response?.data?.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Zabbix API version
|
* Get Zabbix API version
|
||||||
*/
|
*/
|
||||||
getVersion() {
|
getVersion() {
|
||||||
return this.request('apiinfo.version');
|
return this.backendAPIRequest('apiinfo.version');
|
||||||
}
|
}
|
||||||
|
|
||||||
initVersion(): Promise<string> {
|
initVersion(): Promise<string> {
|
||||||
@@ -147,7 +150,11 @@ export class ZabbixAPIConnector {
|
|||||||
return this.request('host.get', params);
|
return this.request('host.get', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
getApps(hostids): Promise<any[]> {
|
async getApps(hostids): Promise<any[]> {
|
||||||
|
if (semver.gte(this.version, '5.4.0')) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
output: 'extend',
|
output: 'extend',
|
||||||
hostids: hostids
|
hostids: hostids
|
||||||
|
|||||||
@@ -19,4 +19,6 @@ export interface ZabbixConnector {
|
|||||||
getApps: (groupFilter?, hostFilter?, appFilter?) => any;
|
getApps: (groupFilter?, hostFilter?, appFilter?) => any;
|
||||||
getItems: (groupFilter?, hostFilter?, appFilter?, itemFilter?, options?) => any;
|
getItems: (groupFilter?, hostFilter?, appFilter?, itemFilter?, options?) => any;
|
||||||
getSLA: (itservices, timeRange, target, options?) => any;
|
getSLA: (itservices, timeRange, target, options?) => any;
|
||||||
|
|
||||||
|
supportsApplications: () => boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import semver from 'semver';
|
||||||
import * as utils from '../utils';
|
import * as utils from '../utils';
|
||||||
import responseHandler from '../responseHandler';
|
import responseHandler from '../responseHandler';
|
||||||
import { CachingProxy } from './proxy/cachingProxy';
|
import { CachingProxy } from './proxy/cachingProxy';
|
||||||
@@ -29,7 +30,7 @@ const REQUESTS_TO_CACHE = [
|
|||||||
|
|
||||||
const REQUESTS_TO_BIND = [
|
const REQUESTS_TO_BIND = [
|
||||||
'getHistory', 'getTrend', 'getMacros', 'getItemsByIDs', 'getEvents', 'getAlerts', 'getHostAlerts',
|
'getHistory', 'getTrend', 'getMacros', 'getItemsByIDs', 'getEvents', 'getAlerts', 'getHostAlerts',
|
||||||
'getAcknowledges', 'getITService', 'getVersion', 'acknowledgeEvent', 'getProxies', 'getEventAlerts',
|
'getAcknowledges', 'getITService', 'acknowledgeEvent', 'getProxies', 'getEventAlerts',
|
||||||
'getExtendedEventData', 'getScripts', 'executeScript', 'getValueMappings'
|
'getExtendedEventData', 'getScripts', 'executeScript', 'getValueMappings'
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ export class Zabbix implements ZabbixConnector {
|
|||||||
getHistoryDB: any;
|
getHistoryDB: any;
|
||||||
dbConnector: any;
|
dbConnector: any;
|
||||||
getTrendsDB: any;
|
getTrendsDB: any;
|
||||||
|
version: string;
|
||||||
|
|
||||||
getHistory: (items, timeFrom, timeTill) => Promise<any>;
|
getHistory: (items, timeFrom, timeTill) => Promise<any>;
|
||||||
getTrend: (items, timeFrom, timeTill) => Promise<any>;
|
getTrend: (items, timeFrom, timeTill) => Promise<any>;
|
||||||
@@ -54,7 +56,6 @@ export class Zabbix implements ZabbixConnector {
|
|||||||
getEventAlerts: (eventids) => Promise<any>;
|
getEventAlerts: (eventids) => Promise<any>;
|
||||||
getExtendedEventData: (eventids) => Promise<any>;
|
getExtendedEventData: (eventids) => Promise<any>;
|
||||||
getMacros: (hostids: any[]) => Promise<any>;
|
getMacros: (hostids: any[]) => Promise<any>;
|
||||||
getVersion: () => Promise<string>;
|
|
||||||
getValueMappings: () => Promise<any>;
|
getValueMappings: () => Promise<any>;
|
||||||
|
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
@@ -168,6 +169,17 @@ export class Zabbix implements ZabbixConnector {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getVersion() {
|
||||||
|
if (!this.version) {
|
||||||
|
this.version = await this.zabbixAPI.initVersion();
|
||||||
|
}
|
||||||
|
return this.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
supportsApplications() {
|
||||||
|
return this.version ? semver.lt(this.version, '5.4.0') : true;
|
||||||
|
}
|
||||||
|
|
||||||
getItemsFromTarget(target, options) {
|
getItemsFromTarget(target, options) {
|
||||||
const parts = ['group', 'host', 'application', 'item'];
|
const parts = ['group', 'host', 'application', 'item'];
|
||||||
const filters = _.map(parts, p => target[p].filter);
|
const filters = _.map(parts, p => target[p].filter);
|
||||||
@@ -218,7 +230,12 @@ export class Zabbix implements ZabbixConnector {
|
|||||||
/**
|
/**
|
||||||
* Get list of applications belonging to given groups and hosts.
|
* Get list of applications belonging to given groups and hosts.
|
||||||
*/
|
*/
|
||||||
getAllApps(groupFilter, hostFilter) {
|
async getAllApps(groupFilter, hostFilter) {
|
||||||
|
await this.getVersion();
|
||||||
|
if (!this.supportsApplications()) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
return this.getHosts(groupFilter, hostFilter)
|
return this.getHosts(groupFilter, hostFilter)
|
||||||
.then(hosts => {
|
.then(hosts => {
|
||||||
const hostids = _.map(hosts, 'hostid');
|
const hostids = _.map(hosts, 'hostid');
|
||||||
@@ -226,11 +243,14 @@ export class Zabbix implements ZabbixConnector {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getApps(groupFilter?, hostFilter?, appFilter?): Promise<AppsResponse> {
|
async getApps(groupFilter?, hostFilter?, appFilter?): Promise<AppsResponse> {
|
||||||
|
await this.getVersion();
|
||||||
|
const skipAppFilter = !this.supportsApplications();
|
||||||
|
|
||||||
return this.getHosts(groupFilter, hostFilter)
|
return this.getHosts(groupFilter, hostFilter)
|
||||||
.then(hosts => {
|
.then(hosts => {
|
||||||
const hostids = _.map(hosts, 'hostid');
|
const hostids = _.map(hosts, 'hostid');
|
||||||
if (appFilter) {
|
if (appFilter && !skipAppFilter) {
|
||||||
return this.zabbixAPI.getApps(hostids)
|
return this.zabbixAPI.getApps(hostids)
|
||||||
.then(apps => filterByQuery(apps, appFilter));
|
.then(apps => filterByQuery(apps, appFilter));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user