Merge branch 'develop-1.9' into develop

Conflicts:
	.gitignore
	zabbix/datasource.js
	zabbix/partials/query.editor.html
	zabbix/queryCtrl.js
This commit is contained in:
Alexander Zobnin
2015-05-16 18:29:54 +03:00
3 changed files with 79 additions and 24 deletions

View File

@@ -1,2 +1,43 @@
# grafana-zabbix # grafana-zabbix
Zabbix API datasource for Grafana dashboard 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 `<your grafana installation>/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.

View File

@@ -39,14 +39,14 @@ function (angular, _, kbn) {
// Need for find target alias // Need for find target alias
var targets = options.targets; var targets = options.targets;
// TODO: remove undefined targets from request // Remove undefined and hidden targets
// Check that all targets defined var displayedTargets = _.filter(targets, function (target) {
var targetsDefined = options.targets.every(function (target, index, array) { return (!target.hide && target.item);
return target.item;
}); });
if (targetsDefined) {
if (displayedTargets.length) {
// Extract zabbix api item objects from targets // Extract zabbix api item objects from targets
var target_items = _.map(options.targets, 'item'); var target_items = _.map(displayedTargets, 'item');
} else { } else {
// No valid targets, return the empty dataset // No valid targets, return the empty dataset
var d = $q.defer(); var d = $q.defer();
@@ -75,13 +75,15 @@ function (angular, _, kbn) {
// Index returned datapoints by item/metric id // Index returned datapoints by item/metric id
var indexed_result = _.groupBy(response, 'itemid'); var indexed_result = _.groupBy(response, 'itemid');
// TODO: realize correct timeseries reduce
/*
// Reduce timeseries to the same size for stacking and tooltip work properly // Reduce timeseries to the same size for stacking and tooltip work properly
var min_length = _.min(_.map(indexed_result, function (history) { var min_length = _.min(_.map(indexed_result, function (history) {
return history.length; return history.length;
})); }));
_.each(indexed_result, function (item) { _.each(indexed_result, function (item) {
item.splice(0, item.length - min_length); item.splice(0, item.length - min_length);
}); });*/
// Sort result as the same as targets for display // Sort result as the same as targets for display
// stacked timeseries in proper order // stacked timeseries in proper order
@@ -120,7 +122,7 @@ function (angular, _, kbn) {
// Request data from Zabbix API // Request data from Zabbix API
ZabbixAPIDatasource.prototype.doZabbixAPIRequest = function(request_data) { ZabbixAPIDatasource.prototype.performZabbixAPIRequest = function(request_data) {
var options = { var options = {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -180,7 +182,7 @@ function (angular, _, kbn) {
itemids: item_ids, itemids: item_ids,
sortfield: 'clock', sortfield: 'clock',
sortorder: 'ASC', sortorder: 'ASC',
limit: self.limitMetrics, limit: self.limitmetrics,
time_from: start, time_from: start,
}, },
auth: self.auth, auth: self.auth,
@@ -192,7 +194,7 @@ function (angular, _, kbn) {
data.params.time_till = end; data.params.time_till = end;
} }
apiRequests.push(self.doZabbixAPIRequest(data)); apiRequests.push(self.performZabbixAPIRequest(data));
}); });
return this.handleMultipleRequest(apiRequests); return this.handleMultipleRequest(apiRequests);
@@ -265,7 +267,7 @@ function (angular, _, kbn) {
id: 1 id: 1
}; };
return this.doZabbixAPIRequest(data); return this.performZabbixAPIRequest(data);
}; };
@@ -285,7 +287,7 @@ function (angular, _, kbn) {
data.params.groupids = groupid; data.params.groupids = groupid;
} }
return this.doZabbixAPIRequest(data); return this.performZabbixAPIRequest(data);
}; };
@@ -303,7 +305,7 @@ function (angular, _, kbn) {
id: 1 id: 1
}; };
return this.doZabbixAPIRequest(data); return this.performZabbixAPIRequest(data);
}; };
@@ -329,7 +331,7 @@ function (angular, _, kbn) {
data.params.applicationids = applicationid; data.params.applicationids = applicationid;
} }
return this.doZabbixAPIRequest(data); return this.performZabbixAPIRequest(data);
}; };
@@ -349,7 +351,7 @@ function (angular, _, kbn) {
params: { params: {
output: ['triggerid', 'description'], output: ['triggerid', 'description'],
itemids: annotation.aids.split(','), // TODO: validate / pull automatically from dashboard. itemids: annotation.aids.split(','), // TODO: validate / pull automatically from dashboard.
limit: self.limitMetrics, limit: self.limitmetrics,
}, },
auth: self.auth, auth: self.auth,
id: 1 id: 1
@@ -372,7 +374,7 @@ function (angular, _, kbn) {
time_from: from, time_from: from,
time_till: to, time_till: to,
objectids: _.keys(obs), objectids: _.keys(obs),
limit: self.limitMetrics, limit: self.limitmetrics,
}, },
auth: self.auth, auth: self.auth,
id: 1 id: 1

View File

@@ -35,10 +35,20 @@ function (angular, _) {
} }
} }
setItemAlias();
$scope.target.errors = validateTarget($scope.target); $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() { $scope.targetBlur = function() {
setItemAlias();
$scope.target.errors = validateTarget($scope.target); $scope.target.errors = validateTarget($scope.target);
if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) {
$scope.oldTarget = angular.copy($scope.target); $scope.oldTarget = angular.copy($scope.target);
@@ -65,7 +75,7 @@ function (angular, _) {
// Call when host selected // Call when host selected
$scope.selectHost = function() { $scope.selectHost = function() {
if ($scope.target.host) {
// Update item list // Update item list
if ($scope.target.application) { if ($scope.target.application) {
$scope.updateItemList($scope.target.host.hostid, $scope.target.application.applicationid); $scope.updateItemList($scope.target.host.hostid, $scope.target.application.applicationid);
@@ -75,6 +85,7 @@ function (angular, _) {
// Update application list // Update application list
$scope.updateAppList($scope.target.host.hostid); $scope.updateAppList($scope.target.host.hostid);
}
$scope.target.errors = validateTarget($scope.target); $scope.target.errors = validateTarget($scope.target);
if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) {
@@ -104,6 +115,7 @@ function (angular, _) {
// Call when item selected // Call when item selected
$scope.selectItem = function() { $scope.selectItem = function() {
setItemAlias();
$scope.target.errors = validateTarget($scope.target); $scope.target.errors = validateTarget($scope.target);
if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) { if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) {
$scope.oldTarget = angular.copy($scope.target); $scope.oldTarget = angular.copy($scope.target);