diff --git a/README.md b/README.md index c02e1c2..e96ecff 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,43 @@ # grafana-zabbix Zabbix API datasource for Grafana dashboard + +![alt tag](https://cloud.githubusercontent.com/assets/4932851/7454206/34bf9f8c-f27a-11e4-8e96-a73829f188c4.png) + + +Query editor allows to add metric by step-by-step selection from host group, host, application dropdown menus. + +![alt tag](https://cloud.githubusercontent.com/assets/4932851/7441162/4f6af788-f0e4-11e4-887b-34d987d00c40.png) +![alt tag](https://cloud.githubusercontent.com/assets/4932851/7441163/56f28f16-f0e4-11e4-9d46-54181c2a2e7e.png) +![alt tag](https://cloud.githubusercontent.com/assets/4932851/7441167/5f29cc94-f0e4-11e4-8d39-7580f33201f6.png) + + +## Installation + +### Grafana 1.9.x + +Download latest release and unpack into `/plugins/datasource/`. Then edit Grafana config.js: + * Add dependencies + + ``` + plugins: { + panels: [], + dependencies: ['datasource/zabbix/datasource', 'datasource/zabbix/queryCtrl'], + } + ``` + * Add datasource and setup your Zabbix API url, username and password + + ``` + datasources: { + ... + }, + zabbix: { + type: 'ZabbixAPIDatasource', + url: 'http://www.zabbix.org/zabbix/api_jsonrpc.php', + username: 'guest', + password: '' + } + }, + ``` + +### Grafana 2.0.x +Now in development. diff --git a/zabbix/datasource.js b/zabbix/datasource.js index 5ca2ac1..45c38b8 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -39,14 +39,14 @@ function (angular, _, kbn) { // Need for find target alias var targets = options.targets; - // TODO: remove undefined targets from request - // Check that all targets defined - var targetsDefined = options.targets.every(function (target, index, array) { - return target.item; + // Remove undefined and hidden targets + var displayedTargets = _.filter(targets, function (target) { + return (!target.hide && target.item); }); - if (targetsDefined) { + + if (displayedTargets.length) { // Extract zabbix api item objects from targets - var target_items = _.map(options.targets, 'item'); + var target_items = _.map(displayedTargets, 'item'); } else { // No valid targets, return the empty dataset var d = $q.defer(); @@ -75,13 +75,15 @@ function (angular, _, kbn) { // 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 @@ -120,7 +122,7 @@ function (angular, _, kbn) { // Request data from Zabbix API - ZabbixAPIDatasource.prototype.doZabbixAPIRequest = function(request_data) { + ZabbixAPIDatasource.prototype.performZabbixAPIRequest = function(request_data) { var options = { method: 'POST', headers: { @@ -180,7 +182,7 @@ function (angular, _, kbn) { itemids: item_ids, sortfield: 'clock', sortorder: 'ASC', - limit: self.limitMetrics, + limit: self.limitmetrics, time_from: start, }, auth: self.auth, @@ -192,7 +194,7 @@ function (angular, _, kbn) { data.params.time_till = end; } - apiRequests.push(self.doZabbixAPIRequest(data)); + apiRequests.push(self.performZabbixAPIRequest(data)); }); return this.handleMultipleRequest(apiRequests); @@ -265,7 +267,7 @@ function (angular, _, kbn) { id: 1 }; - return this.doZabbixAPIRequest(data); + return this.performZabbixAPIRequest(data); }; @@ -285,7 +287,7 @@ function (angular, _, kbn) { data.params.groupids = groupid; } - return this.doZabbixAPIRequest(data); + return this.performZabbixAPIRequest(data); }; @@ -303,7 +305,7 @@ function (angular, _, kbn) { id: 1 }; - return this.doZabbixAPIRequest(data); + return this.performZabbixAPIRequest(data); }; @@ -329,7 +331,7 @@ function (angular, _, kbn) { data.params.applicationids = applicationid; } - return this.doZabbixAPIRequest(data); + return this.performZabbixAPIRequest(data); }; @@ -349,7 +351,7 @@ function (angular, _, kbn) { params: { output: ['triggerid', 'description'], itemids: annotation.aids.split(','), // TODO: validate / pull automatically from dashboard. - limit: self.limitMetrics, + limit: self.limitmetrics, }, auth: self.auth, id: 1 @@ -372,7 +374,7 @@ function (angular, _, kbn) { time_from: from, time_till: to, objectids: _.keys(obs), - limit: self.limitMetrics, + limit: self.limitmetrics, }, auth: self.auth, id: 1 diff --git a/zabbix/queryCtrl.js b/zabbix/queryCtrl.js index a194b27..2c511dc 100644 --- a/zabbix/queryCtrl.js +++ b/zabbix/queryCtrl.js @@ -35,10 +35,20 @@ function (angular, _) { } } + setItemAlias(); + $scope.target.errors = validateTarget($scope.target); }; + // Take alias from item name by default + function setItemAlias() { + if (!$scope.target.alias && $scope.target.item) { + $scope.target.alias = $scope.target.item.expandedName; + } + }; + $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); @@ -65,17 +75,18 @@ function (angular, _) { // Call when host selected $scope.selectHost = function() { + if ($scope.target.host) { + // Update item list + if ($scope.target.application) { + $scope.updateItemList($scope.target.host.hostid, $scope.target.application.applicationid); + } else { + $scope.updateItemList($scope.target.host.hostid, null); + } - // Update item list - if ($scope.target.application) { - $scope.updateItemList($scope.target.host.hostid, $scope.target.application.applicationid); - } else { - $scope.updateItemList($scope.target.host.hostid, null); + // Update application list + $scope.updateAppList($scope.target.host.hostid); } - // Update application list - $scope.updateAppList($scope.target.host.hostid); - $scope.target.errors = validateTarget($scope.target); if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { $scope.oldTarget = angular.copy($scope.target); @@ -104,6 +115,7 @@ function (angular, _) { // 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);