diff --git a/src/datasource-zabbix/query.controller.js b/src/datasource-zabbix/query.controller.js index 98354e2..921da2f 100644 --- a/src/datasource-zabbix/query.controller.js +++ b/src/datasource-zabbix/query.controller.js @@ -14,6 +14,10 @@ export class ZabbixQueryController extends QueryCtrl { // Call superclass constructor super($scope, $injector); + this.zabbix = this.datasource.zabbixAPI; + this.cache = this.datasource.zabbixCache; + this.$q = $q; + this.editorModes = { 0: 'num', 1: 'itservice', @@ -22,9 +26,9 @@ export class ZabbixQueryController extends QueryCtrl { // Map functions for bs-typeahead this.getGroupNames = _.partial(getMetricNames, this, 'groupList'); - this.getHostNames = _.partial(getMetricNames, this, 'filteredHosts'); - this.getApplicationNames = _.partial(getMetricNames, this, 'filteredApplications'); - this.getItemNames = _.partial(getMetricNames, this, 'filteredItems'); + this.getHostNames = _.partial(getMetricNames, this, 'hostList'); + this.getApplicationNames = _.partial(getMetricNames, this, 'appList'); + this.getItemNames = _.partial(getMetricNames, this, 'itemList'); this.init = function() { @@ -32,7 +36,8 @@ export class ZabbixQueryController extends QueryCtrl { var target = this.target; var scopeDefaults = { - metric: {} + metric: {}, + oldTarget: _.cloneDeep(this.target) }; _.defaults(this, scopeDefaults); @@ -85,49 +90,86 @@ export class ZabbixQueryController extends QueryCtrl { } initFilters() { - this.filterGroups(); - this.filterHosts(); - this.filterApplications(); - this.filterItems(); + var self = this; + return this.$q.when(this.suggestGroups()) + .then(() => {return self.suggestHosts();}) + .then(() => {return self.suggestApps();}) + .then(() => {return self.suggestItems();}); } - filterHosts() { + suggestGroups() { var self = this; - var groupFilter = this.templateSrv.replace(this.target.group.filter); - this.datasource.queryProcessor.filterHosts(groupFilter).then(function(hosts) { - self.metric.filteredHosts = hosts; - }); - } - - filterGroups() { - var self = this; - this.datasource.queryProcessor.filterGroups().then(function(groups) { + return this.cache.getGroups().then(groups => { self.metric.groupList = groups; + return groups; }); } - filterApplications() { + suggestHosts() { var self = this; var groupFilter = this.templateSrv.replace(this.target.group.filter); - var hostFilter = this.templateSrv.replace(this.target.host.filter); - this.datasource.queryProcessor.filterApplications(groupFilter, hostFilter) - .then(function(apps) { - self.metric.filteredApplications = apps; + return this.datasource.queryProcessor + .filterGroups(self.metric.groupList, groupFilter) + .then(groups => { + var groupids = _.map(groups, 'groupid'); + return self.zabbix + .getHostsByGroups(groupids) + .then(hosts => { + self.metric.hostList = hosts; + return hosts; + }); }); } - filterItems() { + suggestApps() { var self = this; - var item_type = this.editorModes[this.target.mode]; - var groupFilter = this.templateSrv.replace(this.target.group.filter); var hostFilter = this.templateSrv.replace(this.target.host.filter); - var appFilter = this.templateSrv.replace(this.target.application.filter); - this.datasource.queryProcessor.filterItems(groupFilter, hostFilter, appFilter, - item_type, this.target.showDisabledItems).then(function(items) { - self.metric.filteredItems = items; + return this.datasource.queryProcessor + .filterHosts(self.metric.hostList, hostFilter) + .then(hosts => { + var hostids = _.map(hosts, 'hostid'); + return self.zabbix + .getApps(hostids) + .then(apps => { + return self.metric.appList = apps; + }); }); } + suggestItems() { + var self = this; + var appFilter = this.templateSrv.replace(this.target.application.filter); + if (appFilter) { + // Filter by applications + return this.datasource.queryProcessor + .filterApps(self.metric.appList, appFilter) + .then(apps => { + var appids = _.map(apps, 'applicationid'); + return self.zabbix + .getItems(undefined, appids) + .then(items => { + if (!self.target.showDisabledItems) { + items = _.filter(items, {'status': '0'}); + } + self.metric.itemList = items; + return items; + }); + }); + } else { + // Return all items belonged to selected hosts + var hostids = _.map(self.metric.hostList, 'hostid'); + return self.zabbix + .getItems(hostids) + .then(items => { + if (!self.target.showDisabledItems) { + items = _.filter(items, {'status': '0'}); + } + self.metric.itemList = items; + return items; + }); + } + } + onTargetPartChange(targetPart) { var regexStyle = {'color': '#CCA300'}; targetPart.isRegex = utils.isRegex(targetPart.filter); @@ -135,9 +177,13 @@ export class ZabbixQueryController extends QueryCtrl { } onTargetBlur() { - this.initFilters(); - this.parseTarget(); - this.panelCtrl.refresh(); + var newTarget = _.cloneDeep(this.target); + if (!_.isEqual(this.oldTarget, this.target)) { + this.oldTarget = newTarget; + this.initFilters(); + this.parseTarget(); + this.panelCtrl.refresh(); + } } parseTarget() { diff --git a/src/datasource-zabbix/queryProcessor.service.js b/src/datasource-zabbix/queryProcessor.service.js index d447e55..b229190 100644 --- a/src/datasource-zabbix/queryProcessor.service.js +++ b/src/datasource-zabbix/queryProcessor.service.js @@ -39,31 +39,26 @@ angular.module('grafana.services').factory('QueryProcessor', function($q) { } } - filterGroups(groupFilter) { - return this.cache.getGroups().then(function(groupList) { - return groupList; - }); + filterGroups(groups, groupFilter) { + return this.$q.when( + findByFilter(groups, groupFilter) + ); } /** * Get list of host belonging to given groups. * @return list of hosts */ - filterHosts(groupFilter) { - var self = this; - return this.cache.getGroups().then(function(groups) { - groups = findByFilter(groups, groupFilter); - var hostids = _.flatten(_.map(groups, 'hosts')); - if (hostids.length) { - return self.cache.getIndexedHosts().then(function(hosts) { - return _.map(hostids, function(hostid) { - return hosts[hostid]; - }); - }); - } else { - return []; - } - }); + filterHosts(hosts, hostFilter) { + return this.$q.when( + findByFilter(hosts, hostFilter) + ); + } + + filterApps(apps, appFilter) { + return this.$q.when( + findByFilter(apps, appFilter) + ); } /** @@ -151,10 +146,65 @@ angular.module('grafana.services').factory('QueryProcessor', function($q) { }); } + buildFromCache(groupFilter, hostFilter, appFilter, itemFilter, showDisabledItems) { + var self = this; + return this.cache + .getGroups() + .then(groups => { + return findByFilter(groups, groupFilter); + }) + .then(groups => { + var groupids = _.map(groups, 'groupid'); + return self.cache + .getHosts(groupids) + .then(hosts => { + return findByFilter(hosts, hostFilter); + }); + }) + .then(hosts => { + var hostids = _.map(hosts, 'hostid'); + if (appFilter) { + return self.cache + .getApps(hostids) + .then(apps => { + // Use getByFilter for proper item filtering + return getByFilter(apps, appFilter); + }); + } else { + return { + appFilterEmpty: true, + hostids: hostids + }; + } + }) + .then(apps => { + if (apps.appFilterEmpty) { + return self.cache + .getItems(apps.hostids) + .then(items => { + if (showDisabledItems) { + items = _.filter(items, {'status': '0'}); + } + return getByFilter(items, itemFilter); + }); + } else { + var appids = _.map(apps, 'applicationid'); + return self.cache + .getItems(undefined, appids) + .then(items => { + if (showDisabledItems) { + items = _.filter(items, {'status': '0'}); + } + return getByFilter(items, itemFilter); + }); + } + }); + } + /** * Build query - convert target filters to array of Zabbix items */ - buildFromCache(groupFilter, hostFilter, appFilter, itemFilter) { + _buildFromCache(groupFilter, hostFilter, appFilter, itemFilter) { return this.filterItems(groupFilter, hostFilter, appFilter).then(function(items) { if (items.length) { if (utils.isRegex(itemFilter)) { @@ -309,6 +359,23 @@ function findByName(list, name) { } } +/** + * Different hosts can contains applications and items with same name. + * For this reason use _.filter, which return all elements instead _.find, + * which return only first finded. + * @param {[type]} list list of elements + * @param {[type]} name app name + * @return {[type]} array with finded element or undefined + */ +function filterByName(list, name) { + var finded = _.filter(list, {'name': name}); + if (finded) { + return finded; + } else { + return undefined; + } +} + function findByRegex(list, regex) { var filterPattern = utils.buildRegex(regex); return _.filter(list, function (zbx_obj) { @@ -324,6 +391,14 @@ function findByFilter(list, filter) { } } +function getByFilter(list, filter) { + if (utils.isRegex(filter)) { + return findByRegex(list, filter); + } else { + return filterByName(list, filter); + } +} + function getFromIndex(index, objids) { return _.map(objids, function(id) { return index[id]; diff --git a/src/datasource-zabbix/zabbixAPI.service.js b/src/datasource-zabbix/zabbixAPI.service.js index 7661c0c..b3cf98b 100644 --- a/src/datasource-zabbix/zabbixAPI.service.js +++ b/src/datasource-zabbix/zabbixAPI.service.js @@ -1,5 +1,6 @@ import angular from 'angular'; import _ from 'lodash'; +import * as utils from './utils'; import './zabbixAPICore.service'; /** @ngInject */ @@ -116,24 +117,42 @@ function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) { getGroups() { var params = { output: ['name'], - sortfield: 'name', - selectHosts: [] + sortfield: 'name' }; return this.request('hostgroup.get', params); } - getHosts() { + getHosts(groupids) { var params = { output: ['name', 'host'], - sortfield: 'name', - selectGroups: [], - selectApplications: ['applicationid'] + sortfield: 'name' + }; + if (groupids) { + params.groupids = groupids; + } + + return this.request('host.get', params); + } + + getHostsByGroups(groupids) { + var params = { + output: ['name', 'host'], + groupids: groupids }; return this.request('host.get', params); } + getApps(hostids) { + var params = { + output: ['applicationid', 'name'], + hostids: hostids + }; + + return this.request('application.get', params); + } + getApplications() { var params = { output: ['applicationid', 'name'], @@ -147,7 +166,7 @@ function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) { return this.request('application.get', params); } - getItems() { + getItems(hostids, appids) { var params = { output: [ 'name', 'key_', @@ -157,10 +176,22 @@ function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) { 'state' ], sortfield: 'name', - selectApplications: [] }; + if (hostids) { + params.hostids = hostids; + } + if (appids) { + params.applicationids = appids; + } - return this.request('item.get', params); + return this.request('item.get', params) + .then(items => { + return _.forEach(items, item => { + item.item = item.name; + item.name = utils.expandItemName(item.item, item.key_); + return item; + }); + }); } /** diff --git a/src/datasource-zabbix/zabbixCache.service.js b/src/datasource-zabbix/zabbixCache.service.js index 65a00cf..ebac8e9 100644 --- a/src/datasource-zabbix/zabbixCache.service.js +++ b/src/datasource-zabbix/zabbixCache.service.js @@ -45,21 +45,12 @@ angular.module('grafana.services').factory('ZabbixCachingProxy', function($q, $i _refresh() { var self = this; var promises = [ - this.zabbixAPI.getGroups(), - this.zabbixAPI.getHosts(), - this.zabbixAPI.getApplications(), - this.zabbixAPI.getItems(), - this.zabbixAPI.getHostsExtend() + this.zabbixAPI.getGroups() ]; return this.$q.all(promises).then(function(results) { if (results.length) { - self._groups = convertGroups(results[0]); - self._hosts = convertHosts(results[1]); - self._applications = convertApplications(results[2]); - self._items = convertItems(results[3]); - self._idx_apps = indexApps(results[2]); - self._idx_hosts = indexHosts(results[4]); + self._groups = results[0]; } self._initialized = true; }); @@ -70,13 +61,44 @@ angular.module('grafana.services').factory('ZabbixCachingProxy', function($q, $i if (this._groups) { return this.$q.when(self._groups); } else { - return this.refresh().then(function() { - return self._groups; - }); + return this.zabbixAPI + .getGroups() + .then(groups => { + self._groups = groups; + return self._groups; + }); } } - getHosts() { + getApps(hostids) { + return this.zabbixAPI + .getApps(hostids) + .then(apps => { + return apps; + }); + } + + getHosts(groupids) { + var self = this; + return this.zabbixAPI + .getHosts(groupids) + .then(hosts => { + self._hosts = _.union(self._hosts, hosts); + return hosts; + }); + } + + getItems(hostids, appids) { + var self = this; + return this.zabbixAPI + .getItems(hostids, appids) + .then(items => { + self._items = _.union(self._items, items); + return items; + }); + } + + _getHosts() { var self = this; if (this._hosts) { return this.$q.when(self._hosts); @@ -120,7 +142,7 @@ angular.module('grafana.services').factory('ZabbixCachingProxy', function($q, $i } } - getItems(type) { + _getItems(type) { var self = this; if (this._items) { return this.$q.when(filterItems(self._items, type));