diff --git a/zabbix/datasource.js b/zabbix/datasource.js index e77b35e68..0afa5623f 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -72,6 +72,12 @@ function (angular, _, kbn) { }; } }); + }, function(error) { + return { + status: "error", + title: "Connection failed", + message: "Could not connect to " + error.config.url + }; }); }; @@ -94,107 +100,153 @@ function (angular, _, kbn) { // Create request for each target var promises = _.map(options.targets, function(target) { - // Don't show undefined and hidden targets - if (target.hide || !target.group || !target.host - || !target.application || !target.item) { - return []; - } + if (target.mode !== 1) { + // Don't show undefined and hidden targets + if (target.hide || !target.group || !target.host + || !target.application || !target.item) { + return []; + } - // Replace templated variables - var groupname = templateSrv.replace(target.group.name); - var hostname = templateSrv.replace(target.host.name); - var appname = templateSrv.replace(target.application.name); - var itemname = templateSrv.replace(target.item.name); - - // Extract zabbix groups, hosts and apps from string: - // "{host1,host2,...,hostN}" --> [host1, host2, ..., hostN] - var groups = zabbixHelperSrv.splitMetrics(groupname); - var hosts = zabbixHelperSrv.splitMetrics(hostname); - var apps = zabbixHelperSrv.splitMetrics(appname); - - // Remove hostnames from item names and then - // extract item names - // "hostname: itemname" --> "itemname" - var delete_hostname_pattern = /(?:\[[\w\.]+\]\:\s)/g; - var itemnames = zabbixHelperSrv.splitMetrics(itemname.replace(delete_hostname_pattern, '')); - - // Find items by item names and perform queries - var self = this; - return this.zabbixAPI.itemFindQuery(groups, hosts, apps) - .then(function (items) { - - // Filter hosts by regex - if (target.host.visible_name === 'All') { - if (target.hostFilter && _.every(items, _.identity.hosts)) { - - // Use templated variables in filter - var host_pattern = new RegExp(templateSrv.replace(target.hostFilter)); - items = _.filter(items, function (item) { - return _.some(item.hosts, function (host) { - return host_pattern.test(host.name); + // Replace templated variables + var groupname = templateSrv.replace(target.group.name, options.scopedVars); + var hostname = templateSrv.replace(target.host.name, options.scopedVars); + var appname = templateSrv.replace(target.application.name, options.scopedVars); + var itemname = templateSrv.replace(target.item.name, options.scopedVars); + + // Extract zabbix groups, hosts and apps from string: + // "{host1,host2,...,hostN}" --> [host1, host2, ..., hostN] + var groups = zabbixHelperSrv.splitMetrics(groupname); + var hosts = zabbixHelperSrv.splitMetrics(hostname); + var apps = zabbixHelperSrv.splitMetrics(appname); + + // Remove hostnames from item names and then + // extract item names + // "hostname: itemname" --> "itemname" + var delete_hostname_pattern = /(?:\[[\w\.]+]:\s)/g; + var itemnames = zabbixHelperSrv.splitMetrics(itemname.replace(delete_hostname_pattern, '')); + + var self = this; + + // Query numeric data + if (!target.mode) { + + // Find items by item names and perform queries + return this.zabbixAPI.itemFindQuery(groups, hosts, apps) + .then(function (items) { + + // Filter hosts by regex + if (target.host.visible_name === 'All') { + if (target.hostFilter && _.every(items, _.identity.hosts)) { + + // Use templated variables in filter + var host_pattern = new RegExp(templateSrv.replace(target.hostFilter, options.scopedVars)); + items = _.filter(items, function (item) { + return _.some(item.hosts, function (host) { + return host_pattern.test(host.name); + }); + }); + } + } + + if (itemnames[0] === 'All') { + + // Filter items by regex + if (target.itemFilter) { + + // Use templated variables in filter + var item_pattern = new RegExp(templateSrv.replace(target.itemFilter, options.scopedVars)); + return _.filter(items, function (item) { + return item_pattern.test(zabbixHelperSrv.expandItemName(item)); + }); + } else { + return items; + } + } else { + + // Filtering items + return _.filter(items, function (item) { + return _.contains(itemnames, zabbixHelperSrv.expandItemName(item)); }); - }); - } - } - - if (itemnames[0] === 'All') { + } + }).then(function (items) { + + // Don't perform query for high number of items + // to prevent Grafana slowdown + if (items.length > self.limitmetrics) { + var message = "Try to increase limitmetrics parameter in datasource config.
" + + "Current limitmetrics value is " + self.limitmetrics; + alertSrv.set("Metrics limit exceeded", message, "warning", 10000); + return []; + } else { + items = _.flatten(items); + + // Use alias only for single metric, otherwise use item names + var alias = target.item.name === 'All' || itemnames.length > 1 ? + undefined : templateSrv.replace(target.alias, options.scopedVars); + + var history; + if ((from < useTrendsFrom) && self.trends) { + var points = target.downsampleFunction ? target.downsampleFunction.value : "avg"; + history = self.zabbixAPI.getTrends(items, from, to) + .then(_.bind(zabbixHelperSrv.handleTrendResponse, zabbixHelperSrv, items, alias, target.scale, points)); + } else { + history = self.zabbixAPI.getHistory(items, from, to) + .then(_.bind(zabbixHelperSrv.handleHistoryResponse, zabbixHelperSrv, items, alias, target.scale)); + } + + return history.then(function (timeseries) { + var timeseries_data = _.flatten(timeseries); + return _.map(timeseries_data, function (timeseries) { + + // Series downsampling + if (timeseries.datapoints.length > options.maxDataPoints) { + var ms_interval = Math.floor((to - from) / options.maxDataPoints) * 1000; + var downsampleFunc = target.downsampleFunction ? target.downsampleFunction.value : "avg"; + timeseries.datapoints = zabbixHelperSrv.downsampleSeries(timeseries.datapoints, to, ms_interval, downsampleFunc); + } + return timeseries; + }); + }); + } + }); + } - // Filter items by regex - if (target.itemFilter) { + // Query text data + else if (target.mode === 2) { - // Use templated variables in filter - var item_pattern = new RegExp(templateSrv.replace(target.itemFilter)); - return _.filter(items, function (item) { - return item_pattern.test(zabbixHelperSrv.expandItemName(item)); + // Find items by item names and perform queries + return this.zabbixAPI.itemFindQuery(groups, hosts, apps, "text") + .then(function (items) { + items = _.filter(items, function (item) { + return _.contains(itemnames, zabbixHelperSrv.expandItemName(item)); + }); + return self.zabbixAPI.getHistory(items, from, to).then(function(history) { + return { + target: target.item.name, + datapoints: _.map(history, function (p) { + return [p.value, p.clock * 1000]; + }) + }; }); - } else { - return items; - } - } else { - - // Filtering items - return _.filter(items, function (item) { - return _.contains(itemnames, zabbixHelperSrv.expandItemName(item)); }); - } - }).then(function (items) { - - // Don't perform query for high number of items - // to prevent Grafana slowdown - if (items.length > self.limitmetrics) { - var message = "Try to increase limitmetrics parameter in datasource config.
" - + "Current limitmetrics value is " + self.limitmetrics; - alertSrv.set("Metrics limit exceeded", message, "warning", 10000); - return []; - } else { - items = _.flatten(items); - - // Use alias only for single metric, otherwise use item names - var alias = target.item.name === 'All' || itemnames.length > 1 ? undefined : templateSrv.replace(target.alias); - - if ((from < useTrendsFrom) && self.trends) { - return self.zabbixAPI.getTrends(items, from, to) - .then(_.bind(zabbixHelperSrv.handleTrendResponse, zabbixHelperSrv, items, alias, target.scale)); - } else { - return self.zabbixAPI.getHistory(items, from, to) - .then(_.bind(zabbixHelperSrv.handleHistoryResponse, zabbixHelperSrv, items, alias, target.scale)); - } - } - }); + } + } + + // IT services mode + else if (target.mode === 1) { + // Don't show undefined and hidden targets + if (target.hide || !target.itservice || !target.slaProperty) { + return []; + } else { + return this.zabbixAPI.getSLA(target.itservice.serviceid, from, to) + .then(_.bind(zabbixHelperSrv.handleSLAResponse, zabbixHelperSrv, target.itservice, target.slaProperty)); + } + } }, this); return $q.all(_.flatten(promises)).then(function (results) { var timeseries_data = _.flatten(results); - var data = _.map(timeseries_data, function (timeseries) { - - // Series downsampling - if (timeseries.datapoints.length > options.maxDataPoints) { - var ms_interval = Math.floor((to - from) / options.maxDataPoints) * 1000; - timeseries.datapoints = zabbixHelperSrv.downsampleSeries(timeseries.datapoints, to, ms_interval); - } - return timeseries; - }); - return { data: data }; + return { data: timeseries_data }; }); }; @@ -291,11 +343,17 @@ function (angular, _, kbn) { var params = { output: ['triggerid', 'description'], search: { - 'description': annotation.query + 'description': annotation.trigger }, searchWildcardsEnabled: true, expandDescription: true }; + if (annotation.host) { + params.host = templateSrv.replace(annotation.host); + } + else if (annotation.group) { + params.group = templateSrv.replace(annotation.group); + } return this.zabbixAPI.performZabbixAPIRequest('trigger.get', params) .then(function (result) { @@ -323,7 +381,7 @@ function (angular, _, kbn) { annotation: annotation, time: e.clock * 1000, title: Number(e.value) ? 'Problem' : 'OK', - text: objects[e.objectid].description + formatted_acknowledges, + text: objects[e.objectid].description + formatted_acknowledges }); }); return events; diff --git a/zabbix/helperFunctions.js b/zabbix/helperFunctions.js index 34bb84e25..f59a4708a 100644 --- a/zabbix/helperFunctions.js +++ b/zabbix/helperFunctions.js @@ -14,6 +14,8 @@ function (angular, _) { * Convert Zabbix API history.get response to Grafana format * * @param {Array} items Array of Zabbix Items + * @param alias + * @param scale * @param {Array} history Array of Zabbix History * * @return {Array} Array of timeseries in Grafana format @@ -44,7 +46,7 @@ function (angular, _) { var self = this; return $q.when(_.map(grouped_history, function (history, itemid) { var item = indexed_items[itemid]; - var series = { + return { target: (item.hosts ? item.hosts[0].name+': ' : '') + (alias ? alias : self.expandItemName(item)), datapoints: _.map(history, function (p) { @@ -59,7 +61,6 @@ function (angular, _) { return [value, p.clock * 1000]; }) }; - return series; })).then(function (result) { return _.sortBy(result, 'target'); }); @@ -69,6 +70,9 @@ function (angular, _) { * Convert Zabbix API trends.get response to Grafana format * * @param {Array} items Array of Zabbix Items + * @param alias + * @param scale + * @param {string} points Point value to return: min, max or avg * @param {Array} trends Array of Zabbix Trends * * @return {Array} Array of timeseries in Grafana format @@ -77,7 +81,7 @@ function (angular, _) { * datapoints: [[, ], ...] * } */ - this.handleTrendResponse = function (items, alias, scale, trends) { + this.handleTrendResponse = function (items, alias, scale, points, trends) { // Group items and trends by itemid var indexed_items = _.indexBy(items, 'itemid'); @@ -86,13 +90,22 @@ function (angular, _) { var self = this; return $q.when(_.map(grouped_trends, function (trends, itemid) { var item = indexed_items[itemid]; - var series = { + return { target: (item.hosts ? item.hosts[0].name+': ' : '') + (alias ? alias : self.expandItemName(item)), datapoints: _.map(trends, function (p) { // Value must be a number for properly work - var value = Number(p.value_avg); + var value; + if (points === "min") { + value = Number(p.value_min); + } + else if (points === "max") { + value = Number(p.value_max); + } + else { + value = Number(p.value_avg); + } // Apply scale if (scale) { @@ -101,18 +114,46 @@ function (angular, _) { return [value, p.clock * 1000]; }) }; - return series; })).then(function (result) { return _.sortBy(result, 'target'); }); }; + /** + * Convert Zabbix API service.getsla response to Grafana format + * + * @param itservice + * @param slaProperty + * @param slaObject + * @returns {{target: *, datapoints: *[]}} + */ + this.handleSLAResponse = function (itservice, slaProperty, slaObject) { + var targetSLA = slaObject[itservice.serviceid].sla[0]; + if (slaProperty.property === 'status') { + var targetStatus = slaObject[itservice.serviceid].status; + return { + target: itservice.name + ' ' + slaProperty.name, + datapoints: [ + [targetStatus, targetSLA.to * 1000] + ] + }; + } else { + return { + target: itservice.name + ' ' + slaProperty.name, + datapoints: [ + [targetSLA[slaProperty.property], targetSLA.from * 1000], + [targetSLA[slaProperty.property], targetSLA.to * 1000] + ] + }; + } + }; + /** * Expand item parameters, for example: * CPU $2 time ($3) --> CPU system time (avg1) * * @param item: zabbix api item object - * @return: expanded item name (string) + * @return {string} expanded item name (string) */ this.expandItemName = function(item) { var name = item.name; @@ -185,12 +226,13 @@ function (angular, _) { /** * Downsample datapoints series * - * @param {array} datapoints [[, ], ...] + * @param {Object[]} datapoints [[, ], ...] * @param {integer} time_to Panel time to * @param {integer} ms_interval Interval in milliseconds for grouping datapoints - * @return {array} [[, ], ...] + * @param {string} func Value to return: min, max or avg + * @return {Object[]} [[, ], ...] */ - this.downsampleSeries = function(datapoints, time_to, ms_interval) { + this.downsampleSeries = function(datapoints, time_to, ms_interval, func) { var downsampledSeries = []; var timeWindow = { from: time_to * 1000 - ms_interval, @@ -200,14 +242,28 @@ function (angular, _) { var points_sum = 0; var points_num = 0; var value_avg = 0; + var frame = []; + for (var i = datapoints.length - 1; i >= 0; i -= 1) { if (timeWindow.from < datapoints[i][1] && datapoints[i][1] <= timeWindow.to) { points_sum += datapoints[i][0]; points_num++; + frame.push(datapoints[i][0]); } else { value_avg = points_num ? points_sum / points_num : 0; - downsampledSeries.push([value_avg, timeWindow.to]); + + if (func === "max") { + downsampledSeries.push([_.max(frame), timeWindow.to]); + } + else if (func === "min") { + downsampledSeries.push([_.min(frame), timeWindow.to]); + } + + // avg by default + else { + downsampledSeries.push([value_avg, timeWindow.to]); + } // Shift time window timeWindow.to = timeWindow.from; @@ -215,6 +271,7 @@ function (angular, _) { points_sum = 0; points_num = 0; + frame = []; // Process point again i++; diff --git a/zabbix/partials/annotations.editor.html b/zabbix/partials/annotations.editor.html index 1dcfe6f07..1a95b3651 100644 --- a/zabbix/partials/annotations.editor.html +++ b/zabbix/partials/annotations.editor.html @@ -1,16 +1,36 @@
-
-
Zabbix trigger Example: Lack of free swap space
-
- -
-
+
+
Zabbix trigger +
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
Options
- - + +
diff --git a/zabbix/partials/config.html b/zabbix/partials/config.html index de325613a..a0a7f5074 100644 --- a/zabbix/partials/config.html +++ b/zabbix/partials/config.html @@ -10,13 +10,17 @@
Zabbix API details
User
  • - +
  • Password
  • - +
  • @@ -28,14 +32,18 @@
    Zabbix API details
  • Enable  - +
  • Use trends from
  • - +
  • @@ -46,7 +54,9 @@
    Zabbix API details
    Metrics limit
  • - +
  • diff --git a/zabbix/partials/query.editor.html b/zabbix/partials/query.editor.html index 6fc6627e6..26e2ea5f2 100644 --- a/zabbix/partials/query.editor.html +++ b/zabbix/partials/query.editor.html @@ -1,21 +1,35 @@
    -
    +
    • -
      +
      +
      @@ -186,13 +244,13 @@
    • + class="input-mini tight-form-input" + ng-model="panel.maxDataPoints" + bs-tooltip="'Override max data points, automatically set to graph width in pixels.'" + data-placement="right" + ng-model-onblur ng-change="get_data()" + spellcheck='false' + placeholder="auto">
    @@ -204,7 +262,17 @@
  • - max data points + Max data points + +
  • +
  • + + IT services + +
  • +
  • + + IT service property
  • @@ -218,7 +286,9 @@
    Max data points
      -
    • Grafana-Zabbix plugin uses maxDataPoints parameter to consolidate the real number of values down to this number
    • +
    • Grafana-Zabbix plugin uses maxDataPoints parameter to consolidate the real number of values down to this + number +
    • If there are more real values, then by default they will be consolidated using averages
    • This could hide real peaks and max values in your series
    • Point consolidation will effect series legend values (min,max,total,current)
    • @@ -226,5 +296,23 @@
      Max data points
    +
    +
    IT services
    +

    + Select "IT services" in targets menu to activate IT services mode. +

    +
    + +
    +
    IT service property
    +
      +
    • Zabbix returns the following availability information about IT service
    • +
    • Status - current status of the IT service
    • +
    • SLA - SLA for the given time interval
    • +
    • OK time - time the service was in OK state, in seconds
    • +
    • Problem time - time the service was in problem state, in seconds
    • +
    • Down time - time the service was in scheduled downtime, in seconds
    • +
    +
    \ No newline at end of file diff --git a/zabbix/queryCtrl.js b/zabbix/queryCtrl.js index 0a02a5893..92e676a3f 100644 --- a/zabbix/queryCtrl.js +++ b/zabbix/queryCtrl.js @@ -1,212 +1,271 @@ define([ - 'angular', - 'lodash', - './helperFunctions' -], -function (angular, _) { - 'use strict'; - - var module = angular.module('grafana.controllers'); - var targetLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - - module.controller('ZabbixAPIQueryCtrl', function($scope, $sce, templateSrv, zabbixHelperSrv) { - - $scope.init = function() { - $scope.targetLetters = targetLetters; - $scope.metric = { - hostGroupList: [], - hostList: [{name: '*', visible_name: 'All'}], - applicationList: [{name: '*', visible_name: 'All'}], - itemList: [{name: 'All'}] - }; + 'angular', + 'lodash', + './helperFunctions' + ], + function (angular, _) { + 'use strict'; - // Update host group, host, application and item lists - $scope.updateGroupList(); - $scope.updateHostList(); - $scope.updateAppList(); - $scope.updateItemList(); + var module = angular.module('grafana.controllers'); + var targetLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - setItemAlias(); + module.controller('ZabbixAPIQueryCtrl', function ($scope, $sce, templateSrv, zabbixHelperSrv) { - $scope.target.errors = validateTarget($scope.target); - }; + $scope.init = function () { + $scope.targetLetters = targetLetters; + if (!$scope.target.mode || $scope.target.mode !== 1) { + $scope.downsampleFunctionList = [ + {name: "avg", value: "avg"}, + {name: "min", value: "min"}, + {name: "max", value: "max"} + ]; - /** - * Take alias from item name by default - */ - function setItemAlias() { - if (!$scope.target.alias && $scope.target.item) { - $scope.target.alias = $scope.target.item.name; - } - } - - $scope.targetBlur = function() { - setItemAlias(); - $scope.target.errors = validateTarget($scope.target); - if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { - $scope.oldTarget = angular.copy($scope.target); - $scope.get_data(); - } - }; - - /** - * Call when host group selected - */ - $scope.selectHostGroup = function() { - $scope.updateHostList(); - $scope.updateAppList(); - $scope.updateItemList(); - - $scope.target.errors = validateTarget($scope.target); - if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { - $scope.oldTarget = angular.copy($scope.target); - $scope.get_data(); - } - }; - - /** - * Call when host selected - */ - $scope.selectHost = function() { - $scope.updateAppList(); - $scope.updateItemList(); - - $scope.target.errors = validateTarget($scope.target); - if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { - $scope.oldTarget = angular.copy($scope.target); - $scope.get_data(); - } - }; - - /** - * Call when application selected - */ - $scope.selectApplication = function() { - $scope.updateItemList(); - - $scope.target.errors = validateTarget($scope.target); - if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { - $scope.oldTarget = angular.copy($scope.target); - $scope.get_data(); - } - }; - - /** - * Call when item selected - */ - $scope.selectItem = function() { - setItemAlias(); - $scope.target.errors = validateTarget($scope.target); - if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { - $scope.oldTarget = angular.copy($scope.target); - $scope.get_data(); + // Set avg by default + if (!$scope.target.downsampleFunction) { + $scope.target.downsampleFunction = $scope.downsampleFunctionList[0]; + } + if (!$scope.metric) { + $scope.metric = { + hostGroupList: [], + hostList: [{name: '*', visible_name: 'All'}], + applicationList: [{name: '*', visible_name: 'All'}], + itemList: [{name: 'All'}] + }; + } + + // Update host group, host, application and item lists + $scope.updateGroupList(); + $scope.updateHostList(); + $scope.updateAppList(); + $scope.updateItemList(); + + setItemAlias(); + } + else if ($scope.target.mode === 1) { + $scope.slaPropertyList = [ + {name: "Status", property: "status"}, + {name: "SLA", property: "sla"}, + {name: "OK time", property: "okTime"}, + {name: "Problem time", property: "problemTime"}, + {name: "Down time", property: "downtimeTime"} + ]; + $scope.itserviceList = [{name: "test"}]; + $scope.updateITServiceList(); + } + + $scope.target.errors = validateTarget($scope.target); + }; + + /** + * Switch query editor to specified mode. + * Modes: + * 0 - items + * 1 - IT services + */ + $scope.switchEditorMode = function (mode) { + $scope.target.mode = mode; + $scope.init(); + }; + + /** + * Take alias from item name by default + */ + function setItemAlias() { + if (!$scope.target.alias && $scope.target.item) { + $scope.target.alias = $scope.target.item.name; + } } - }; - - $scope.duplicate = function() { - var clone = angular.copy($scope.target); - $scope.panel.targets.push(clone); - }; - - $scope.moveMetricQuery = function(fromIndex, toIndex) { - _.move($scope.panel.targets, fromIndex, toIndex); - }; - - ////////////////////////////// - // SUGGESTION QUERIES - ////////////////////////////// - - /** - * Update list of host groups - */ - $scope.updateGroupList = function() { - $scope.datasource.zabbixAPI.performHostGroupSuggestQuery().then(function (groups) { - $scope.metric.groupList = [{name: '*', visible_name: 'All'}]; - addTemplatedVariables($scope.metric.groupList); - $scope.metric.groupList = $scope.metric.groupList.concat(groups); - }); - }; - - /** - * Update list of hosts - */ - $scope.updateHostList = function() { - var groups = $scope.target.group ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; - if (groups) { - $scope.datasource.zabbixAPI.hostFindQuery(groups).then(function (hosts) { - $scope.metric.hostList = [{name: '*', visible_name: 'All'}]; - addTemplatedVariables($scope.metric.hostList); - $scope.metric.hostList = $scope.metric.hostList.concat(hosts); + + $scope.targetBlur = function () { + setItemAlias(); + $scope.target.errors = validateTarget($scope.target); + if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { + $scope.oldTarget = angular.copy($scope.target); + $scope.get_data(); + } + }; + + /** + * Call when IT service is selected. + */ + $scope.selectITService = function () { + $scope.target.errors = validateTarget($scope.target); + if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { + $scope.oldTarget = angular.copy($scope.target); + $scope.get_data(); + } + }; + + /** + * Call when host group selected + */ + $scope.selectHostGroup = function () { + $scope.updateHostList(); + $scope.updateAppList(); + $scope.updateItemList(); + + $scope.target.errors = validateTarget($scope.target); + if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { + $scope.oldTarget = angular.copy($scope.target); + $scope.get_data(); + } + }; + + /** + * Call when host selected + */ + $scope.selectHost = function () { + $scope.updateAppList(); + $scope.updateItemList(); + + $scope.target.errors = validateTarget($scope.target); + if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { + $scope.oldTarget = angular.copy($scope.target); + $scope.get_data(); + } + }; + + /** + * Call when application selected + */ + $scope.selectApplication = function () { + $scope.updateItemList(); + + $scope.target.errors = validateTarget($scope.target); + if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { + $scope.oldTarget = angular.copy($scope.target); + $scope.get_data(); + } + }; + + /** + * Call when item selected + */ + $scope.selectItem = function () { + setItemAlias(); + $scope.target.errors = validateTarget($scope.target); + if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { + $scope.oldTarget = angular.copy($scope.target); + $scope.get_data(); + } + }; + + $scope.duplicate = function () { + var clone = angular.copy($scope.target); + $scope.panel.targets.push(clone); + }; + + $scope.moveMetricQuery = function (fromIndex, toIndex) { + _.move($scope.panel.targets, fromIndex, toIndex); + }; + + ////////////////////////////// + // SUGGESTION QUERIES + ////////////////////////////// + + /** + * Update list of IT services + */ + $scope.updateITServiceList = function () { + $scope.datasource.zabbixAPI.getITService().then(function (iteservices) { + $scope.itserviceList = []; + $scope.itserviceList = $scope.itserviceList.concat(iteservices); }); - } - }; - - /** - * Update list of host applications - */ - $scope.updateAppList = function() { - var groups = $scope.target.group ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; - var hosts = $scope.target.host ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.host.name)) : undefined; - if (groups && hosts) { - $scope.datasource.zabbixAPI.appFindQuery(hosts, groups).then(function (apps) { - apps = _.map(_.uniq(_.map(apps, 'name')), function (appname) { - return {name: appname}; - }); - $scope.metric.applicationList = [{name: '*', visible_name: 'All'}]; - addTemplatedVariables($scope.metric.applicationList); - $scope.metric.applicationList = $scope.metric.applicationList.concat(apps); + }; + + /** + * Update list of host groups + */ + $scope.updateGroupList = function () { + $scope.datasource.zabbixAPI.performHostGroupSuggestQuery().then(function (groups) { + $scope.metric.groupList = [{name: '*', visible_name: 'All'}]; + addTemplatedVariables($scope.metric.groupList); + $scope.metric.groupList = $scope.metric.groupList.concat(groups); }); - } - }; - - /** - * Update list of items - */ - $scope.updateItemList = function() { - var groups = $scope.target.group ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; - var hosts = $scope.target.host ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.host.name)) : undefined; - var apps = $scope.target.application ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.application.name)) : undefined; - if (groups && hosts && apps) { - $scope.datasource.zabbixAPI.itemFindQuery(groups, hosts, apps).then(function (items) { - // Show only unique item names - var uniq_items = _.map(_.uniq(items, function (item) { - return zabbixHelperSrv.expandItemName(item); - }), function (item) { - return {name: zabbixHelperSrv.expandItemName(item)}; + }; + + /** + * Update list of hosts + */ + $scope.updateHostList = function () { + var groups = $scope.target.group ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; + if (groups) { + $scope.datasource.zabbixAPI.hostFindQuery(groups).then(function (hosts) { + $scope.metric.hostList = [{name: '*', visible_name: 'All'}]; + addTemplatedVariables($scope.metric.hostList); + $scope.metric.hostList = $scope.metric.hostList.concat(hosts); + }); + } + }; + + /** + * Update list of host applications + */ + $scope.updateAppList = function () { + var groups = $scope.target.group ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; + var hosts = $scope.target.host ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.host.name)) : undefined; + if (groups && hosts) { + $scope.datasource.zabbixAPI.appFindQuery(hosts, groups).then(function (apps) { + apps = _.map(_.uniq(_.map(apps, 'name')), function (appname) { + return {name: appname}; + }); + $scope.metric.applicationList = [{name: '*', visible_name: 'All'}]; + addTemplatedVariables($scope.metric.applicationList); + $scope.metric.applicationList = $scope.metric.applicationList.concat(apps); + }); + } + }; + + /** + * Update list of items + */ + $scope.updateItemList = function () { + var groups = $scope.target.group ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; + var hosts = $scope.target.host ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.host.name)) : undefined; + var apps = $scope.target.application ? + zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.application.name)) : undefined; + var itemtype = $scope.target.mode === 2 ? "text" : "numeric"; + if (groups && hosts && apps) { + $scope.datasource.zabbixAPI.itemFindQuery(groups, hosts, apps, itemtype).then(function (items) { + // Show only unique item names + var uniq_items = _.map(_.uniq(items, function (item) { + return zabbixHelperSrv.expandItemName(item); + }), function (item) { + return {name: zabbixHelperSrv.expandItemName(item)}; + }); + $scope.metric.itemList = [{name: 'All'}]; + addTemplatedVariables($scope.metric.itemList); + $scope.metric.itemList = $scope.metric.itemList.concat(uniq_items); + }); + } + }; + + /** + * Add templated variables to list of available metrics + * + * @param {Array} metricList List of metrics which variables add to + */ + function addTemplatedVariables(metricList) { + _.each(templateSrv.variables, function (variable) { + metricList.push({ + name: '$' + variable.name, + templated: true }); - $scope.metric.itemList = [{name: 'All'}]; - addTemplatedVariables($scope.metric.itemList); - $scope.metric.itemList = $scope.metric.itemList.concat(uniq_items); }); } - }; - - /** - * Add templated variables to list of available metrics - * - * @param {Array} metricList List of metrics which variables add to - */ - function addTemplatedVariables(metricList) { - _.each(templateSrv.variables, function(variable) { - metricList.push({ - name: '$' + variable.name, - templated: true - }); - }); - } - ////////////////////////////// - // VALIDATION - ////////////////////////////// + ////////////////////////////// + // VALIDATION + ////////////////////////////// - function validateTarget(target) { - var errs = {}; - if (!target) { - errs = 'Not defined'; + function validateTarget(target) { + var errs = {}; + if (!target) { + errs = 'Not defined'; + } + return errs; } - return errs; - } - }); + }); -}); + }); diff --git a/zabbix/zabbixAPIWrapper.js b/zabbix/zabbixAPIWrapper.js index 45a14d1ef..8a89ccc02 100644 --- a/zabbix/zabbixAPIWrapper.js +++ b/zabbix/zabbixAPIWrapper.js @@ -1,7 +1,7 @@ define([ 'angular', - 'lodash', -], + 'lodash' + ], function (angular, _) { 'use strict'; @@ -94,7 +94,7 @@ function (angular, _) { }, auth: null, id: 1 - }, + } }; if (this.basicAuth || this.withCredentials) { @@ -245,8 +245,8 @@ function (angular, _) { /** * Get the list of hosts * - * @param {array} groupids - * @return {array} array of Zabbix host objects + * @param {string|string[]} groupids + * @return {Object} array of Zabbix host objects */ p.performHostSuggestQuery = function(groupids) { var params = { @@ -269,7 +269,7 @@ function (angular, _) { * * @param {array} hostids * @param {array} groupids - * @return {array} array of Zabbix application objects + * @return {Object} array of Zabbix application objects */ p.performAppSuggestQuery = function(hostids, /* optional */ groupids) { var params = { @@ -289,12 +289,12 @@ function (angular, _) { /** * Items request * - * @param {string or Array} hostids /////////////////////////// - * @param {string or Array} applicationids // Zabbix API parameters // - * @param {string or Array} groupids /////////////////////////// - * @return {string or Array} Array of Zabbix API item objects + * @param {string|string[]} hostids /////////////////////////// + * @param {string|string[]} applicationids // Zabbix API parameters // + * @param {string|string[]} groupids /////////////////////////// + * @return {string|string[]} Array of Zabbix API item objects */ - p.performItemSuggestQuery = function(hostids, applicationids, /* optional */ groupids) { + p.performItemSuggestQuery = function(hostids, applicationids, groupids, itemtype) { var params = { output: ['name', 'key_', 'value_type', 'delay'], sortfield: 'name', @@ -302,13 +302,17 @@ function (angular, _) { webitems: true, // Return only numeric items filter: { - value_type: [0,3] + value_type: [0, 3] }, // Return only enabled items monitored: true, searchByAny: true }; + if (itemtype === "text") { + params.filter.value_type = [1, 2, 4]; + } + // Filter by hosts or by groups if (hostids) { params.hostids = hostids; @@ -409,7 +413,7 @@ function (angular, _) { * @param {string or array} apps * @return {array} array of Zabbix API item objects */ - p.itemFindQuery = function(groups, hosts, apps) { + p.itemFindQuery = function(groups, hosts, apps, itemtype) { var promises = []; // Get hostids from names @@ -447,7 +451,7 @@ function (angular, _) { }), 'applicationid'); } - return self.performItemSuggestQuery(hostids, applicationids, groupids); + return self.performItemSuggestQuery(hostids, applicationids, groupids, itemtype); }); }; @@ -508,6 +512,25 @@ function (angular, _) { }); }; + p.getITService = function(/* optional */ serviceids) { + var params = { + output: 'extend', + serviceids: serviceids + }; + return this.performZabbixAPIRequest('service.get', params); + }; + + p.getSLA = function(serviceids, from, to) { + var params = { + serviceids: serviceids, + intervals: [{ + from: from, + to: to + }] + }; + return this.performZabbixAPIRequest('service.getsla', params); + }; + return ZabbixAPI; });