Skip to content

Commit 3410593

Browse files
Fix compatibility with Zabbix 5.4 (skip applications filter) (grafana#1214)
* Fix queries in Zabbix 5.4 (applications not supported) * Fix alerting queries in Zabbix 5.4
1 parent 29a8bde commit 3410593

File tree

6 files changed

+59
-13
lines changed

6 files changed

+59
-13
lines changed

pkg/datasource/zabbix.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,10 @@ func (ds *ZabbixDatasourceInstance) getItems(ctx context.Context, groupFilter st
167167
}
168168

169169
apps, err := ds.getApps(ctx, groupFilter, hostFilter, appFilter)
170-
if err != nil {
170+
// Apps not supported in Zabbix 5.4 and higher
171+
if isAppMethodNotFoundError(err) {
172+
apps = []map[string]interface{}{}
173+
} else if err != nil {
171174
return nil, err
172175
}
173176
var appids []string
@@ -505,3 +508,12 @@ func isNotAuthorized(err error) bool {
505508
strings.Contains(message, "Not authorised.") ||
506509
strings.Contains(message, "Not authorized.")
507510
}
511+
512+
func isAppMethodNotFoundError(err error) bool {
513+
if err == nil {
514+
return false
515+
}
516+
517+
message := err.Error()
518+
return message == `Method not found. Incorrect API "application".`
519+
}

src/datasource-zabbix/partials/query.editor.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
<label class="gf-form-label query-keyword width-7">Application</label>
123123
<input type="text"
124124
ng-model="ctrl.target.application.filter"
125+
ng-disabled="ctrl.appFilterDisabled()"
125126
bs-typeahead="ctrl.getApplicationNames"
126127
ng-blur="ctrl.onTargetBlur()"
127128
data-min-length=0

src/datasource-zabbix/query.controller.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,4 +512,8 @@ export class ZabbixQueryController extends QueryCtrl {
512512
this.init();
513513
this.targetChanged();
514514
}
515+
516+
appFilterDisabled() {
517+
return !this.zabbix.supportsApplications();
518+
}
515519
}

src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,14 @@ export class ZabbixAPIConnector {
4646
//////////////////////////
4747

4848
request(method: string, params?: any) {
49-
return this.backendAPIRequest(method, params).then(response => {
50-
return response?.data?.result;
51-
});
49+
if (!this.version) {
50+
return this.initVersion().then(() => this.request(method, params));
51+
}
52+
53+
return this.backendAPIRequest(method, params);
5254
}
5355

54-
backendAPIRequest(method: string, params: any = {}) {
56+
async backendAPIRequest(method: string, params: any = {}) {
5557
const requestOptions: BackendSrvRequest = {
5658
url: this.backendAPIUrl,
5759
method: 'POST',
@@ -74,14 +76,15 @@ export class ZabbixAPIConnector {
7476
requestOptions.headers.Authorization = this.requestOptions.basicAuth;
7577
}
7678

77-
return getBackendSrv().datasourceRequest(requestOptions);
79+
const response = await getBackendSrv().datasourceRequest(requestOptions);
80+
return response?.data?.result;
7881
}
7982

8083
/**
8184
* Get Zabbix API version
8285
*/
8386
getVersion() {
84-
return this.request('apiinfo.version');
87+
return this.backendAPIRequest('apiinfo.version');
8588
}
8689

8790
initVersion(): Promise<string> {
@@ -147,7 +150,11 @@ export class ZabbixAPIConnector {
147150
return this.request('host.get', params);
148151
}
149152

150-
getApps(hostids): Promise<any[]> {
153+
async getApps(hostids): Promise<any[]> {
154+
if (semver.gte(this.version, '5.4.0')) {
155+
return [];
156+
}
157+
151158
const params = {
152159
output: 'extend',
153160
hostids: hostids

src/datasource-zabbix/zabbix/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ export interface ZabbixConnector {
1919
getApps: (groupFilter?, hostFilter?, appFilter?) => any;
2020
getItems: (groupFilter?, hostFilter?, appFilter?, itemFilter?, options?) => any;
2121
getSLA: (itservices, timeRange, target, options?) => any;
22+
23+
supportsApplications: () => boolean;
2224
}

src/datasource-zabbix/zabbix/zabbix.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import _ from 'lodash';
22
import moment from 'moment';
3+
import semver from 'semver';
34
import * as utils from '../utils';
45
import responseHandler from '../responseHandler';
56
import { CachingProxy } from './proxy/cachingProxy';
@@ -29,7 +30,7 @@ const REQUESTS_TO_CACHE = [
2930

3031
const REQUESTS_TO_BIND = [
3132
'getHistory', 'getTrend', 'getMacros', 'getItemsByIDs', 'getEvents', 'getAlerts', 'getHostAlerts',
32-
'getAcknowledges', 'getITService', 'getVersion', 'acknowledgeEvent', 'getProxies', 'getEventAlerts',
33+
'getAcknowledges', 'getITService', 'acknowledgeEvent', 'getProxies', 'getEventAlerts',
3334
'getExtendedEventData', 'getScripts', 'executeScript', 'getValueMappings'
3435
];
3536

@@ -40,6 +41,7 @@ export class Zabbix implements ZabbixConnector {
4041
getHistoryDB: any;
4142
dbConnector: any;
4243
getTrendsDB: any;
44+
version: string;
4345

4446
getHistory: (items, timeFrom, timeTill) => Promise<any>;
4547
getTrend: (items, timeFrom, timeTill) => Promise<any>;
@@ -54,7 +56,6 @@ export class Zabbix implements ZabbixConnector {
5456
getEventAlerts: (eventids) => Promise<any>;
5557
getExtendedEventData: (eventids) => Promise<any>;
5658
getMacros: (hostids: any[]) => Promise<any>;
57-
getVersion: () => Promise<string>;
5859
getValueMappings: () => Promise<any>;
5960

6061
constructor(options) {
@@ -168,6 +169,17 @@ export class Zabbix implements ZabbixConnector {
168169
});
169170
}
170171

172+
async getVersion() {
173+
if (!this.version) {
174+
this.version = await this.zabbixAPI.initVersion();
175+
}
176+
return this.version;
177+
}
178+
179+
supportsApplications() {
180+
return this.version ? semver.lt(this.version, '5.4.0') : true;
181+
}
182+
171183
getItemsFromTarget(target, options) {
172184
const parts = ['group', 'host', 'application', 'item'];
173185
const filters = _.map(parts, p => target[p].filter);
@@ -218,19 +230,27 @@ export class Zabbix implements ZabbixConnector {
218230
/**
219231
* Get list of applications belonging to given groups and hosts.
220232
*/
221-
getAllApps(groupFilter, hostFilter) {
233+
async getAllApps(groupFilter, hostFilter) {
234+
await this.getVersion();
235+
if (!this.supportsApplications()) {
236+
return [];
237+
}
238+
222239
return this.getHosts(groupFilter, hostFilter)
223240
.then(hosts => {
224241
const hostids = _.map(hosts, 'hostid');
225242
return this.zabbixAPI.getApps(hostids);
226243
});
227244
}
228245

229-
getApps(groupFilter?, hostFilter?, appFilter?): Promise<AppsResponse> {
246+
async getApps(groupFilter?, hostFilter?, appFilter?): Promise<AppsResponse> {
247+
await this.getVersion();
248+
const skipAppFilter = !this.supportsApplications();
249+
230250
return this.getHosts(groupFilter, hostFilter)
231251
.then(hosts => {
232252
const hostids = _.map(hosts, 'hostid');
233-
if (appFilter) {
253+
if (appFilter && !skipAppFilter) {
234254
return this.zabbixAPI.getApps(hostids)
235255
.then(apps => filterByQuery(apps, appFilter));
236256
} else {

0 commit comments

Comments
 (0)