diff --git a/zabbix/datasource.js b/zabbix/datasource.js index 45c38b8..a7ab033 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -12,8 +12,8 @@ function (angular, _, kbn) { module.factory('ZabbixAPIDatasource', function($q, backendSrv, templateSrv) { function ZabbixAPIDatasource(datasource) { - this.name = datasource.name; this.type = 'zabbix'; + this.name = datasource.name; this.url = datasource.url; @@ -33,103 +33,72 @@ function (angular, _, kbn) { ZabbixAPIDatasource.prototype.query = function(options) { // get from & to in seconds - var from = kbn.parseDate(options.range.from).getTime(); - var to = kbn.parseDate(options.range.to).getTime(); + var from = Math.ceil(kbn.parseDate(options.range.from).getTime() / 1000); + var to = Math.ceil(kbn.parseDate(options.range.to).getTime() / 1000); - // Need for find target alias - var targets = options.targets; + // Create request for each target + var promises = _.map(options.targets, function(target) { - // Remove undefined and hidden targets - var displayedTargets = _.filter(targets, function (target) { - return (!target.hide && target.item); - }); + // Remove undefined and hidden targets + if (target.hide || !target.item) { + return []; + } - if (displayedTargets.length) { - // Extract zabbix api item objects from targets - var target_items = _.map(displayedTargets, 'item'); - } else { - // No valid targets, return the empty dataset - var d = $q.defer(); - d.resolve({ data: [] }); - return d.promise; - } + // Perform request and then handle result + return this.performTimeSeriesQuery(target.item, from, to).then(_.partial( + this.handleZabbixAPIResponse, target)); + }, this); - from = Math.ceil(from/1000); - to = Math.ceil(to/1000); - - return this.performTimeSeriesQuery(target_items, from, to).then(function (response) { - /** - * Response should be in the format: - * data: [ - * { - * target: "Metric name", - * datapoints: [[, ], ...] - * }, - * { - * target: "Metric name", - * datapoints: [[, ], ...] - * }, - * ] - */ - - // Index returned datapoints by item/metric id - var indexed_result = _.groupBy(response, 'itemid'); - - // TODO: realize correct timeseries reduce - /* - // Reduce timeseries to the same size for stacking and tooltip work properly - var min_length = _.min(_.map(indexed_result, function (history) { - return history.length; - })); - _.each(indexed_result, function (item) { - item.splice(0, item.length - min_length); - });*/ - - // Sort result as the same as targets for display - // stacked timeseries in proper order - var sorted_history = _.sortBy(indexed_result, function (value, key, list) { - return _.indexOf(_.map(target_items, 'itemid'), key); - }); - - var series = _.map(sorted_history, - // Foreach itemid index: iterate over the data points and - // normalize to Grafana response format. - function (history, index) { - return { - // Lookup itemid:alias map - //target: targets[itemid].alias, - target: targets[index].alias, - - datapoints: _.map(history, function (p) { - - // Value must be a number for properly work - var value = Number(p.value); - - // TODO: Correct time for proper stacking - //var clock = Math.round(Number(p.clock) / 60) * 60; - return [value, p.clock * 1000]; - }) - }; - }) - return $q.when({data: series}); + return $q.all(promises).then(function(results) { + return { data: _.flatten(results) }; }); }; - /////////////////////////////////////////////////////////////////////// - /// Query methods - /////////////////////////////////////////////////////////////////////// + // Request data from Zabbix API + ZabbixAPIDatasource.prototype.handleZabbixAPIResponse = function(target, response) { + /** + * Response should be in the format: + * data: [ + * { + * target: "Metric name", + * datapoints: [[, ], ...] + * }, + * { + * target: "Metric name", + * datapoints: [[, ], ...] + * }, + * ] + */ + + var series = { + target: target.alias, + datapoints: _.map(response, function (p) { + // Value must be a number for properly work + var value = Number(p.value); + return [value, p.clock * 1000]; + }) + }; + + return $q.when(series); + }; // Request data from Zabbix API - ZabbixAPIDatasource.prototype.performZabbixAPIRequest = function(request_data) { + ZabbixAPIDatasource.prototype.performZabbixAPIRequest = function(method, params) { var options = { method: 'POST', headers: { 'Content-Type': 'application/json' }, url: this.url, - data: request_data + data: { + jsonrpc: '2.0', + method: method, + params: params, + auth: this.auth, + id: 1 + } }; var performedQuery; @@ -162,68 +131,22 @@ function (angular, _, kbn) { * @param items: array of zabbix api item objects */ ZabbixAPIDatasource.prototype.performTimeSeriesQuery = function(items, start, end) { + var params = { + output: 'extend', + history: items.value_type, + itemids: items.itemid, + sortfield: 'clock', + sortorder: 'ASC', + limit: this.limitmetrics, + time_from: start, + }; - // Group items by value type for separate requests - var items_by_value_type = _.groupBy(items, 'value_type'); + // Relative queries (e.g. last hour) don't include an end time + if (end) { + params.time_till = end; + } - var self = this; - var apiRequests = []; - - // Prepare requests for each value type - _.each(items_by_value_type, function (value, key, list) { - var item_ids = _.map(value, 'itemid'); - var history_type = key; - var data = { - jsonrpc: '2.0', - method: 'history.get', - params: { - output: 'extend', - history: history_type, - itemids: item_ids, - sortfield: 'clock', - sortorder: 'ASC', - limit: self.limitmetrics, - time_from: start, - }, - auth: self.auth, - id: 1 - }; - - // Relative queries (e.g. last hour) don't include an end time - if (end) { - data.params.time_till = end; - } - - apiRequests.push(self.performZabbixAPIRequest(data)); - }); - - return this.handleMultipleRequest(apiRequests); - }; - - - // Handle multiple request - ZabbixAPIDatasource.prototype.handleMultipleRequest = function(apiRequests) { - var history = []; - var performedQuery = null; - - // Build chain of api requests and put all history data into single array - _.each(apiRequests, function (apiRequest) { - if(!performedQuery) { - performedQuery = apiRequest.then(function (response) { - history = history.concat(response); - return history; - }); - } else { - performedQuery = performedQuery.then(function () { - return apiRequest.then(function (response) { - history = history.concat(response); - return history; - }); - }); - } - }); - - return performedQuery; + return this.performZabbixAPIRequest('history.get', params); }; @@ -255,83 +178,62 @@ function (angular, _, kbn) { // Get the list of host groups ZabbixAPIDatasource.prototype.performHostGroupSuggestQuery = function() { - var data = { - jsonrpc: '2.0', - method: 'hostgroup.get', - params: { - output: ['name'], - real_hosts: true, //Return only host groups that contain hosts - sortfield: 'name' - }, - auth: this.auth, - id: 1 + var params = { + output: ['name'], + real_hosts: true, //Return only host groups that contain hosts + sortfield: 'name' }; - return this.performZabbixAPIRequest(data); + return this.performZabbixAPIRequest('hostgroup.get', params); }; // Get the list of hosts ZabbixAPIDatasource.prototype.performHostSuggestQuery = function(groupid) { - var data = { - jsonrpc: '2.0', - method: 'host.get', - params: { - output: ['name'], - sortfield: 'name' - }, - auth: this.auth, - id: 1 + var params = { + output: ['name'], + sortfield: 'name' }; + // Return only hosts in given group if (groupid) { - data.params.groupids = groupid; + params.groupids = groupid; } - - return this.performZabbixAPIRequest(data); + return this.performZabbixAPIRequest('host.get', params); }; // Get the list of applications ZabbixAPIDatasource.prototype.performAppSuggestQuery = function(hostid) { - var data = { - jsonrpc: '2.0', - method: 'application.get', - params: { - output: ['name'], - sortfield: 'name', - hostids: hostid - }, - auth: this.auth, - id: 1 + var params = { + output: ['name'], + sortfield: 'name', + hostids: hostid }; - return this.performZabbixAPIRequest(data); + return this.performZabbixAPIRequest('application.get', params); }; // Get the list of host items ZabbixAPIDatasource.prototype.performItemSuggestQuery = function(hostid, applicationid) { - var data = { - jsonrpc: '2.0', - method: 'item.get', - params: { - output: ['name', 'key_', 'value_type', 'delay'], - sortfield: 'name', - hostids: hostid, - webitems: true, //Include web items in the result - filter: { - value_type: [0,3] - } - }, - auth: this.auth, - id: 1 + var params = { + output: ['name', 'key_', 'value_type', 'delay'], + sortfield: 'name', + hostids: hostid, + + //Include web items in the result + webitems: true, + // Return only numeric items + filter: { + value_type: [0,3] + } }; // If application selected return only relative items if (applicationid) { - data.params.applicationids = applicationid; + params.applicationids = applicationid; } - return this.performZabbixAPIRequest(data); + return this.performZabbixAPIRequest('item.get', params); }; diff --git a/zabbix/partials/config.html b/zabbix/partials/config.html index 7dbe967..81f0e44 100644 --- a/zabbix/partials/config.html +++ b/zabbix/partials/config.html @@ -10,13 +10,13 @@ User
  • - +
  • Password
  • - +