Add dist/ directory to repo to correspond development guide.
http://docs.grafana.org/plugins/development/
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Don't diff files in dist/
|
||||||
|
*.map binary
|
||||||
|
dist/** binary
|
||||||
2
.gitignore
vendored
@@ -23,7 +23,7 @@ awsconfig
|
|||||||
/tmp
|
/tmp
|
||||||
vendor/phantomjs/phantomjs
|
vendor/phantomjs/phantomjs
|
||||||
|
|
||||||
dist/
|
# dist/
|
||||||
|
|
||||||
# locally required config files
|
# locally required config files
|
||||||
public/css/*.min.css
|
public/css/*.min.css
|
||||||
|
|||||||
24
dist/README.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
## Zabbix plugin for Grafana
|
||||||
|
Zabbix plugin allows to show different type of data from [Zabbix](http://www.zabbix.com/)
|
||||||
|
monitoring system.
|
||||||
|
|
||||||
|
### Live Demo
|
||||||
|
|
||||||
|
Check out the [live demo](http://play.grafana-zabbix.org/) with dashboard examples.
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
#### Flexible metric editor
|
||||||
|
* Regex-based metric filtering
|
||||||
|
* Client-side data processing functions
|
||||||
|
* Template variables support
|
||||||
|
|
||||||
|
#### Templated dashboards support
|
||||||
|
Group, host, application or item names can be replaced with a template variable. This allows you to create generic dashboards that can quickly be changed to show stats for a specific cluster, server or application.
|
||||||
|
|
||||||
|
#### Annotations support
|
||||||
|
* Display zabbix events on graphs
|
||||||
|
* Show acknowledges for problems
|
||||||
|
|
||||||
|
#### Triggers panel
|
||||||
|
Panel for showing Zabbix triggers (like Last 20 issues) with some customizable features.
|
||||||
1
dist/components/config.html
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<h3 class="page-heading">Zabbix Plugin Config</h3>
|
||||||
27
dist/components/config.js
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register([], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var ZabbixAppConfigCtrl;
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setters: [],
|
||||||
|
execute: function () {
|
||||||
|
_export('ZabbixAppConfigCtrl', ZabbixAppConfigCtrl = function ZabbixAppConfigCtrl() {
|
||||||
|
_classCallCheck(this, ZabbixAppConfigCtrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
_export('ZabbixAppConfigCtrl', ZabbixAppConfigCtrl);
|
||||||
|
|
||||||
|
ZabbixAppConfigCtrl.templateUrl = 'components/config.html';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=config.js.map
|
||||||
1
dist/components/config.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["../../src/components/config.js"],"names":["ZabbixAppConfigCtrl","templateUrl"],"mappings":";;;;;;;;;;;;;;;;qCAAaA,mB,GACX,+BAAc;AAAA;AAAG,O;;;;AAEnBA,0BAAoBC,WAApB,GAAkC,wBAAlC","file":"config.js","sourcesContent":["export class ZabbixAppConfigCtrl {\n constructor() { }\n}\nZabbixAppConfigCtrl.templateUrl = 'components/config.html';\n"]}
|
||||||
569
dist/dashboards/template_linux_server.json
vendored
Normal file
@@ -0,0 +1,569 @@
|
|||||||
|
{
|
||||||
|
"id": null,
|
||||||
|
"title": "Template Linux Server",
|
||||||
|
"originalTitle": "Template Linux Server",
|
||||||
|
"tags": [
|
||||||
|
"zabbix",
|
||||||
|
"example"
|
||||||
|
],
|
||||||
|
"style": "dark",
|
||||||
|
"timezone": "browser",
|
||||||
|
"editable": true,
|
||||||
|
"hideControls": false,
|
||||||
|
"sharedCrosshair": false,
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"collapse": false,
|
||||||
|
"editable": true,
|
||||||
|
"height": "250px",
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"aliasColors": {
|
||||||
|
"CPU iowait time": "#B7DBAB",
|
||||||
|
"CPU system time": "#BF1B00",
|
||||||
|
"CPU user time": "#EAB839"
|
||||||
|
},
|
||||||
|
"bars": false,
|
||||||
|
"datasource": null,
|
||||||
|
"editable": true,
|
||||||
|
"error": false,
|
||||||
|
"fill": 3,
|
||||||
|
"grid": {
|
||||||
|
"threshold1": null,
|
||||||
|
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||||
|
"threshold2": null,
|
||||||
|
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||||
|
},
|
||||||
|
"id": 1,
|
||||||
|
"legend": {
|
||||||
|
"avg": false,
|
||||||
|
"current": false,
|
||||||
|
"max": false,
|
||||||
|
"min": false,
|
||||||
|
"show": true,
|
||||||
|
"total": false,
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 1,
|
||||||
|
"links": [],
|
||||||
|
"nullPointMode": "connected",
|
||||||
|
"percentage": false,
|
||||||
|
"pointradius": 2,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"span": 6,
|
||||||
|
"stack": true,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"application": {
|
||||||
|
"filter": "CPU"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"group": {
|
||||||
|
"filter": "$group"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "$host"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "/CPU/"
|
||||||
|
},
|
||||||
|
"mode": 0,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "CPU",
|
||||||
|
"tooltip": {
|
||||||
|
"msResolution": false,
|
||||||
|
"shared": true,
|
||||||
|
"value_type": "individual"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"format": "percent",
|
||||||
|
"logBase": 1,
|
||||||
|
"max": 100,
|
||||||
|
"min": 0,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aliasColors": {
|
||||||
|
"Processor load (1 min average per core)": "#1F78C1"
|
||||||
|
},
|
||||||
|
"bars": false,
|
||||||
|
"datasource": null,
|
||||||
|
"editable": true,
|
||||||
|
"error": false,
|
||||||
|
"fill": 1,
|
||||||
|
"grid": {
|
||||||
|
"threshold1": null,
|
||||||
|
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||||
|
"threshold2": null,
|
||||||
|
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||||
|
},
|
||||||
|
"id": 2,
|
||||||
|
"legend": {
|
||||||
|
"avg": false,
|
||||||
|
"current": false,
|
||||||
|
"max": false,
|
||||||
|
"min": false,
|
||||||
|
"show": true,
|
||||||
|
"total": false,
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 2,
|
||||||
|
"links": [],
|
||||||
|
"nullPointMode": "connected",
|
||||||
|
"percentage": false,
|
||||||
|
"pointradius": 5,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"span": 6,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"application": {
|
||||||
|
"filter": "CPU"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"group": {
|
||||||
|
"filter": "$group"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "$host"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "Processor load (15 min average per core)"
|
||||||
|
},
|
||||||
|
"mode": 0,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "System load",
|
||||||
|
"tooltip": {
|
||||||
|
"msResolution": false,
|
||||||
|
"shared": true,
|
||||||
|
"value_type": "cumulative"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": 0,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"showTitle": true,
|
||||||
|
"title": "CPU"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapse": false,
|
||||||
|
"editable": true,
|
||||||
|
"height": "250px",
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": false,
|
||||||
|
"datasource": null,
|
||||||
|
"editable": true,
|
||||||
|
"error": false,
|
||||||
|
"fill": 3,
|
||||||
|
"grid": {
|
||||||
|
"threshold1": null,
|
||||||
|
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||||
|
"threshold2": null,
|
||||||
|
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||||
|
},
|
||||||
|
"id": 3,
|
||||||
|
"legend": {
|
||||||
|
"alignAsTable": false,
|
||||||
|
"avg": false,
|
||||||
|
"current": false,
|
||||||
|
"max": false,
|
||||||
|
"min": false,
|
||||||
|
"rightSide": false,
|
||||||
|
"show": true,
|
||||||
|
"total": false,
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 2,
|
||||||
|
"links": [],
|
||||||
|
"minSpan": 4,
|
||||||
|
"nullPointMode": "connected",
|
||||||
|
"percentage": false,
|
||||||
|
"pointradius": 5,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"repeat": "netif",
|
||||||
|
"scopedVars": {
|
||||||
|
"netif": {
|
||||||
|
"text": "eth0",
|
||||||
|
"value": "eth0",
|
||||||
|
"selected": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seriesOverrides": [
|
||||||
|
{
|
||||||
|
"alias": "/Incoming/",
|
||||||
|
"transform": "negative-Y"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"span": 6,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"application": {
|
||||||
|
"filter": ""
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"group": {
|
||||||
|
"filter": "$group"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "$host"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "/$netif/"
|
||||||
|
},
|
||||||
|
"mode": 0,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Network traffic on $netif",
|
||||||
|
"tooltip": {
|
||||||
|
"msResolution": false,
|
||||||
|
"shared": true,
|
||||||
|
"value_type": "cumulative"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"format": "bps",
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": false,
|
||||||
|
"datasource": null,
|
||||||
|
"editable": true,
|
||||||
|
"error": false,
|
||||||
|
"fill": 3,
|
||||||
|
"grid": {
|
||||||
|
"threshold1": null,
|
||||||
|
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||||
|
"threshold2": null,
|
||||||
|
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||||
|
},
|
||||||
|
"id": 4,
|
||||||
|
"legend": {
|
||||||
|
"alignAsTable": false,
|
||||||
|
"avg": false,
|
||||||
|
"current": false,
|
||||||
|
"max": false,
|
||||||
|
"min": false,
|
||||||
|
"rightSide": false,
|
||||||
|
"show": true,
|
||||||
|
"total": false,
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 2,
|
||||||
|
"links": [],
|
||||||
|
"minSpan": 4,
|
||||||
|
"nullPointMode": "connected",
|
||||||
|
"percentage": false,
|
||||||
|
"pointradius": 5,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"repeat": null,
|
||||||
|
"scopedVars": {
|
||||||
|
"netif": {
|
||||||
|
"text": "eth1",
|
||||||
|
"value": "eth1",
|
||||||
|
"selected": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seriesOverrides": [
|
||||||
|
{
|
||||||
|
"alias": "/Incoming/",
|
||||||
|
"transform": "negative-Y"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"span": 6,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"application": {
|
||||||
|
"filter": ""
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"group": {
|
||||||
|
"filter": "$group"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "$host"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "/$netif/"
|
||||||
|
},
|
||||||
|
"mode": 0,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Network traffic on $netif",
|
||||||
|
"tooltip": {
|
||||||
|
"msResolution": false,
|
||||||
|
"shared": true,
|
||||||
|
"value_type": "cumulative"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"format": "bps",
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"repeatIteration": 1460635040618,
|
||||||
|
"repeatPanelId": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"showTitle": true,
|
||||||
|
"title": "Network"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": {
|
||||||
|
"from": "now-3h",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {
|
||||||
|
"now": true,
|
||||||
|
"refresh_intervals": [
|
||||||
|
"30s",
|
||||||
|
"1m",
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"30m",
|
||||||
|
"1h",
|
||||||
|
"3h",
|
||||||
|
"2h",
|
||||||
|
"1d"
|
||||||
|
],
|
||||||
|
"time_options": [
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"1h",
|
||||||
|
"6h",
|
||||||
|
"12h",
|
||||||
|
"24h",
|
||||||
|
"2d",
|
||||||
|
"7d",
|
||||||
|
"30d"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"templating": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"allFormat": "regex values",
|
||||||
|
"current": {
|
||||||
|
"text": "Frontend",
|
||||||
|
"value": "Frontend"
|
||||||
|
},
|
||||||
|
"datasource": null,
|
||||||
|
"hide": 0,
|
||||||
|
"includeAll": false,
|
||||||
|
"label": "Group",
|
||||||
|
"multi": false,
|
||||||
|
"multiFormat": "glob",
|
||||||
|
"name": "group",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"text": "Backend",
|
||||||
|
"value": "Backend",
|
||||||
|
"selected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Database servers",
|
||||||
|
"value": "Database servers",
|
||||||
|
"selected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Frontend",
|
||||||
|
"value": "Frontend",
|
||||||
|
"selected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Linux servers",
|
||||||
|
"value": "Linux servers",
|
||||||
|
"selected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Network",
|
||||||
|
"value": "Network",
|
||||||
|
"selected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Workstations",
|
||||||
|
"value": "Workstations",
|
||||||
|
"selected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Zabbix servers",
|
||||||
|
"value": "Zabbix servers",
|
||||||
|
"selected": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"query": "*",
|
||||||
|
"refresh": 1,
|
||||||
|
"refresh_on_load": false,
|
||||||
|
"regex": "",
|
||||||
|
"type": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allFormat": "glob",
|
||||||
|
"current": {
|
||||||
|
"text": "frontend01",
|
||||||
|
"value": "frontend01"
|
||||||
|
},
|
||||||
|
"datasource": null,
|
||||||
|
"hide": 0,
|
||||||
|
"includeAll": false,
|
||||||
|
"label": "Host",
|
||||||
|
"multi": false,
|
||||||
|
"multiFormat": "glob",
|
||||||
|
"name": "host",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"text": "frontend01",
|
||||||
|
"value": "frontend01",
|
||||||
|
"selected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "frontend02",
|
||||||
|
"value": "frontend02",
|
||||||
|
"selected": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"query": "$group.*",
|
||||||
|
"refresh": 1,
|
||||||
|
"refresh_on_load": false,
|
||||||
|
"regex": "",
|
||||||
|
"type": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allFormat": "regex values",
|
||||||
|
"current": {
|
||||||
|
"text": "All",
|
||||||
|
"value": "$__all"
|
||||||
|
},
|
||||||
|
"datasource": null,
|
||||||
|
"hide": 0,
|
||||||
|
"hideLabel": false,
|
||||||
|
"includeAll": true,
|
||||||
|
"label": "Network interface",
|
||||||
|
"multi": true,
|
||||||
|
"multiFormat": "regex values",
|
||||||
|
"name": "netif",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"text": "All",
|
||||||
|
"value": "$__all",
|
||||||
|
"selected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "eth0",
|
||||||
|
"value": "eth0",
|
||||||
|
"selected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "eth1",
|
||||||
|
"value": "eth1",
|
||||||
|
"selected": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"query": "*.$host.Network interfaces.*",
|
||||||
|
"refresh": 1,
|
||||||
|
"refresh_on_load": false,
|
||||||
|
"regex": "/(?:Incoming|Outgoing) network traffic on (.*)/",
|
||||||
|
"type": "query"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"annotations": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"schemaVersion": 12,
|
||||||
|
"version": 8,
|
||||||
|
"links": []
|
||||||
|
}
|
||||||
633
dist/dashboards/zabbix_server_dashboard.json
vendored
Normal file
@@ -0,0 +1,633 @@
|
|||||||
|
{
|
||||||
|
"id": null,
|
||||||
|
"title": "Zabbix Server Dashboard",
|
||||||
|
"originalTitle": "Zabbix Server Dashboard",
|
||||||
|
"tags": [
|
||||||
|
"zabbix",
|
||||||
|
"example"
|
||||||
|
],
|
||||||
|
"style": "dark",
|
||||||
|
"timezone": "browser",
|
||||||
|
"editable": true,
|
||||||
|
"hideControls": false,
|
||||||
|
"sharedCrosshair": false,
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"collapse": false,
|
||||||
|
"editable": true,
|
||||||
|
"height": "100px",
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"cacheTimeout": null,
|
||||||
|
"colorBackground": false,
|
||||||
|
"colorValue": false,
|
||||||
|
"colors": [
|
||||||
|
"rgba(245, 54, 54, 0.9)",
|
||||||
|
"rgba(237, 129, 40, 0.89)",
|
||||||
|
"rgba(50, 172, 45, 0.97)"
|
||||||
|
],
|
||||||
|
"datasource": null,
|
||||||
|
"editable": true,
|
||||||
|
"error": false,
|
||||||
|
"format": "none",
|
||||||
|
"id": 3,
|
||||||
|
"interval": null,
|
||||||
|
"isNew": true,
|
||||||
|
"links": [],
|
||||||
|
"maxDataPoints": 100,
|
||||||
|
"nullPointMode": "connected",
|
||||||
|
"nullText": null,
|
||||||
|
"postfix": "",
|
||||||
|
"postfixFontSize": "50%",
|
||||||
|
"prefix": "",
|
||||||
|
"prefixFontSize": "50%",
|
||||||
|
"span": 4,
|
||||||
|
"sparkline": {
|
||||||
|
"fillColor": "rgba(31, 118, 189, 0.18)",
|
||||||
|
"full": false,
|
||||||
|
"lineColor": "rgb(31, 120, 193)",
|
||||||
|
"show": false
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"application": {
|
||||||
|
"filter": "General"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"group": {
|
||||||
|
"filter": "Zabbix servers"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "Host name"
|
||||||
|
},
|
||||||
|
"mode": 2,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": "",
|
||||||
|
"title": "Host name",
|
||||||
|
"type": "singlestat",
|
||||||
|
"valueFontSize": "80%",
|
||||||
|
"valueMaps": [
|
||||||
|
{
|
||||||
|
"op": "=",
|
||||||
|
"text": "N/A",
|
||||||
|
"value": "null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"valueName": "avg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cacheTimeout": null,
|
||||||
|
"colorBackground": false,
|
||||||
|
"colorValue": false,
|
||||||
|
"colors": [
|
||||||
|
"rgba(245, 54, 54, 0.9)",
|
||||||
|
"rgba(237, 129, 40, 0.89)",
|
||||||
|
"rgba(50, 172, 45, 0.97)"
|
||||||
|
],
|
||||||
|
"datasource": null,
|
||||||
|
"decimals": 0,
|
||||||
|
"editable": true,
|
||||||
|
"error": false,
|
||||||
|
"format": "s",
|
||||||
|
"id": 4,
|
||||||
|
"interval": null,
|
||||||
|
"isNew": true,
|
||||||
|
"links": [],
|
||||||
|
"maxDataPoints": "",
|
||||||
|
"nullPointMode": "connected",
|
||||||
|
"nullText": null,
|
||||||
|
"postfix": "",
|
||||||
|
"postfixFontSize": "50%",
|
||||||
|
"prefix": "",
|
||||||
|
"prefixFontSize": "50%",
|
||||||
|
"span": 4,
|
||||||
|
"sparkline": {
|
||||||
|
"fillColor": "rgba(31, 118, 189, 0.18)",
|
||||||
|
"full": false,
|
||||||
|
"lineColor": "rgb(31, 120, 193)",
|
||||||
|
"show": false
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"application": {
|
||||||
|
"filter": "General"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"group": {
|
||||||
|
"filter": "Zabbix servers"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "System uptime"
|
||||||
|
},
|
||||||
|
"mode": 0,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": "",
|
||||||
|
"title": "Uptime",
|
||||||
|
"type": "singlestat",
|
||||||
|
"valueFontSize": "80%",
|
||||||
|
"valueMaps": [
|
||||||
|
{
|
||||||
|
"op": "=",
|
||||||
|
"text": "N/A",
|
||||||
|
"value": "null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"valueName": "current"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cacheTimeout": null,
|
||||||
|
"colorBackground": false,
|
||||||
|
"colorValue": false,
|
||||||
|
"colors": [
|
||||||
|
"rgba(245, 54, 54, 0.9)",
|
||||||
|
"rgba(237, 129, 40, 0.89)",
|
||||||
|
"rgba(50, 172, 45, 0.97)"
|
||||||
|
],
|
||||||
|
"datasource": null,
|
||||||
|
"editable": true,
|
||||||
|
"error": false,
|
||||||
|
"format": "none",
|
||||||
|
"id": 5,
|
||||||
|
"interval": null,
|
||||||
|
"isNew": true,
|
||||||
|
"links": [],
|
||||||
|
"maxDataPoints": "",
|
||||||
|
"nullPointMode": "connected",
|
||||||
|
"nullText": null,
|
||||||
|
"postfix": "",
|
||||||
|
"postfixFontSize": "50%",
|
||||||
|
"prefix": "",
|
||||||
|
"prefixFontSize": "50%",
|
||||||
|
"span": 4,
|
||||||
|
"sparkline": {
|
||||||
|
"fillColor": "rgba(31, 118, 189, 0.18)",
|
||||||
|
"full": false,
|
||||||
|
"lineColor": "rgb(31, 120, 193)",
|
||||||
|
"show": false
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"application": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"group": {
|
||||||
|
"filter": "Zabbix servers"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "/Required performance of Zabbix server/"
|
||||||
|
},
|
||||||
|
"mode": 0,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": "",
|
||||||
|
"title": "Required performance, NVPS",
|
||||||
|
"type": "singlestat",
|
||||||
|
"valueFontSize": "80%",
|
||||||
|
"valueMaps": [
|
||||||
|
{
|
||||||
|
"op": "=",
|
||||||
|
"text": "N/A",
|
||||||
|
"value": "null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"valueName": "current"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "General"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapse": false,
|
||||||
|
"editable": true,
|
||||||
|
"height": "300px",
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": false,
|
||||||
|
"datasource": null,
|
||||||
|
"editable": true,
|
||||||
|
"error": false,
|
||||||
|
"fill": 1,
|
||||||
|
"grid": {
|
||||||
|
"threshold1": null,
|
||||||
|
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||||
|
"threshold2": null,
|
||||||
|
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||||
|
},
|
||||||
|
"id": 1,
|
||||||
|
"isNew": true,
|
||||||
|
"legend": {
|
||||||
|
"alignAsTable": true,
|
||||||
|
"avg": false,
|
||||||
|
"current": false,
|
||||||
|
"max": false,
|
||||||
|
"min": false,
|
||||||
|
"rightSide": true,
|
||||||
|
"show": true,
|
||||||
|
"total": false,
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 2,
|
||||||
|
"links": [],
|
||||||
|
"nullPointMode": "connected",
|
||||||
|
"percentage": false,
|
||||||
|
"pointradius": 5,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [
|
||||||
|
{
|
||||||
|
"alias": "/user/",
|
||||||
|
"color": "#1F78C1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": "/system/",
|
||||||
|
"color": "#BF1B00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": "/iowait/",
|
||||||
|
"color": "#E5AC0E"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"span": 7,
|
||||||
|
"stack": true,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"application": {
|
||||||
|
"filter": "CPU"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"group": {
|
||||||
|
"filter": "Zabbix servers"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "/CPU (?!idle)/"
|
||||||
|
},
|
||||||
|
"mode": 0,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "CPU",
|
||||||
|
"tooltip": {
|
||||||
|
"msResolution": false,
|
||||||
|
"shared": true,
|
||||||
|
"value_type": "individual"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"format": "percent",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"text": "Current",
|
||||||
|
"value": "current"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Avg",
|
||||||
|
"value": "avg"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"editable": true,
|
||||||
|
"error": false,
|
||||||
|
"fontSize": "100%",
|
||||||
|
"id": 2,
|
||||||
|
"isNew": true,
|
||||||
|
"links": [],
|
||||||
|
"pageSize": null,
|
||||||
|
"scroll": true,
|
||||||
|
"showHeader": true,
|
||||||
|
"sort": {
|
||||||
|
"col": 2,
|
||||||
|
"desc": true
|
||||||
|
},
|
||||||
|
"span": 5,
|
||||||
|
"styles": [
|
||||||
|
{
|
||||||
|
"dateFormat": "YYYY-MM-DD HH:mm:ss",
|
||||||
|
"pattern": "Time",
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"colorMode": "cell",
|
||||||
|
"colors": [
|
||||||
|
"rgb(41, 170, 106)",
|
||||||
|
"rgba(239, 148, 21, 0.89)",
|
||||||
|
"rgba(239, 10, 10, 0.9)"
|
||||||
|
],
|
||||||
|
"decimals": 1,
|
||||||
|
"pattern": "/.*/",
|
||||||
|
"thresholds": [
|
||||||
|
"50",
|
||||||
|
"80"
|
||||||
|
],
|
||||||
|
"type": "number",
|
||||||
|
"unit": "percent"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"application": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"group": {
|
||||||
|
"filter": "Zabbix servers"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "/Zabbix busy/"
|
||||||
|
},
|
||||||
|
"mode": 0,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Zabbix processes",
|
||||||
|
"transform": "timeseries_aggregations",
|
||||||
|
"type": "table"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Row"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "New row",
|
||||||
|
"height": "380",
|
||||||
|
"editable": true,
|
||||||
|
"collapse": false,
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"title": "Zabbix busy processes",
|
||||||
|
"error": false,
|
||||||
|
"span": 7.069277691711851,
|
||||||
|
"editable": true,
|
||||||
|
"type": "graph",
|
||||||
|
"isNew": true,
|
||||||
|
"id": 6,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"mode": 0,
|
||||||
|
"group": {
|
||||||
|
"filter": "Zabbix servers"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"application": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "/Zabbix busy/"
|
||||||
|
},
|
||||||
|
"functions": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"datasource": null,
|
||||||
|
"renderer": "flot",
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"label": null,
|
||||||
|
"show": true,
|
||||||
|
"logBase": 1,
|
||||||
|
"min": null,
|
||||||
|
"max": null,
|
||||||
|
"format": "percent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": null,
|
||||||
|
"show": true,
|
||||||
|
"logBase": 1,
|
||||||
|
"min": null,
|
||||||
|
"max": null,
|
||||||
|
"format": "short"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"xaxis": {
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
"grid": {
|
||||||
|
"threshold1": null,
|
||||||
|
"threshold2": null,
|
||||||
|
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||||
|
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"fill": 0,
|
||||||
|
"linewidth": 2,
|
||||||
|
"points": false,
|
||||||
|
"pointradius": 5,
|
||||||
|
"bars": false,
|
||||||
|
"stack": false,
|
||||||
|
"percentage": false,
|
||||||
|
"legend": {
|
||||||
|
"show": true,
|
||||||
|
"values": false,
|
||||||
|
"min": false,
|
||||||
|
"max": false,
|
||||||
|
"current": false,
|
||||||
|
"total": false,
|
||||||
|
"avg": false,
|
||||||
|
"hideEmpty": true,
|
||||||
|
"hideZero": true,
|
||||||
|
"alignAsTable": true,
|
||||||
|
"rightSide": true
|
||||||
|
},
|
||||||
|
"nullPointMode": "connected",
|
||||||
|
"steppedLine": false,
|
||||||
|
"tooltip": {
|
||||||
|
"value_type": "cumulative",
|
||||||
|
"shared": true,
|
||||||
|
"msResolution": false
|
||||||
|
},
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"aliasColors": {},
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"links": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Zabbix Queue",
|
||||||
|
"error": false,
|
||||||
|
"span": 4.930722308288148,
|
||||||
|
"editable": true,
|
||||||
|
"type": "graph",
|
||||||
|
"isNew": true,
|
||||||
|
"id": 7,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"mode": 0,
|
||||||
|
"group": {
|
||||||
|
"filter": "Zabbix servers"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"application": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "Zabbix queue"
|
||||||
|
},
|
||||||
|
"functions": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "B",
|
||||||
|
"mode": 0,
|
||||||
|
"group": {
|
||||||
|
"filter": "Zabbix servers"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"application": {
|
||||||
|
"filter": "Zabbix server"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"filter": "/Values processed/"
|
||||||
|
},
|
||||||
|
"functions": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"datasource": null,
|
||||||
|
"renderer": "flot",
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"label": null,
|
||||||
|
"show": true,
|
||||||
|
"logBase": 1,
|
||||||
|
"min": null,
|
||||||
|
"max": null,
|
||||||
|
"format": "short"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": null,
|
||||||
|
"show": true,
|
||||||
|
"logBase": 1,
|
||||||
|
"min": null,
|
||||||
|
"max": null,
|
||||||
|
"format": "short"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"xaxis": {
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
"grid": {
|
||||||
|
"threshold1": null,
|
||||||
|
"threshold2": null,
|
||||||
|
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||||
|
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"fill": 0,
|
||||||
|
"linewidth": 2,
|
||||||
|
"points": false,
|
||||||
|
"pointradius": 5,
|
||||||
|
"bars": false,
|
||||||
|
"stack": false,
|
||||||
|
"percentage": false,
|
||||||
|
"legend": {
|
||||||
|
"show": true,
|
||||||
|
"values": false,
|
||||||
|
"min": false,
|
||||||
|
"max": false,
|
||||||
|
"current": false,
|
||||||
|
"total": false,
|
||||||
|
"avg": false
|
||||||
|
},
|
||||||
|
"nullPointMode": "connected",
|
||||||
|
"steppedLine": false,
|
||||||
|
"tooltip": {
|
||||||
|
"value_type": "cumulative",
|
||||||
|
"shared": true,
|
||||||
|
"msResolution": false
|
||||||
|
},
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"aliasColors": {},
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"links": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": {
|
||||||
|
"from": "now-6h",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {
|
||||||
|
"refresh_intervals": [
|
||||||
|
"5s",
|
||||||
|
"10s",
|
||||||
|
"30s",
|
||||||
|
"1m",
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"30m",
|
||||||
|
"1h",
|
||||||
|
"2h",
|
||||||
|
"1d"
|
||||||
|
],
|
||||||
|
"time_options": [
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"1h",
|
||||||
|
"6h",
|
||||||
|
"12h",
|
||||||
|
"24h",
|
||||||
|
"2d",
|
||||||
|
"7d",
|
||||||
|
"30d"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"annotations": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"schemaVersion": 12,
|
||||||
|
"version": 6,
|
||||||
|
"links": []
|
||||||
|
}
|
||||||
116
dist/datasource-zabbix/add-metric-function.directive.js
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['angular', 'lodash', 'jquery', './metricFunctions'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var angular, _, $, metricFunctions;
|
||||||
|
|
||||||
|
function getAllFunctionNames(categories) {
|
||||||
|
return _.reduce(categories, function (list, category) {
|
||||||
|
_.each(category, function (func) {
|
||||||
|
list.push(func.name);
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFunctionDropDownMenu(categories) {
|
||||||
|
return _.map(categories, function (list, category) {
|
||||||
|
return {
|
||||||
|
text: category,
|
||||||
|
submenu: _.map(list, function (value) {
|
||||||
|
return {
|
||||||
|
text: value.name,
|
||||||
|
click: "ctrl.addFunction('" + value.name + "')"
|
||||||
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
setters: [function (_angular) {
|
||||||
|
angular = _angular.default;
|
||||||
|
}, function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}, function (_jquery) {
|
||||||
|
$ = _jquery.default;
|
||||||
|
}, function (_metricFunctions) {
|
||||||
|
metricFunctions = _metricFunctions;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
angular.module('grafana.directives').directive('addMetricFunction', function ($compile) {
|
||||||
|
var inputTemplate = '<input type="text"' + ' class="gf-form-input"' + ' spellcheck="false" style="display:none"></input>';
|
||||||
|
|
||||||
|
var buttonTemplate = '<a class="gf-form-label tight-form-func dropdown-toggle query-part"' + ' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown">' + '<i class="fa fa-plus"></i></a>';
|
||||||
|
|
||||||
|
return {
|
||||||
|
link: function link($scope, elem) {
|
||||||
|
var categories = metricFunctions.getCategories();
|
||||||
|
var allFunctions = getAllFunctionNames(categories);
|
||||||
|
|
||||||
|
$scope.functionMenu = createFunctionDropDownMenu(categories);
|
||||||
|
|
||||||
|
var $input = $(inputTemplate);
|
||||||
|
var $button = $(buttonTemplate);
|
||||||
|
$input.appendTo(elem);
|
||||||
|
$button.appendTo(elem);
|
||||||
|
|
||||||
|
$input.attr('data-provide', 'typeahead');
|
||||||
|
$input.typeahead({
|
||||||
|
source: allFunctions,
|
||||||
|
minLength: 1,
|
||||||
|
items: 10,
|
||||||
|
updater: function updater(value) {
|
||||||
|
var funcDef = metricFunctions.getFuncDef(value);
|
||||||
|
if (!funcDef) {
|
||||||
|
// try find close match
|
||||||
|
value = value.toLowerCase();
|
||||||
|
funcDef = _.find(allFunctions, function (funcName) {
|
||||||
|
return funcName.toLowerCase().indexOf(value) === 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!funcDef) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.$apply(function () {
|
||||||
|
$scope.addFunction(funcDef);
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.trigger('blur');
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$button.click(function () {
|
||||||
|
$button.hide();
|
||||||
|
$input.show();
|
||||||
|
$input.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.keyup(function () {
|
||||||
|
elem.toggleClass('open', $input.val() === '');
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.blur(function () {
|
||||||
|
// clicking the function dropdown menu wont
|
||||||
|
// work if you remove class at once
|
||||||
|
setTimeout(function () {
|
||||||
|
$input.val('');
|
||||||
|
$input.hide();
|
||||||
|
$button.show();
|
||||||
|
elem.removeClass('open');
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
$compile(elem.contents())($scope);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=add-metric-function.directive.js.map
|
||||||
1
dist/datasource-zabbix/add-metric-function.directive.js.map
vendored
Normal file
7
dist/datasource-zabbix/css/query-editor.css
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.zbx-regex {
|
||||||
|
color: #CCA300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zbx-variable {
|
||||||
|
color: #33B5E5;
|
||||||
|
}
|
||||||
287
dist/datasource-zabbix/dataProcessor.js
vendored
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['lodash', './utils'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _, utils, metricFunctions, aggregationFunctions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downsample datapoints series
|
||||||
|
*/
|
||||||
|
function downsampleSeries(datapoints, time_to, ms_interval, func) {
|
||||||
|
var downsampledSeries = [];
|
||||||
|
var timeWindow = {
|
||||||
|
from: time_to * 1000 - ms_interval,
|
||||||
|
to: time_to * 1000
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
timeWindow.from -= ms_interval;
|
||||||
|
|
||||||
|
points_sum = 0;
|
||||||
|
points_num = 0;
|
||||||
|
frame = [];
|
||||||
|
|
||||||
|
// Process point again
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return downsampledSeries.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Group points by given time interval
|
||||||
|
* datapoints: [[<value>, <unixtime>], ...]
|
||||||
|
*/
|
||||||
|
function groupBy(interval, groupByCallback, datapoints) {
|
||||||
|
var ms_interval = utils.parseInterval(interval);
|
||||||
|
|
||||||
|
// Calculate frame timestamps
|
||||||
|
var frames = _.groupBy(datapoints, function (point) {
|
||||||
|
// Calculate time for group of points
|
||||||
|
return Math.floor(point[1] / ms_interval) * ms_interval;
|
||||||
|
});
|
||||||
|
|
||||||
|
// frame: { '<unixtime>': [[<value>, <unixtime>], ...] }
|
||||||
|
// return [{ '<unixtime>': <value> }, { '<unixtime>': <value> }, ...]
|
||||||
|
var grouped = _.mapValues(frames, function (frame) {
|
||||||
|
var points = _.map(frame, function (point) {
|
||||||
|
return point[0];
|
||||||
|
});
|
||||||
|
return groupByCallback(points);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert points to Grafana format
|
||||||
|
return sortByTime(_.map(grouped, function (value, timestamp) {
|
||||||
|
return [Number(value), Number(timestamp)];
|
||||||
|
}));
|
||||||
|
}function sumSeries(timeseries) {
|
||||||
|
|
||||||
|
// Calculate new points for interpolation
|
||||||
|
var new_timestamps = _.uniq(_.map(_.flatten(timeseries, true), function (point) {
|
||||||
|
return point[1];
|
||||||
|
}));
|
||||||
|
new_timestamps = _.sortBy(new_timestamps);
|
||||||
|
|
||||||
|
var interpolated_timeseries = _.map(timeseries, function (series) {
|
||||||
|
var timestamps = _.map(series, function (point) {
|
||||||
|
return point[1];
|
||||||
|
});
|
||||||
|
var new_points = _.map(_.difference(new_timestamps, timestamps), function (timestamp) {
|
||||||
|
return [null, timestamp];
|
||||||
|
});
|
||||||
|
var new_series = series.concat(new_points);
|
||||||
|
return sortByTime(new_series);
|
||||||
|
});
|
||||||
|
|
||||||
|
_.each(interpolated_timeseries, interpolateSeries);
|
||||||
|
|
||||||
|
var new_timeseries = [];
|
||||||
|
var sum;
|
||||||
|
for (var i = new_timestamps.length - 1; i >= 0; i--) {
|
||||||
|
sum = 0;
|
||||||
|
for (var j = interpolated_timeseries.length - 1; j >= 0; j--) {
|
||||||
|
sum += interpolated_timeseries[j][i][0];
|
||||||
|
}
|
||||||
|
new_timeseries.push([sum, new_timestamps[i]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortByTime(new_timeseries);
|
||||||
|
}function limit(order, n, orderByFunc, timeseries) {
|
||||||
|
var orderByCallback = aggregationFunctions[orderByFunc];
|
||||||
|
var sortByIteratee = function sortByIteratee(ts) {
|
||||||
|
var values = _.map(ts.datapoints, function (point) {
|
||||||
|
return point[0];
|
||||||
|
});
|
||||||
|
return orderByCallback(values);
|
||||||
|
};
|
||||||
|
var sortedTimeseries = _.sortBy(timeseries, sortByIteratee);
|
||||||
|
if (order === 'bottom') {
|
||||||
|
return sortedTimeseries.slice(0, n);
|
||||||
|
} else {
|
||||||
|
return sortedTimeseries.slice(-n);
|
||||||
|
}
|
||||||
|
}function AVERAGE(values) {
|
||||||
|
var sum = 0;
|
||||||
|
_.each(values, function (value) {
|
||||||
|
sum += value;
|
||||||
|
});
|
||||||
|
return sum / values.length;
|
||||||
|
}function MIN(values) {
|
||||||
|
return _.min(values);
|
||||||
|
}function MAX(values) {
|
||||||
|
return _.max(values);
|
||||||
|
}function MEDIAN(values) {
|
||||||
|
var sorted = _.sortBy(values);
|
||||||
|
return sorted[Math.floor(sorted.length / 2)];
|
||||||
|
}function setAlias(alias, timeseries) {
|
||||||
|
timeseries.target = alias;
|
||||||
|
return timeseries;
|
||||||
|
}function setAliasByRegex(alias, timeseries) {
|
||||||
|
timeseries.target = extractText(timeseries.target, alias);
|
||||||
|
return timeseries;
|
||||||
|
}function extractText(str, pattern) {
|
||||||
|
var extractPattern = new RegExp(pattern);
|
||||||
|
var extractedValue = extractPattern.exec(str);
|
||||||
|
extractedValue = extractedValue[0];
|
||||||
|
return extractedValue;
|
||||||
|
}function scale(factor, datapoints) {
|
||||||
|
return _.map(datapoints, function (point) {
|
||||||
|
return [point[0] * factor, point[1]];
|
||||||
|
});
|
||||||
|
}function delta(datapoints) {
|
||||||
|
var newSeries = [];
|
||||||
|
var deltaValue = void 0;
|
||||||
|
for (var i = 1; i < datapoints.length; i++) {
|
||||||
|
deltaValue = datapoints[i][0] - datapoints[i - 1][0];
|
||||||
|
newSeries.push([deltaValue, datapoints[i][1]]);
|
||||||
|
}
|
||||||
|
return newSeries;
|
||||||
|
}function groupByWrapper(interval, groupFunc, datapoints) {
|
||||||
|
var groupByCallback = aggregationFunctions[groupFunc];
|
||||||
|
return groupBy(interval, groupByCallback, datapoints);
|
||||||
|
}function aggregateByWrapper(interval, aggregateFunc, datapoints) {
|
||||||
|
// Flatten all points in frame and then just use groupBy()
|
||||||
|
var flattenedPoints = _.flatten(datapoints, true);
|
||||||
|
var groupByCallback = aggregationFunctions[aggregateFunc];
|
||||||
|
return groupBy(interval, groupByCallback, flattenedPoints);
|
||||||
|
}function aggregateWrapper(groupByCallback, interval, datapoints) {
|
||||||
|
var flattenedPoints = _.flatten(datapoints, true);
|
||||||
|
return groupBy(interval, groupByCallback, flattenedPoints);
|
||||||
|
}function sortByTime(series) {
|
||||||
|
return _.sortBy(series, function (point) {
|
||||||
|
return point[1];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interpolate series with gaps
|
||||||
|
*/
|
||||||
|
function interpolateSeries(series) {
|
||||||
|
var left, right;
|
||||||
|
|
||||||
|
// Interpolate series
|
||||||
|
for (var i = series.length - 1; i >= 0; i--) {
|
||||||
|
if (!series[i][0]) {
|
||||||
|
left = findNearestLeft(series, series[i]);
|
||||||
|
right = findNearestRight(series, series[i]);
|
||||||
|
if (!left) {
|
||||||
|
left = right;
|
||||||
|
}
|
||||||
|
if (!right) {
|
||||||
|
right = left;
|
||||||
|
}
|
||||||
|
series[i][0] = linearInterpolation(series[i][1], left, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return series;
|
||||||
|
}function linearInterpolation(timestamp, left, right) {
|
||||||
|
if (left[1] === right[1]) {
|
||||||
|
return (left[0] + right[0]) / 2;
|
||||||
|
} else {
|
||||||
|
return left[0] + (right[0] - left[0]) / (right[1] - left[1]) * (timestamp - left[1]);
|
||||||
|
}
|
||||||
|
}function findNearestRight(series, point) {
|
||||||
|
var point_index = _.indexOf(series, point);
|
||||||
|
var nearestRight;
|
||||||
|
for (var i = point_index; i < series.length; i++) {
|
||||||
|
if (series[i][0] !== null) {
|
||||||
|
return series[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nearestRight;
|
||||||
|
}function findNearestLeft(series, point) {
|
||||||
|
var point_index = _.indexOf(series, point);
|
||||||
|
var nearestLeft;
|
||||||
|
for (var i = point_index; i > 0; i--) {
|
||||||
|
if (series[i][0] !== null) {
|
||||||
|
return series[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nearestLeft;
|
||||||
|
}function timeShift(interval, range) {
|
||||||
|
var shift = utils.parseTimeShiftInterval(interval) / 1000;
|
||||||
|
return range.map(function (time) {
|
||||||
|
return time - shift;
|
||||||
|
});
|
||||||
|
}function unShiftTimeSeries(interval, datapoints) {
|
||||||
|
var unshift = utils.parseTimeShiftInterval(interval);
|
||||||
|
return datapoints.map(function (dp) {
|
||||||
|
return [dp[0], dp[1] + unshift];
|
||||||
|
});
|
||||||
|
}return {
|
||||||
|
setters: [function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}, function (_utils) {
|
||||||
|
utils = _utils;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
metricFunctions = {
|
||||||
|
groupBy: groupByWrapper,
|
||||||
|
scale: scale,
|
||||||
|
delta: delta,
|
||||||
|
aggregateBy: aggregateByWrapper,
|
||||||
|
average: _.partial(aggregateWrapper, AVERAGE),
|
||||||
|
min: _.partial(aggregateWrapper, MIN),
|
||||||
|
max: _.partial(aggregateWrapper, MAX),
|
||||||
|
median: _.partial(aggregateWrapper, MEDIAN),
|
||||||
|
sumSeries: sumSeries,
|
||||||
|
top: _.partial(limit, 'top'),
|
||||||
|
bottom: _.partial(limit, 'bottom'),
|
||||||
|
timeShift: timeShift,
|
||||||
|
setAlias: setAlias,
|
||||||
|
setAliasByRegex: setAliasByRegex
|
||||||
|
};
|
||||||
|
aggregationFunctions = {
|
||||||
|
avg: AVERAGE,
|
||||||
|
min: MIN,
|
||||||
|
max: MAX,
|
||||||
|
median: MEDIAN
|
||||||
|
};
|
||||||
|
|
||||||
|
_export('default', {
|
||||||
|
downsampleSeries: downsampleSeries,
|
||||||
|
groupBy: groupBy,
|
||||||
|
AVERAGE: AVERAGE,
|
||||||
|
MIN: MIN,
|
||||||
|
MAX: MAX,
|
||||||
|
MEDIAN: MEDIAN,
|
||||||
|
unShiftTimeSeries: unShiftTimeSeries,
|
||||||
|
|
||||||
|
get aggregationFunctions() {
|
||||||
|
return aggregationFunctions;
|
||||||
|
},
|
||||||
|
|
||||||
|
get metricFunctions() {
|
||||||
|
return metricFunctions;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=dataProcessor.js.map
|
||||||
1
dist/datasource-zabbix/dataProcessor.js.map
vendored
Normal file
597
dist/datasource-zabbix/datasource.js
vendored
Normal file
@@ -0,0 +1,597 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations', './metricFunctions', './dataProcessor', './responseHandler', './zabbix.js', './zabbixAPICore.service.js'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _, dateMath, utils, migrations, metricFunctions, dataProcessor, responseHandler, ZabbixAPIError, _slicedToArray, _createClass, ZabbixAPIDatasource;
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindFunctionDefs(functionDefs, category) {
|
||||||
|
var aggregationFunctions = _.map(metricFunctions.getCategories()[category], 'name');
|
||||||
|
var aggFuncDefs = _.filter(functionDefs, function (func) {
|
||||||
|
return _.includes(aggregationFunctions, func.def.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
return _.map(aggFuncDefs, function (func) {
|
||||||
|
var funcInstance = metricFunctions.createFuncInstance(func.def, func.params);
|
||||||
|
return funcInstance.bindFunction(dataProcessor.metricFunctions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function downsampleSeries(timeseries_data, options) {
|
||||||
|
return _.map(timeseries_data, function (timeseries) {
|
||||||
|
if (timeseries.datapoints.length > options.maxDataPoints) {
|
||||||
|
timeseries.datapoints = dataProcessor.groupBy(options.interval, dataProcessor.AVERAGE, timeseries.datapoints);
|
||||||
|
}
|
||||||
|
return timeseries;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMetric(metricObj) {
|
||||||
|
return {
|
||||||
|
text: metricObj.name,
|
||||||
|
expandable: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom formatter for template variables.
|
||||||
|
* Default Grafana "regex" formatter returns
|
||||||
|
* value1|value2
|
||||||
|
* This formatter returns
|
||||||
|
* (value1|value2)
|
||||||
|
* This format needed for using in complex regex with
|
||||||
|
* template variables, for example
|
||||||
|
* /CPU $cpu_item.*time/ where $cpu_item is system,user,iowait
|
||||||
|
*/
|
||||||
|
function zabbixTemplateFormat(value) {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return utils.escapeRegex(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var escapedValues = _.map(value, utils.escapeRegex);
|
||||||
|
return '(' + escapedValues.join('|') + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If template variables are used in request, replace it using regex format
|
||||||
|
* and wrap with '/' for proper multi-value work. Example:
|
||||||
|
* $variable selected as a, b, c
|
||||||
|
* We use filter $variable
|
||||||
|
* $variable -> a|b|c -> /a|b|c/
|
||||||
|
* /$variable/ -> /a|b|c/ -> /a|b|c/
|
||||||
|
*/
|
||||||
|
function replaceTemplateVars(templateSrv, target, scopedVars) {
|
||||||
|
var replacedTarget = templateSrv.replace(target, scopedVars, zabbixTemplateFormat);
|
||||||
|
if (target !== replacedTarget && !utils.isRegex(replacedTarget)) {
|
||||||
|
replacedTarget = '/^' + replacedTarget + '$/';
|
||||||
|
}
|
||||||
|
return replacedTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractText(str, pattern, useCaptureGroups) {
|
||||||
|
var extractPattern = new RegExp(pattern);
|
||||||
|
var extractedValue = extractPattern.exec(str);
|
||||||
|
if (extractedValue) {
|
||||||
|
if (useCaptureGroups) {
|
||||||
|
extractedValue = extractedValue[1];
|
||||||
|
} else {
|
||||||
|
extractedValue = extractedValue[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply function one by one:
|
||||||
|
// sequence([a(), b(), c()]) = c(b(a()));
|
||||||
|
function sequence(funcsArray) {
|
||||||
|
return function (result) {
|
||||||
|
for (var i = 0; i < funcsArray.length; i++) {
|
||||||
|
result = funcsArray[i].call(this, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setters: [function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}, function (_appCoreUtilsDatemath) {
|
||||||
|
dateMath = _appCoreUtilsDatemath;
|
||||||
|
}, function (_utils) {
|
||||||
|
utils = _utils;
|
||||||
|
}, function (_migrations) {
|
||||||
|
migrations = _migrations;
|
||||||
|
}, function (_metricFunctions) {
|
||||||
|
metricFunctions = _metricFunctions;
|
||||||
|
}, function (_dataProcessor) {
|
||||||
|
dataProcessor = _dataProcessor.default;
|
||||||
|
}, function (_responseHandler) {
|
||||||
|
responseHandler = _responseHandler.default;
|
||||||
|
}, function (_zabbixJs) {}, function (_zabbixAPICoreServiceJs) {
|
||||||
|
ZabbixAPIError = _zabbixAPICoreServiceJs.ZabbixAPIError;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
_slicedToArray = function () {
|
||||||
|
function sliceIterator(arr, i) {
|
||||||
|
var _arr = [];
|
||||||
|
var _n = true;
|
||||||
|
var _d = false;
|
||||||
|
var _e = undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
||||||
|
_arr.push(_s.value);
|
||||||
|
|
||||||
|
if (i && _arr.length === i) break;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
_d = true;
|
||||||
|
_e = err;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (!_n && _i["return"]) _i["return"]();
|
||||||
|
} finally {
|
||||||
|
if (_d) throw _e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (arr, i) {
|
||||||
|
if (Array.isArray(arr)) {
|
||||||
|
return arr;
|
||||||
|
} else if (Symbol.iterator in Object(arr)) {
|
||||||
|
return sliceIterator(arr, i);
|
||||||
|
} else {
|
||||||
|
throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
_createClass = function () {
|
||||||
|
function defineProperties(target, props) {
|
||||||
|
for (var i = 0; i < props.length; i++) {
|
||||||
|
var descriptor = props[i];
|
||||||
|
descriptor.enumerable = descriptor.enumerable || false;
|
||||||
|
descriptor.configurable = true;
|
||||||
|
if ("value" in descriptor) descriptor.writable = true;
|
||||||
|
Object.defineProperty(target, descriptor.key, descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (Constructor, protoProps, staticProps) {
|
||||||
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
||||||
|
if (staticProps) defineProperties(Constructor, staticProps);
|
||||||
|
return Constructor;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
_export('ZabbixAPIDatasource', ZabbixAPIDatasource = function () {
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function ZabbixAPIDatasource(instanceSettings, templateSrv, alertSrv, Zabbix) {
|
||||||
|
_classCallCheck(this, ZabbixAPIDatasource);
|
||||||
|
|
||||||
|
this.templateSrv = templateSrv;
|
||||||
|
this.alertSrv = alertSrv;
|
||||||
|
|
||||||
|
// General data source settings
|
||||||
|
this.name = instanceSettings.name;
|
||||||
|
this.url = instanceSettings.url;
|
||||||
|
this.basicAuth = instanceSettings.basicAuth;
|
||||||
|
this.withCredentials = instanceSettings.withCredentials;
|
||||||
|
|
||||||
|
// Zabbix API credentials
|
||||||
|
this.username = instanceSettings.jsonData.username;
|
||||||
|
this.password = instanceSettings.jsonData.password;
|
||||||
|
|
||||||
|
// Use trends instead history since specified time
|
||||||
|
this.trends = instanceSettings.jsonData.trends;
|
||||||
|
this.trendsFrom = instanceSettings.jsonData.trendsFrom || '7d';
|
||||||
|
|
||||||
|
// Set cache update interval
|
||||||
|
var ttl = instanceSettings.jsonData.cacheTTL || '1h';
|
||||||
|
this.cacheTTL = utils.parseInterval(ttl);
|
||||||
|
|
||||||
|
this.zabbix = new Zabbix(this.url, this.username, this.password, this.basicAuth, this.withCredentials, this.cacheTTL);
|
||||||
|
|
||||||
|
// Use custom format for template variables
|
||||||
|
this.replaceTemplateVars = _.partial(replaceTemplateVars, this.templateSrv);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////
|
||||||
|
// Datasource methods //
|
||||||
|
////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query panel data. Calls for each panel in dashboard.
|
||||||
|
* @param {Object} options Contains time range, targets and other info.
|
||||||
|
* @return {Object} Grafana metrics object with timeseries data for each target.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
_createClass(ZabbixAPIDatasource, [{
|
||||||
|
key: 'query',
|
||||||
|
value: function query(options) {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
var timeFrom = Math.ceil(dateMath.parse(options.range.from) / 1000);
|
||||||
|
var timeTo = Math.ceil(dateMath.parse(options.range.to) / 1000);
|
||||||
|
|
||||||
|
var useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000);
|
||||||
|
var useTrends = timeFrom <= useTrendsFrom && this.trends;
|
||||||
|
|
||||||
|
// Create request for each target
|
||||||
|
var promises = _.map(options.targets, function (target) {
|
||||||
|
// Prevent changes of original object
|
||||||
|
target = _.cloneDeep(target);
|
||||||
|
_this.replaceTargetVariables(target, options);
|
||||||
|
|
||||||
|
// Apply Time-related functions (timeShift(), etc)
|
||||||
|
var timeFunctions = bindFunctionDefs(target.functions, 'Time');
|
||||||
|
if (timeFunctions.length) {
|
||||||
|
var _sequence = sequence(timeFunctions)([timeFrom, timeTo]),
|
||||||
|
_sequence2 = _slicedToArray(_sequence, 2),
|
||||||
|
time_from = _sequence2[0],
|
||||||
|
time_to = _sequence2[1];
|
||||||
|
|
||||||
|
timeFrom = time_from;
|
||||||
|
timeTo = time_to;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metrics or Text query mode
|
||||||
|
if (target.mode !== 1) {
|
||||||
|
// Migrate old targets
|
||||||
|
target = migrations.migrate(target);
|
||||||
|
|
||||||
|
// Don't request undefined and hidden targets
|
||||||
|
if (target.hide || !target.group || !target.host || !target.item) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target.mode || target.mode === 0) {
|
||||||
|
return _this.queryNumericData(target, timeFrom, timeTo, useTrends);
|
||||||
|
} else if (target.mode === 2) {
|
||||||
|
return _this.queryTextData(target, timeFrom, timeTo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IT services mode
|
||||||
|
else if (target.mode === 1) {
|
||||||
|
// Don't show undefined and hidden targets
|
||||||
|
if (target.hide || !target.itservice || !target.slaProperty) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return _this.zabbix.getSLA(target.itservice.serviceid, timeFrom, timeTo).then(function (slaObject) {
|
||||||
|
return responseHandler.handleSLAResponse(target.itservice, target.slaProperty, slaObject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Data for panel (all targets)
|
||||||
|
return Promise.all(_.flatten(promises)).then(_.flatten).then(function (timeseries_data) {
|
||||||
|
return downsampleSeries(timeseries_data, options);
|
||||||
|
}).then(function (data) {
|
||||||
|
return { data: data };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'queryNumericData',
|
||||||
|
value: function queryNumericData(target, timeFrom, timeTo, useTrends) {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
itemtype: 'num'
|
||||||
|
};
|
||||||
|
return this.zabbix.getItemsFromTarget(target, options).then(function (items) {
|
||||||
|
var getHistoryPromise = void 0;
|
||||||
|
|
||||||
|
if (useTrends) {
|
||||||
|
(function () {
|
||||||
|
var valueType = _this2.getTrendValueType(target);
|
||||||
|
getHistoryPromise = _this2.zabbix.getTrend(items, timeFrom, timeTo).then(function (history) {
|
||||||
|
return responseHandler.handleTrends(history, items, valueType);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
} else {
|
||||||
|
// Use history
|
||||||
|
getHistoryPromise = _this2.zabbix.getHistory(items, timeFrom, timeTo).then(function (history) {
|
||||||
|
return responseHandler.handleHistory(history, items);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return getHistoryPromise.then(function (timeseries_data) {
|
||||||
|
return _this2.applyDataProcessingFunctions(timeseries_data, target);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getTrendValueType',
|
||||||
|
value: function getTrendValueType(target) {
|
||||||
|
// Find trendValue() function and get specified trend value
|
||||||
|
var trendFunctions = _.map(metricFunctions.getCategories()['Trends'], 'name');
|
||||||
|
var trendValueFunc = _.find(target.functions, function (func) {
|
||||||
|
return _.includes(trendFunctions, func.def.name);
|
||||||
|
});
|
||||||
|
return trendValueFunc ? trendValueFunc.params[0] : "avg";
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'applyDataProcessingFunctions',
|
||||||
|
value: function applyDataProcessingFunctions(timeseries_data, target) {
|
||||||
|
var transformFunctions = bindFunctionDefs(target.functions, 'Transform');
|
||||||
|
var aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate');
|
||||||
|
var filterFunctions = bindFunctionDefs(target.functions, 'Filter');
|
||||||
|
var aliasFunctions = bindFunctionDefs(target.functions, 'Alias');
|
||||||
|
|
||||||
|
// Apply transformation functions
|
||||||
|
timeseries_data = _.map(timeseries_data, function (timeseries) {
|
||||||
|
timeseries.datapoints = sequence(transformFunctions)(timeseries.datapoints);
|
||||||
|
return timeseries;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Apply filter functions
|
||||||
|
if (filterFunctions.length) {
|
||||||
|
timeseries_data = sequence(filterFunctions)(timeseries_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply aggregations
|
||||||
|
if (aggregationFunctions.length) {
|
||||||
|
(function () {
|
||||||
|
var dp = _.map(timeseries_data, 'datapoints');
|
||||||
|
dp = sequence(aggregationFunctions)(dp);
|
||||||
|
|
||||||
|
var aggFuncNames = _.map(metricFunctions.getCategories()['Aggregate'], 'name');
|
||||||
|
var lastAgg = _.findLast(target.functions, function (func) {
|
||||||
|
return _.includes(aggFuncNames, func.def.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
timeseries_data = [{
|
||||||
|
target: lastAgg.text,
|
||||||
|
datapoints: dp
|
||||||
|
}];
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply alias functions
|
||||||
|
_.forEach(timeseries_data, sequence(aliasFunctions));
|
||||||
|
|
||||||
|
// Apply Time-related functions (timeShift(), etc)
|
||||||
|
// Find timeShift() function and get specified trend value
|
||||||
|
this.applyTimeShiftFunction(timeseries_data, target);
|
||||||
|
|
||||||
|
return timeseries_data;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'applyTimeShiftFunction',
|
||||||
|
value: function applyTimeShiftFunction(timeseries_data, target) {
|
||||||
|
// Find timeShift() function and get specified interval
|
||||||
|
var timeShiftFunc = _.find(target.functions, function (func) {
|
||||||
|
return func.def.name === 'timeShift';
|
||||||
|
});
|
||||||
|
if (timeShiftFunc) {
|
||||||
|
(function () {
|
||||||
|
var shift = timeShiftFunc.params[0];
|
||||||
|
_.forEach(timeseries_data, function (series) {
|
||||||
|
series.datapoints = dataProcessor.unShiftTimeSeries(shift, series.datapoints);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'queryTextData',
|
||||||
|
value: function queryTextData(target, timeFrom, timeTo) {
|
||||||
|
var _this3 = this;
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
itemtype: 'text'
|
||||||
|
};
|
||||||
|
return this.zabbix.getItemsFromTarget(target, options).then(function (items) {
|
||||||
|
if (items.length) {
|
||||||
|
return _this3.zabbix.getHistory(items, timeFrom, timeTo).then(function (history) {
|
||||||
|
return responseHandler.convertHistory(history, items, false, function (point) {
|
||||||
|
var value = point.value;
|
||||||
|
|
||||||
|
// Regex-based extractor
|
||||||
|
if (target.textFilter) {
|
||||||
|
value = extractText(point.value, target.textFilter, target.useCaptureGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [value, point.clock * 1000];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'testDatasource',
|
||||||
|
value: function testDatasource() {
|
||||||
|
var _this4 = this;
|
||||||
|
|
||||||
|
var zabbixVersion = void 0;
|
||||||
|
return this.zabbix.getVersion().then(function (version) {
|
||||||
|
zabbixVersion = version;
|
||||||
|
return _this4.zabbix.login();
|
||||||
|
}).then(function () {
|
||||||
|
return {
|
||||||
|
status: "success",
|
||||||
|
title: "Success",
|
||||||
|
message: "Zabbix API version: " + zabbixVersion
|
||||||
|
};
|
||||||
|
}).catch(function (error) {
|
||||||
|
if (error instanceof ZabbixAPIError) {
|
||||||
|
return {
|
||||||
|
status: "error",
|
||||||
|
title: error.message,
|
||||||
|
message: error.data
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
status: "error",
|
||||||
|
title: "Connection failed",
|
||||||
|
message: "Could not connect to given url"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'metricFindQuery',
|
||||||
|
value: function metricFindQuery(query) {
|
||||||
|
var _this5 = this;
|
||||||
|
|
||||||
|
var result = void 0;
|
||||||
|
var parts = [];
|
||||||
|
|
||||||
|
// Split query. Query structure: group.host.app.item
|
||||||
|
_.each(query.split('.'), function (part) {
|
||||||
|
part = _this5.replaceTemplateVars(part, {});
|
||||||
|
|
||||||
|
// Replace wildcard to regex
|
||||||
|
if (part === '*') {
|
||||||
|
part = '/.*/';
|
||||||
|
}
|
||||||
|
parts.push(part);
|
||||||
|
});
|
||||||
|
var template = _.zipObject(['group', 'host', 'app', 'item'], parts);
|
||||||
|
|
||||||
|
// Get items
|
||||||
|
if (parts.length === 4) {
|
||||||
|
// Search for all items, even it's not belong to any application
|
||||||
|
if (template.app === '/.*/') {
|
||||||
|
template.app = '';
|
||||||
|
}
|
||||||
|
result = this.zabbix.getItems(template.group, template.host, template.app, template.item);
|
||||||
|
} else if (parts.length === 3) {
|
||||||
|
// Get applications
|
||||||
|
result = this.zabbix.getApps(template.group, template.host, template.app);
|
||||||
|
} else if (parts.length === 2) {
|
||||||
|
// Get hosts
|
||||||
|
result = this.zabbix.getHosts(template.group, template.host);
|
||||||
|
} else if (parts.length === 1) {
|
||||||
|
// Get groups
|
||||||
|
result = this.zabbix.getGroups(template.group);
|
||||||
|
} else {
|
||||||
|
result = Promise.resolve([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.then(function (metrics) {
|
||||||
|
return metrics.map(formatMetric);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'annotationQuery',
|
||||||
|
value: function annotationQuery(options) {
|
||||||
|
var _this6 = this;
|
||||||
|
|
||||||
|
var timeFrom = Math.ceil(dateMath.parse(options.rangeRaw.from) / 1000);
|
||||||
|
var timeTo = Math.ceil(dateMath.parse(options.rangeRaw.to) / 1000);
|
||||||
|
var annotation = options.annotation;
|
||||||
|
var showOkEvents = annotation.showOkEvents ? [0, 1] : 1;
|
||||||
|
|
||||||
|
// Show all triggers
|
||||||
|
var showTriggers = [0, 1];
|
||||||
|
|
||||||
|
var getTriggers = this.zabbix.getTriggers(this.replaceTemplateVars(annotation.group, {}), this.replaceTemplateVars(annotation.host, {}), this.replaceTemplateVars(annotation.application, {}), showTriggers);
|
||||||
|
|
||||||
|
return getTriggers.then(function (triggers) {
|
||||||
|
|
||||||
|
// Filter triggers by description
|
||||||
|
if (utils.isRegex(annotation.trigger)) {
|
||||||
|
triggers = _.filter(triggers, function (trigger) {
|
||||||
|
return utils.buildRegex(annotation.trigger).test(trigger.description);
|
||||||
|
});
|
||||||
|
} else if (annotation.trigger) {
|
||||||
|
triggers = _.filter(triggers, function (trigger) {
|
||||||
|
return trigger.description === annotation.trigger;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove events below the chose severity
|
||||||
|
triggers = _.filter(triggers, function (trigger) {
|
||||||
|
return Number(trigger.priority) >= Number(annotation.minseverity);
|
||||||
|
});
|
||||||
|
|
||||||
|
var objectids = _.map(triggers, 'triggerid');
|
||||||
|
return _this6.zabbix.getEvents(objectids, timeFrom, timeTo, showOkEvents).then(function (events) {
|
||||||
|
var indexedTriggers = _.keyBy(triggers, 'triggerid');
|
||||||
|
|
||||||
|
// Hide acknowledged events if option enabled
|
||||||
|
if (annotation.hideAcknowledged) {
|
||||||
|
events = _.filter(events, function (event) {
|
||||||
|
return !event.acknowledges.length;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return _.map(events, function (event) {
|
||||||
|
var tags = void 0;
|
||||||
|
if (annotation.showHostname) {
|
||||||
|
tags = _.map(event.hosts, 'name');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show event type (OK or Problem)
|
||||||
|
var title = Number(event.value) ? 'Problem' : 'OK';
|
||||||
|
|
||||||
|
var formatted_acknowledges = utils.formatAcknowledges(event.acknowledges);
|
||||||
|
return {
|
||||||
|
annotation: annotation,
|
||||||
|
time: event.clock * 1000,
|
||||||
|
title: title,
|
||||||
|
tags: tags,
|
||||||
|
text: indexedTriggers[event.objectid].description + formatted_acknowledges
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'replaceTargetVariables',
|
||||||
|
value: function replaceTargetVariables(target, options) {
|
||||||
|
var _this7 = this;
|
||||||
|
|
||||||
|
var parts = ['group', 'host', 'application', 'item'];
|
||||||
|
parts.forEach(function (p) {
|
||||||
|
if (target[p] && target[p].filter) {
|
||||||
|
target[p].filter = _this7.replaceTemplateVars(target[p].filter, options.scopedVars);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
target.textFilter = this.replaceTemplateVars(target.textFilter, options.scopedVars);
|
||||||
|
|
||||||
|
_.forEach(target.functions, function (func) {
|
||||||
|
func.params = func.params.map(function (param) {
|
||||||
|
if (typeof param === 'number') {
|
||||||
|
return +_this7.templateSrv.replace(param.toString(), options.scopedVars);
|
||||||
|
} else {
|
||||||
|
return _this7.templateSrv.replace(param, options.scopedVars);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixAPIDatasource;
|
||||||
|
}());
|
||||||
|
|
||||||
|
_export('ZabbixAPIDatasource', ZabbixAPIDatasource);
|
||||||
|
|
||||||
|
_export('zabbixTemplateFormat', zabbixTemplateFormat);
|
||||||
|
|
||||||
|
// Fix for backward compatibility with lodash 2.4
|
||||||
|
if (!_.includes) {
|
||||||
|
_.includes = _.contains;
|
||||||
|
}
|
||||||
|
if (!_.keyBy) {
|
||||||
|
_.keyBy = _.indexBy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=datasource.js.map
|
||||||
1
dist/datasource-zabbix/datasource.js.map
vendored
Normal file
107
dist/datasource-zabbix/img/zabbix_app_logo.svg
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.0"
|
||||||
|
id="Layer_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
width="100px"
|
||||||
|
height="100px"
|
||||||
|
viewBox="692 0 100 100"
|
||||||
|
style="enable-background:new 692 0 100 100;"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:version="0.91 r"
|
||||||
|
sodipodi:docname="zabbix_app_logo.svg"
|
||||||
|
enable-background="new"><metadata
|
||||||
|
id="metadata13"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs11"><linearGradient
|
||||||
|
id="SVGID_1_"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="2.6005001"
|
||||||
|
y1="65.475197"
|
||||||
|
x2="94.377701"
|
||||||
|
y2="30.245199"><stop
|
||||||
|
id="stop34"
|
||||||
|
style="stop-color:#58595B"
|
||||||
|
offset="0.2583" /><stop
|
||||||
|
id="stop32"
|
||||||
|
style="stop-color:#646C70"
|
||||||
|
offset="0.2917" /><stop
|
||||||
|
id="stop30"
|
||||||
|
style="stop-color:#6C8087"
|
||||||
|
offset="0.3398" /><stop
|
||||||
|
id="stop28"
|
||||||
|
style="stop-color:#6D8F9B"
|
||||||
|
offset="0.3927" /><stop
|
||||||
|
id="stop26"
|
||||||
|
style="stop-color:#689BAA"
|
||||||
|
offset="0.4499" /><stop
|
||||||
|
id="stop24"
|
||||||
|
style="stop-color:#5FA3B5"
|
||||||
|
offset="0.5128" /><stop
|
||||||
|
id="stop22"
|
||||||
|
style="stop-color:#53A8BD"
|
||||||
|
offset="0.5837" /><stop
|
||||||
|
id="stop20"
|
||||||
|
style="stop-color:#47ABC2"
|
||||||
|
offset="0.6674" /><stop
|
||||||
|
id="stop18"
|
||||||
|
style="stop-color:#3FAEC5"
|
||||||
|
offset="0.7759" /><stop
|
||||||
|
id="stop16"
|
||||||
|
style="stop-color:#3CAFC7"
|
||||||
|
offset="1" /><stop
|
||||||
|
id="stop14"
|
||||||
|
style="stop-color:#3BB0C9"
|
||||||
|
offset="1" /></linearGradient></defs><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1615"
|
||||||
|
inkscape:window-height="1026"
|
||||||
|
id="namedview9"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="4.285"
|
||||||
|
inkscape:cx="50.424685"
|
||||||
|
inkscape:cy="23.581186"
|
||||||
|
inkscape:window-x="65"
|
||||||
|
inkscape:window-y="24"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="g5194" /><style
|
||||||
|
type="text/css"
|
||||||
|
id="style3">
|
||||||
|
.st0{fill:#787878;}
|
||||||
|
</style><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="g5194"
|
||||||
|
inkscape:label="Zabbix BG Original"
|
||||||
|
style="display:inline"><rect
|
||||||
|
style="fill:#d40000;fill-opacity:1"
|
||||||
|
id="rect5196"
|
||||||
|
width="100"
|
||||||
|
height="100"
|
||||||
|
x="692"
|
||||||
|
y="0" /></g><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer6"
|
||||||
|
inkscape:label="Zabbix Original Z"
|
||||||
|
style="display:inline"><path
|
||||||
|
d="m 715.54426,16.689227 52.91147,0 0,6.87033 -42.58255,52.167008 43.62047,0 0,7.584207 -54.9873,0 0,-6.871516 42.58255,-52.166552 -41.54464,0 0,-7.583477 z"
|
||||||
|
style="display:inline;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||||
|
id="path4169-6"
|
||||||
|
inkscape:connector-curvature="0" /></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.5 KiB |
251
dist/datasource-zabbix/metric-function-editor.directive.js
vendored
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['angular', 'lodash', 'jquery'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var angular, _, $;
|
||||||
|
|
||||||
|
return {
|
||||||
|
setters: [function (_angular) {
|
||||||
|
angular = _angular.default;
|
||||||
|
}, function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}, function (_jquery) {
|
||||||
|
$ = _jquery.default;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
angular.module('grafana.directives').directive('metricFunctionEditor', function ($compile, templateSrv) {
|
||||||
|
|
||||||
|
var funcSpanTemplate = '<a ng-click="">{{func.def.name}}</a><span>(</span>';
|
||||||
|
var paramTemplate = '<input type="text" style="display:none"' + ' class="input-mini tight-form-func-param"></input>';
|
||||||
|
|
||||||
|
var funcControlsTemplate = '<div class="tight-form-func-controls">' + '<span class="pointer fa fa-arrow-left"></span>' + '<span class="pointer fa fa-question-circle"></span>' + '<span class="pointer fa fa-remove" ></span>' + '<span class="pointer fa fa-arrow-right"></span>' + '</div>';
|
||||||
|
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
link: function postLink($scope, elem) {
|
||||||
|
var $funcLink = $(funcSpanTemplate);
|
||||||
|
var $funcControls = $(funcControlsTemplate);
|
||||||
|
var ctrl = $scope.ctrl;
|
||||||
|
var func = $scope.func;
|
||||||
|
var funcDef = func.def;
|
||||||
|
var scheduledRelink = false;
|
||||||
|
var paramCountAtLink = 0;
|
||||||
|
|
||||||
|
function clickFuncParam(paramIndex) {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
|
||||||
|
var $link = $(this);
|
||||||
|
var $input = $link.next();
|
||||||
|
|
||||||
|
$input.val(func.params[paramIndex]);
|
||||||
|
$input.css('width', $link.width() + 16 + 'px');
|
||||||
|
|
||||||
|
$link.hide();
|
||||||
|
$input.show();
|
||||||
|
$input.focus();
|
||||||
|
$input.select();
|
||||||
|
|
||||||
|
var typeahead = $input.data('typeahead');
|
||||||
|
if (typeahead) {
|
||||||
|
$input.val('');
|
||||||
|
typeahead.lookup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduledRelinkIfNeeded() {
|
||||||
|
if (paramCountAtLink === func.params.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scheduledRelink) {
|
||||||
|
scheduledRelink = true;
|
||||||
|
setTimeout(function () {
|
||||||
|
relink();
|
||||||
|
scheduledRelink = false;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputBlur(paramIndex) {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
var $input = $(this);
|
||||||
|
var $link = $input.prev();
|
||||||
|
var newValue = $input.val();
|
||||||
|
|
||||||
|
if (newValue !== '' || func.def.params[paramIndex].optional) {
|
||||||
|
$link.html(templateSrv.highlightVariablesAsHtml(newValue));
|
||||||
|
|
||||||
|
func.updateParam($input.val(), paramIndex);
|
||||||
|
scheduledRelinkIfNeeded();
|
||||||
|
|
||||||
|
$scope.$apply(function () {
|
||||||
|
ctrl.targetChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.hide();
|
||||||
|
$link.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputKeyPress(paramIndex, e) {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
if (e.which === 13) {
|
||||||
|
inputBlur.call(this, paramIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputKeyDown() {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
this.style.width = (3 + this.value.length) * 8 + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTypeahead($input, paramIndex) {
|
||||||
|
$input.attr('data-provide', 'typeahead');
|
||||||
|
|
||||||
|
var options = funcDef.params[paramIndex].options;
|
||||||
|
if (funcDef.params[paramIndex].type === 'int' || funcDef.params[paramIndex].type === 'float') {
|
||||||
|
options = _.map(options, function (val) {
|
||||||
|
return val.toString();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$input.typeahead({
|
||||||
|
source: options,
|
||||||
|
minLength: 0,
|
||||||
|
items: 20,
|
||||||
|
updater: function updater(value) {
|
||||||
|
setTimeout(function () {
|
||||||
|
inputBlur.call($input[0], paramIndex);
|
||||||
|
}, 0);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var typeahead = $input.data('typeahead');
|
||||||
|
typeahead.lookup = function () {
|
||||||
|
this.query = this.$element.val() || '';
|
||||||
|
return this.process(this.source);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleFuncControls() {
|
||||||
|
var targetDiv = elem.closest('.tight-form');
|
||||||
|
|
||||||
|
if (elem.hasClass('show-function-controls')) {
|
||||||
|
elem.removeClass('show-function-controls');
|
||||||
|
targetDiv.removeClass('has-open-function');
|
||||||
|
$funcControls.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
elem.addClass('show-function-controls');
|
||||||
|
targetDiv.addClass('has-open-function');
|
||||||
|
|
||||||
|
$funcControls.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addElementsAndCompile() {
|
||||||
|
$funcControls.appendTo(elem);
|
||||||
|
$funcLink.appendTo(elem);
|
||||||
|
|
||||||
|
_.each(funcDef.params, function (param, index) {
|
||||||
|
if (param.optional && func.params.length <= index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index > 0) {
|
||||||
|
$('<span>, </span>').appendTo(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
var paramValue = templateSrv.highlightVariablesAsHtml(func.params[index]);
|
||||||
|
var $paramLink = $('<a ng-click="" class="graphite-func-param-link">' + paramValue + '</a>');
|
||||||
|
var $input = $(paramTemplate);
|
||||||
|
|
||||||
|
paramCountAtLink++;
|
||||||
|
|
||||||
|
$paramLink.appendTo(elem);
|
||||||
|
$input.appendTo(elem);
|
||||||
|
|
||||||
|
$input.blur(_.partial(inputBlur, index));
|
||||||
|
$input.keyup(inputKeyDown);
|
||||||
|
$input.keypress(_.partial(inputKeyPress, index));
|
||||||
|
$paramLink.click(_.partial(clickFuncParam, index));
|
||||||
|
|
||||||
|
if (funcDef.params[index].options) {
|
||||||
|
addTypeahead($input, index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('<span>)</span>').appendTo(elem);
|
||||||
|
|
||||||
|
$compile(elem.contents())($scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ifJustAddedFocusFistParam() {
|
||||||
|
if ($scope.func.added) {
|
||||||
|
$scope.func.added = false;
|
||||||
|
setTimeout(function () {
|
||||||
|
elem.find('.graphite-func-param-link').first().click();
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerFuncControlsToggle() {
|
||||||
|
$funcLink.click(toggleFuncControls);
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerFuncControlsActions() {
|
||||||
|
$funcControls.click(function (e) {
|
||||||
|
var $target = $(e.target);
|
||||||
|
if ($target.hasClass('fa-remove')) {
|
||||||
|
toggleFuncControls();
|
||||||
|
$scope.$apply(function () {
|
||||||
|
ctrl.removeFunction($scope.func);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($target.hasClass('fa-arrow-left')) {
|
||||||
|
$scope.$apply(function () {
|
||||||
|
_.move($scope.target.functions, $scope.$index, $scope.$index - 1);
|
||||||
|
ctrl.targetChanged();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($target.hasClass('fa-arrow-right')) {
|
||||||
|
$scope.$apply(function () {
|
||||||
|
_.move($scope.target.functions, $scope.$index, $scope.$index + 1);
|
||||||
|
ctrl.targetChanged();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($target.hasClass('fa-question-circle')) {
|
||||||
|
var docSite = "http://docs.grafana-zabbix.org/reference/functions/";
|
||||||
|
window.open(docSite + '#' + funcDef.name.toLowerCase(), '_blank');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function relink() {
|
||||||
|
elem.children().remove();
|
||||||
|
|
||||||
|
addElementsAndCompile();
|
||||||
|
ifJustAddedFocusFistParam();
|
||||||
|
registerFuncControlsToggle();
|
||||||
|
registerFuncControlsActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
relink();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=metric-function-editor.directive.js.map
|
||||||
1
dist/datasource-zabbix/metric-function-editor.directive.js.map
vendored
Normal file
315
dist/datasource-zabbix/metricFunctions.js
vendored
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['lodash', 'jquery'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _, $, _createClass, index, categories, FuncInstance;
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFuncDef(funcDef) {
|
||||||
|
funcDef.params = funcDef.params || [];
|
||||||
|
funcDef.defaultParams = funcDef.defaultParams || [];
|
||||||
|
|
||||||
|
if (funcDef.category) {
|
||||||
|
categories[funcDef.category].push(funcDef);
|
||||||
|
}
|
||||||
|
index[funcDef.name] = funcDef;
|
||||||
|
index[funcDef.shortName || funcDef.name] = funcDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform
|
||||||
|
|
||||||
|
function createFuncInstance(funcDef, params) {
|
||||||
|
if (_.isString(funcDef)) {
|
||||||
|
if (!index[funcDef]) {
|
||||||
|
throw { message: 'Method not found ' + name };
|
||||||
|
}
|
||||||
|
funcDef = index[funcDef];
|
||||||
|
}
|
||||||
|
return new FuncInstance(funcDef, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
_export('createFuncInstance', createFuncInstance);
|
||||||
|
|
||||||
|
function getFuncDef(name) {
|
||||||
|
return index[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
_export('getFuncDef', getFuncDef);
|
||||||
|
|
||||||
|
function getCategories() {
|
||||||
|
return categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
_export('getCategories', getCategories);
|
||||||
|
|
||||||
|
return {
|
||||||
|
setters: [function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}, function (_jquery) {
|
||||||
|
$ = _jquery.default;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
_createClass = function () {
|
||||||
|
function defineProperties(target, props) {
|
||||||
|
for (var i = 0; i < props.length; i++) {
|
||||||
|
var descriptor = props[i];
|
||||||
|
descriptor.enumerable = descriptor.enumerable || false;
|
||||||
|
descriptor.configurable = true;
|
||||||
|
if ("value" in descriptor) descriptor.writable = true;
|
||||||
|
Object.defineProperty(target, descriptor.key, descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (Constructor, protoProps, staticProps) {
|
||||||
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
||||||
|
if (staticProps) defineProperties(Constructor, staticProps);
|
||||||
|
return Constructor;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
index = [];
|
||||||
|
categories = {
|
||||||
|
Transform: [],
|
||||||
|
Aggregate: [],
|
||||||
|
Filter: [],
|
||||||
|
Trends: [],
|
||||||
|
Time: [],
|
||||||
|
Alias: []
|
||||||
|
};
|
||||||
|
addFuncDef({
|
||||||
|
name: 'groupBy',
|
||||||
|
category: 'Transform',
|
||||||
|
params: [{ name: 'interval', type: 'string' }, { name: 'function', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
|
||||||
|
defaultParams: ['1m', 'avg']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'scale',
|
||||||
|
category: 'Transform',
|
||||||
|
params: [{ name: 'factor', type: 'float', options: [100, 0.01, 10, -1] }],
|
||||||
|
defaultParams: [100]
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'delta',
|
||||||
|
category: 'Transform',
|
||||||
|
params: [],
|
||||||
|
defaultParams: []
|
||||||
|
});
|
||||||
|
|
||||||
|
// Aggregate
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'sumSeries',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [],
|
||||||
|
defaultParams: []
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'median',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [{ name: 'interval', type: 'string' }],
|
||||||
|
defaultParams: ['1m']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'average',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [{ name: 'interval', type: 'string' }],
|
||||||
|
defaultParams: ['1m']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'min',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [{ name: 'interval', type: 'string' }],
|
||||||
|
defaultParams: ['1m']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'max',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [{ name: 'interval', type: 'string' }],
|
||||||
|
defaultParams: ['1m']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'aggregateBy',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [{ name: 'interval', type: 'string' }, { name: 'function', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
|
||||||
|
defaultParams: ['1m', 'avg']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'top',
|
||||||
|
category: 'Filter',
|
||||||
|
params: [{ name: 'number', type: 'int' }, { name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
|
||||||
|
defaultParams: [5, 'avg']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'bottom',
|
||||||
|
category: 'Filter',
|
||||||
|
params: [{ name: 'number', type: 'int' }, { name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
|
||||||
|
defaultParams: [5, 'avg']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Trends
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'trendValue',
|
||||||
|
category: 'Trends',
|
||||||
|
params: [{ name: 'type', type: 'string', options: ['avg', 'min', 'max'] }],
|
||||||
|
defaultParams: ['avg']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Time
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'timeShift',
|
||||||
|
category: 'Time',
|
||||||
|
params: [{ name: 'interval', type: 'string', options: ['24h', '7d', '1M', '+24h', '-24h'] }],
|
||||||
|
defaultParams: ['24h']
|
||||||
|
});
|
||||||
|
|
||||||
|
//Alias
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'setAlias',
|
||||||
|
category: 'Alias',
|
||||||
|
params: [{ name: 'alias', type: 'string' }],
|
||||||
|
defaultParams: []
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'setAliasByRegex',
|
||||||
|
category: 'Alias',
|
||||||
|
params: [{ name: 'aliasByRegex', type: 'string' }],
|
||||||
|
defaultParams: []
|
||||||
|
});
|
||||||
|
|
||||||
|
_.each(categories, function (funcList, catName) {
|
||||||
|
categories[catName] = _.sortBy(funcList, 'name');
|
||||||
|
});
|
||||||
|
|
||||||
|
FuncInstance = function () {
|
||||||
|
function FuncInstance(funcDef, params) {
|
||||||
|
_classCallCheck(this, FuncInstance);
|
||||||
|
|
||||||
|
this.def = funcDef;
|
||||||
|
|
||||||
|
if (params) {
|
||||||
|
this.params = params;
|
||||||
|
} else {
|
||||||
|
// Create with default params
|
||||||
|
this.params = [];
|
||||||
|
this.params = funcDef.defaultParams.slice(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateText();
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(FuncInstance, [{
|
||||||
|
key: 'bindFunction',
|
||||||
|
value: function bindFunction(metricFunctions) {
|
||||||
|
var func = metricFunctions[this.def.name];
|
||||||
|
if (func) {
|
||||||
|
|
||||||
|
// Bind function arguments
|
||||||
|
var bindedFunc = func;
|
||||||
|
var param;
|
||||||
|
for (var i = 0; i < this.params.length; i++) {
|
||||||
|
param = this.params[i];
|
||||||
|
|
||||||
|
// Convert numeric params
|
||||||
|
if (this.def.params[i].type === 'int' || this.def.params[i].type === 'float') {
|
||||||
|
param = Number(param);
|
||||||
|
}
|
||||||
|
bindedFunc = _.partial(bindedFunc, param);
|
||||||
|
}
|
||||||
|
return bindedFunc;
|
||||||
|
} else {
|
||||||
|
throw { message: 'Method not found ' + this.def.name };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'render',
|
||||||
|
value: function render(metricExp) {
|
||||||
|
var str = this.def.name + '(';
|
||||||
|
var parameters = _.map(this.params, function (value, index) {
|
||||||
|
|
||||||
|
var paramType = this.def.params[index].type;
|
||||||
|
if (paramType === 'int' || paramType === 'float' || paramType === 'value_or_series' || paramType === 'boolean') {
|
||||||
|
return value;
|
||||||
|
} else if (paramType === 'int_or_interval' && $.isNumeric(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "'" + value + "'";
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
if (metricExp) {
|
||||||
|
parameters.unshift(metricExp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str + parameters.join(', ') + ')';
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: '_hasMultipleParamsInString',
|
||||||
|
value: function _hasMultipleParamsInString(strValue, index) {
|
||||||
|
if (strValue.indexOf(',') === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.def.params[index + 1] && this.def.params[index + 1].optional;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'updateParam',
|
||||||
|
value: function updateParam(strValue, index) {
|
||||||
|
// handle optional parameters
|
||||||
|
// if string contains ',' and next param is optional, split and update both
|
||||||
|
if (this._hasMultipleParamsInString(strValue, index)) {
|
||||||
|
_.each(strValue.split(','), function (partVal, idx) {
|
||||||
|
this.updateParam(partVal.trim(), idx);
|
||||||
|
}, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strValue === '' && this.def.params[index].optional) {
|
||||||
|
this.params.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
this.params[index] = strValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateText();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'updateText',
|
||||||
|
value: function updateText() {
|
||||||
|
if (this.params.length === 0) {
|
||||||
|
this.text = this.def.name + '()';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = this.def.name + '(';
|
||||||
|
text += this.params.join(', ');
|
||||||
|
text += ')';
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return FuncInstance;
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=metricFunctions.js.map
|
||||||
1
dist/datasource-zabbix/metricFunctions.js.map
vendored
Normal file
55
dist/datasource-zabbix/migrations.js
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
System.register([], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query format migration.
|
||||||
|
* This module can detect query format version and make migration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isGrafana2target(target) {
|
||||||
|
if (!target.mode || target.mode === 0 || target.mode === 2) {
|
||||||
|
if ((target.hostFilter || target.itemFilter || target.downsampleFunction || target.host && target.host.host) && target.item.filter === undefined && target.host.filter === undefined) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_export("isGrafana2target", isGrafana2target);
|
||||||
|
|
||||||
|
function migrateFrom2To3version(target) {
|
||||||
|
target.group.filter = target.group.name === "*" ? "/.*/" : target.group.name;
|
||||||
|
target.host.filter = target.host.name === "*" ? convertToRegex(target.hostFilter) : target.host.name;
|
||||||
|
target.application.filter = target.application.name === "*" ? "" : target.application.name;
|
||||||
|
target.item.filter = target.item.name === "All" ? convertToRegex(target.itemFilter) : target.item.name;
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
_export("migrateFrom2To3version", migrateFrom2To3version);
|
||||||
|
|
||||||
|
function migrate(target) {
|
||||||
|
if (isGrafana2target(target)) {
|
||||||
|
return migrateFrom2To3version(target);
|
||||||
|
} else {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_export("migrate", migrate);
|
||||||
|
|
||||||
|
function convertToRegex(str) {
|
||||||
|
if (str) {
|
||||||
|
return '/' + str + '/';
|
||||||
|
} else {
|
||||||
|
return '/.*/';
|
||||||
|
}
|
||||||
|
}return {
|
||||||
|
setters: [],
|
||||||
|
execute: function () {}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=migrations.js.map
|
||||||
1
dist/datasource-zabbix/migrations.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["../../src/datasource-zabbix/migrations.js"],"names":["isGrafana2target","target","mode","hostFilter","itemFilter","downsampleFunction","host","item","filter","undefined","migrateFrom2To3version","group","name","convertToRegex","application","migrate","str"],"mappings":";;;;;AAAA;;;;;AAKO,WAASA,gBAAT,CAA0BC,MAA1B,EAAkC;AACvC,QAAI,CAACA,OAAOC,IAAR,IAAgBD,OAAOC,IAAP,KAAgB,CAAhC,IAAqCD,OAAOC,IAAP,KAAgB,CAAzD,EAA4D;AAC1D,UAAI,CAACD,OAAOE,UAAP,IAAqBF,OAAOG,UAA5B,IAA0CH,OAAOI,kBAAjD,IACAJ,OAAOK,IAAP,IAAeL,OAAOK,IAAP,CAAYA,IAD5B,KAECL,OAAOM,IAAP,CAAYC,MAAZ,KAAuBC,SAAvB,IAAoCR,OAAOK,IAAP,CAAYE,MAAZ,KAAuBC,SAFhE,EAE4E;AAC1E,eAAO,IAAP;AACD,OAJD,MAIO;AACL,eAAO,KAAP;AACD;AACF,KARD,MAQO;AACL,aAAO,KAAP;AACD;AACF;;8BAZeT,gB;;AAcT,WAASU,sBAAT,CAAgCT,MAAhC,EAAwC;AAC7CA,WAAOU,KAAP,CAAaH,MAAb,GAAsBP,OAAOU,KAAP,CAAaC,IAAb,KAAsB,GAAtB,GAA4B,MAA5B,GAAqCX,OAAOU,KAAP,CAAaC,IAAxE;AACAX,WAAOK,IAAP,CAAYE,MAAZ,GAAqBP,OAAOK,IAAP,CAAYM,IAAZ,KAAqB,GAArB,GAA2BC,eAAeZ,OAAOE,UAAtB,CAA3B,GAA+DF,OAAOK,IAAP,CAAYM,IAAhG;AACAX,WAAOa,WAAP,CAAmBN,MAAnB,GAA4BP,OAAOa,WAAP,CAAmBF,IAAnB,KAA4B,GAA5B,GAAkC,EAAlC,GAAuCX,OAAOa,WAAP,CAAmBF,IAAtF;AACAX,WAAOM,IAAP,CAAYC,MAAZ,GAAqBP,OAAOM,IAAP,CAAYK,IAAZ,KAAqB,KAArB,GAA6BC,eAAeZ,OAAOG,UAAtB,CAA7B,GAAiEH,OAAOM,IAAP,CAAYK,IAAlG;AACA,WAAOX,MAAP;AACD;oCANeS,sB;;AAQT,WAASK,OAAT,CAAiBd,MAAjB,EAAyB;AAC9B,QAAID,iBAAiBC,MAAjB,CAAJ,EAA8B;AAC5B,aAAOS,uBAAuBT,MAAvB,CAAP;AACD,KAFD,MAEO;AACL,aAAOA,MAAP;AACD;AACF;;qBANec,O;;AAQhB,WAASF,cAAT,CAAwBG,GAAxB,EAA6B;AAC3B,QAAIA,GAAJ,EAAS;AACP,aAAO,MAAMA,GAAN,GAAY,GAAnB;AACD,KAFD,MAEO;AACL,aAAO,MAAP;AACD;AACF,G","file":"migrations.js","sourcesContent":["/**\n * Query format migration.\n * This module can detect query format version and make migration.\n */\n\nexport function isGrafana2target(target) {\n if (!target.mode || target.mode === 0 || target.mode === 2) {\n if ((target.hostFilter || target.itemFilter || target.downsampleFunction ||\n (target.host && target.host.host)) &&\n (target.item.filter === undefined && target.host.filter === undefined)) {\n return true;\n } else {\n return false;\n }\n } else {\n return false;\n }\n}\n\nexport function migrateFrom2To3version(target) {\n target.group.filter = target.group.name === \"*\" ? \"/.*/\" : target.group.name;\n target.host.filter = target.host.name === \"*\" ? convertToRegex(target.hostFilter) : target.host.name;\n target.application.filter = target.application.name === \"*\" ? \"\" : target.application.name;\n target.item.filter = target.item.name === \"All\" ? convertToRegex(target.itemFilter) : target.item.name;\n return target;\n}\n\nexport function migrate(target) {\n if (isGrafana2target(target)) {\n return migrateFrom2To3version(target);\n } else {\n return target;\n }\n}\n\nfunction convertToRegex(str) {\n if (str) {\n return '/' + str + '/';\n } else {\n return '/.*/';\n }\n}\n"]}
|
||||||
51
dist/datasource-zabbix/module.js
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['./datasource', './query.controller'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var ZabbixAPIDatasource, ZabbixQueryController, ZabbixConfigController, ZabbixQueryOptionsController, ZabbixAnnotationsQueryController;
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setters: [function (_datasource) {
|
||||||
|
ZabbixAPIDatasource = _datasource.ZabbixAPIDatasource;
|
||||||
|
}, function (_queryController) {
|
||||||
|
ZabbixQueryController = _queryController.ZabbixQueryController;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
_export('ConfigCtrl', ZabbixConfigController = function ZabbixConfigController() {
|
||||||
|
_classCallCheck(this, ZabbixConfigController);
|
||||||
|
});
|
||||||
|
|
||||||
|
ZabbixConfigController.templateUrl = 'datasource-zabbix/partials/config.html';
|
||||||
|
|
||||||
|
_export('QueryOptionsCtrl', ZabbixQueryOptionsController = function ZabbixQueryOptionsController() {
|
||||||
|
_classCallCheck(this, ZabbixQueryOptionsController);
|
||||||
|
});
|
||||||
|
|
||||||
|
ZabbixQueryOptionsController.templateUrl = 'datasource-zabbix/partials/query.options.html';
|
||||||
|
|
||||||
|
_export('AnnotationsQueryCtrl', ZabbixAnnotationsQueryController = function ZabbixAnnotationsQueryController() {
|
||||||
|
_classCallCheck(this, ZabbixAnnotationsQueryController);
|
||||||
|
});
|
||||||
|
|
||||||
|
ZabbixAnnotationsQueryController.templateUrl = 'datasource-zabbix/partials/annotations.editor.html';
|
||||||
|
|
||||||
|
_export('Datasource', ZabbixAPIDatasource);
|
||||||
|
|
||||||
|
_export('ConfigCtrl', ZabbixConfigController);
|
||||||
|
|
||||||
|
_export('QueryCtrl', ZabbixQueryController);
|
||||||
|
|
||||||
|
_export('QueryOptionsCtrl', ZabbixQueryOptionsController);
|
||||||
|
|
||||||
|
_export('AnnotationsQueryCtrl', ZabbixAnnotationsQueryController);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=module.js.map
|
||||||
1
dist/datasource-zabbix/module.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["../../src/datasource-zabbix/module.js"],"names":["ZabbixAPIDatasource","ZabbixQueryController","ZabbixConfigController","templateUrl","ZabbixQueryOptionsController","ZabbixAnnotationsQueryController"],"mappings":";;;;;;;;;;;;;;;AAAQA,yB,eAAAA,mB;;AACAC,2B,oBAAAA,qB;;;4BAEFC,sB;;;;AACNA,6BAAuBC,WAAvB,GAAqC,wCAArC;;kCAEMC,4B;;;;AACNA,mCAA6BD,WAA7B,GAA2C,+CAA3C;;sCAEME,gC;;;;AACNA,uCAAiCF,WAAjC,GAA+C,oDAA/C;;4BAGEH,mB;;4BACAE,sB;;2BACAD,qB;;kCACAG,4B;;sCACAC,gC","file":"module.js","sourcesContent":["import {ZabbixAPIDatasource} from './datasource';\nimport {ZabbixQueryController} from './query.controller';\n\nclass ZabbixConfigController {}\nZabbixConfigController.templateUrl = 'datasource-zabbix/partials/config.html';\n\nclass ZabbixQueryOptionsController {}\nZabbixQueryOptionsController.templateUrl = 'datasource-zabbix/partials/query.options.html';\n\nclass ZabbixAnnotationsQueryController {}\nZabbixAnnotationsQueryController.templateUrl = 'datasource-zabbix/partials/annotations.editor.html';\n\nexport {\n ZabbixAPIDatasource as Datasource,\n ZabbixConfigController as ConfigCtrl,\n ZabbixQueryController as QueryCtrl,\n ZabbixQueryOptionsController as QueryOptionsCtrl,\n ZabbixAnnotationsQueryController as AnnotationsQueryCtrl\n};\n"]}
|
||||||
65
dist/datasource-zabbix/partials/annotations.editor.html
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<div class="gf-form-group">
|
||||||
|
<h6>Filter Triggers</h6>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-10">Group</span>
|
||||||
|
<input type="text"
|
||||||
|
class="gf-form-input max-width-16"
|
||||||
|
ng-model="ctrl.annotation.group">
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-10">Host</span>
|
||||||
|
<input type="text"
|
||||||
|
class="gf-form-input max-width-16"
|
||||||
|
ng-model="ctrl.annotation.host">
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-10">Application</span>
|
||||||
|
<input type="text"
|
||||||
|
class="gf-form-input max-width-16"
|
||||||
|
ng-model="ctrl.annotation.application">
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-10">Trigger</span>
|
||||||
|
<input type="text"
|
||||||
|
class="gf-form-input max-width-16"
|
||||||
|
ng-model="ctrl.annotation.trigger">
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form-group">
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-10">Minimum severity</span>
|
||||||
|
<div class="gf-form-select-wrapper">
|
||||||
|
<select class="gf-form-input gf-size-auto"
|
||||||
|
ng-init='ctrl.annotation.minseverity = ctrl.annotation.minseverity || 0'
|
||||||
|
ng-model='ctrl.annotation.minseverity'
|
||||||
|
ng-options="v as k for (k, v) in {
|
||||||
|
'Not classified': 0,
|
||||||
|
'Information': 1,
|
||||||
|
'Warning': 2,
|
||||||
|
'Average': 3,
|
||||||
|
'High': 4,
|
||||||
|
'Disaster': 5
|
||||||
|
}"
|
||||||
|
ng-change="render()">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form-group">
|
||||||
|
<h6>Options</h6>
|
||||||
|
<div class="gf-form">
|
||||||
|
<editor-checkbox text="Show OK events" model="ctrl.annotation.showOkEvents"></editor-checkbox>
|
||||||
|
<editor-checkbox text="Hide acknowledged events" model="ctrl.annotation.hideAcknowledged"></editor-checkbox>
|
||||||
|
<editor-checkbox text="Show hostname" model="ctrl.annotation.showHostname"></editor-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
60
dist/datasource-zabbix/partials/config.html
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<datasource-http-settings current="ctrl.current">
|
||||||
|
</datasource-http-settings>
|
||||||
|
|
||||||
|
<div class="gf-form-group">
|
||||||
|
<h3 class="page-heading">Zabbix API details</h3>
|
||||||
|
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-7">
|
||||||
|
Username
|
||||||
|
</span>
|
||||||
|
<input class="gf-form-input max-width-21"
|
||||||
|
type="text"
|
||||||
|
ng-model='ctrl.current.jsonData.username'
|
||||||
|
placeholder="user"
|
||||||
|
required>
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-7">
|
||||||
|
Password
|
||||||
|
</span>
|
||||||
|
<input class="gf-form-input max-width-21"
|
||||||
|
type="password"
|
||||||
|
ng-model='ctrl.current.jsonData.password'
|
||||||
|
placeholder="password">
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label width-7">Trends</label>
|
||||||
|
</div>
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label="Enable"
|
||||||
|
checked="ctrl.current.jsonData.trends" switch-class="max-width-6">
|
||||||
|
</gf-form-switch>
|
||||||
|
<div class="gf-form" ng-if="ctrl.current.jsonData.trends">
|
||||||
|
<span class="gf-form-label width-7">
|
||||||
|
Use from
|
||||||
|
</span>
|
||||||
|
<input class="gf-form-input max-width-5"
|
||||||
|
type="text"
|
||||||
|
ng-model='ctrl.current.jsonData.trendsFrom'
|
||||||
|
placeholder="7d">
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-12">
|
||||||
|
Cache update interval
|
||||||
|
</span>
|
||||||
|
<input class="gf-form-input max-width-4"
|
||||||
|
type="text"
|
||||||
|
ng-model='ctrl.current.jsonData.cacheTTL'
|
||||||
|
placeholder="1h">
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
170
dist/datasource-zabbix/partials/query.editor.html
vendored
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
<query-editor-row query-ctrl="ctrl" can-collapse="false">
|
||||||
|
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form max-width-20">
|
||||||
|
<label class="gf-form-label width-7">Query Mode</label>
|
||||||
|
<div class="gf-form-select-wrapper max-width-20">
|
||||||
|
<select class="gf-form-input"
|
||||||
|
ng-change="ctrl.switchEditorMode(ctrl.target.mode)"
|
||||||
|
ng-model="ctrl.target.mode"
|
||||||
|
ng-options="v.mode as v.text for (k, v) in ctrl.editorModes">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form gf-form--grow">
|
||||||
|
<div class="gf-form-label gf-form-label--grow"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- IT Service editor -->
|
||||||
|
<div class="gf-form-inline" ng-show="ctrl.target.mode == 1">
|
||||||
|
<div class="gf-form max-width-20">
|
||||||
|
<label class="gf-form-label query-keyword width-7">IT Service</label>
|
||||||
|
<div class="gf-form-select-wrapper max-width-20">
|
||||||
|
<select class="gf-form-input"
|
||||||
|
ng-change="ctrl.selectITService()"
|
||||||
|
ng-model="ctrl.target.itservice"
|
||||||
|
bs-tooltip="ctrl.target.itservice.name.length > 25 ? ctrl.target.itservice.name : ''"
|
||||||
|
ng-options="itservice.name for itservice in ctrl.itserviceList track by itservice.name">
|
||||||
|
<option value="">-- Select IT service --</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label query-keyword">IT service property</label>
|
||||||
|
<div class="gf-form-select-wrapper">
|
||||||
|
<select class="gf-form-input"
|
||||||
|
ng-change="ctrl.selectITService()"
|
||||||
|
ng-model="ctrl.target.slaProperty"
|
||||||
|
ng-options="slaProperty.name for slaProperty in ctrl.slaPropertyList track by slaProperty.name">
|
||||||
|
<option value="">-- Property --</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form gf-form--grow">
|
||||||
|
<div class="gf-form-label gf-form-label--grow"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form-inline" ng-hide="ctrl.target.mode == 1">
|
||||||
|
<!-- Select Group -->
|
||||||
|
<div class="gf-form max-width-20">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Group</label>
|
||||||
|
<input type="text"
|
||||||
|
ng-model="ctrl.target.group.filter"
|
||||||
|
bs-typeahead="ctrl.getGroupNames"
|
||||||
|
ng-blur="ctrl.onTargetBlur()"
|
||||||
|
data-min-length=0
|
||||||
|
data-items=100
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-class="{
|
||||||
|
'zbx-variable': ctrl.isVariable(ctrl.target.group.filter),
|
||||||
|
'zbx-regex': ctrl.isRegex(ctrl.target.group.filter)
|
||||||
|
}"></input>
|
||||||
|
</div>
|
||||||
|
<!-- Select Host -->
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Host</label>
|
||||||
|
<input type="text"
|
||||||
|
ng-model="ctrl.target.host.filter"
|
||||||
|
bs-typeahead="ctrl.getHostNames"
|
||||||
|
ng-blur="ctrl.onTargetBlur()"
|
||||||
|
data-min-length=0
|
||||||
|
data-items=100
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-class="{
|
||||||
|
'zbx-variable': ctrl.isVariable(ctrl.target.host.filter),
|
||||||
|
'zbx-regex': ctrl.isRegex(ctrl.target.host.filter)
|
||||||
|
}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form gf-form--grow">
|
||||||
|
<div class="gf-form-label gf-form-label--grow"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form-inline" ng-hide="ctrl.target.mode == 1">
|
||||||
|
<!-- Select Application -->
|
||||||
|
<div class="gf-form max-width-20">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Application</label>
|
||||||
|
<input type="text"
|
||||||
|
ng-model="ctrl.target.application.filter"
|
||||||
|
bs-typeahead="ctrl.getApplicationNames"
|
||||||
|
ng-blur="ctrl.onTargetBlur()"
|
||||||
|
data-min-length=0
|
||||||
|
data-items=100
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-class="{
|
||||||
|
'zbx-variable': ctrl.isVariable(ctrl.target.application.filter),
|
||||||
|
'zbx-regex': ctrl.isRegex(ctrl.target.application.filter)
|
||||||
|
}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Select Item -->
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Item</label>
|
||||||
|
<input type="text"
|
||||||
|
ng-model="ctrl.target.item.filter"
|
||||||
|
bs-typeahead="ctrl.getItemNames"
|
||||||
|
ng-blur="ctrl.onTargetBlur()"
|
||||||
|
data-min-length=0
|
||||||
|
data-items=100
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-class="{
|
||||||
|
'zbx-variable': ctrl.isVariable(ctrl.target.item.filter),
|
||||||
|
'zbx-regex': ctrl.isRegex(ctrl.target.item.filter)
|
||||||
|
}">
|
||||||
|
</div>
|
||||||
|
<div class="gf-form gf-form--grow">
|
||||||
|
<label class="gf-form-label gf-form-label--grow">
|
||||||
|
<a ng-click="ctrl.toggleQueryOptions()">
|
||||||
|
<i class="fa fa-caret-down" ng-show="ctrl.showQueryOptions"></i>
|
||||||
|
<i class="fa fa-caret-right" ng-hide="ctrl.showQueryOptions"></i>
|
||||||
|
{{ctrl.queryOptionsText}}
|
||||||
|
</a>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Query options -->
|
||||||
|
<div class="gf-form-group" ng-if="ctrl.showQueryOptions">
|
||||||
|
<div class="gf-form offset-width-7">
|
||||||
|
<gf-form-switch class="gf-form" ng-hide="ctrl.target.mode == 2"
|
||||||
|
label="Show disabled items"
|
||||||
|
checked="ctrl.target.options.showDisabledItems"
|
||||||
|
on-change="ctrl.onQueryOptionChange()">
|
||||||
|
</gf-form-switch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Metric processing functions -->
|
||||||
|
<div class="gf-form-inline" ng-hide="ctrl.target.mode">
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Functions</label>
|
||||||
|
<div ng-repeat="func in ctrl.target.functions" class="gf-form-label query-part" metric-function-editor></div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form dropdown" add-metric-function>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form gf-form--grow">
|
||||||
|
<div class="gf-form-label gf-form-label--grow"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Text mode options -->
|
||||||
|
<div class="gf-form-inline" ng-show="ctrl.target.mode == 2">
|
||||||
|
<!-- Text metric regex -->
|
||||||
|
<div class="gf-form max-width-20">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Text filter</label>
|
||||||
|
<input type="text"
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-model="ctrl.target.textFilter"
|
||||||
|
spellcheck='false'
|
||||||
|
placeholder="Text filter (regex)"
|
||||||
|
ng-blur="ctrl.onTargetBlur()">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<gf-form-switch class="gf-form" label="Use capture groups" checked="ctrl.target.useCaptureGroups" on-change="ctrl.onTargetBlur()">
|
||||||
|
</gf-form-switch>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</query-editor-row>
|
||||||
88
dist/datasource-zabbix/partials/query.options.html
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<section class="grafana-metric-options gf-form-group">
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form max-width-15">
|
||||||
|
<span class="gf-form-label">Max data points</span>
|
||||||
|
<input type="text"
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-model="ctrl.panelCtrl.panel.maxDataPoints"
|
||||||
|
bs-tooltip="'Override max data points, automatically set to graph width in pixels.'"
|
||||||
|
data-placement="right"
|
||||||
|
ng-model-onblur ng-change="ctrl.panelCtrl.refresh()"
|
||||||
|
spellcheck='false'
|
||||||
|
placeholder="auto">
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-10">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
|
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||||
|
Max data points
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<span class="gf-form-label width-10">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
|
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(2);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||||
|
IT services
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<span class="gf-form-label width-12">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
|
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||||
|
IT service property
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<span class="gf-form-label width-8">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
|
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(4)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||||
|
Text filter
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="editor-row">
|
||||||
|
<div class="pull-left">
|
||||||
|
|
||||||
|
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 1">
|
||||||
|
<h5>Max data points</h5>
|
||||||
|
<ul>
|
||||||
|
<li>Grafana-Zabbix plugin uses maxDataPoints parameter to consolidate the real number of values down to this
|
||||||
|
number
|
||||||
|
</li>
|
||||||
|
<li>If there are more real values, then by default they will be consolidated using averages</li>
|
||||||
|
<li>This could hide real peaks and max values in your series</li>
|
||||||
|
<li>Point consolidation will effect series legend values (min,max,total,current)</li>
|
||||||
|
<li>If you override maxDataPoint and set a high value performance can be severely effected</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 2">
|
||||||
|
<h5>IT services</h5>
|
||||||
|
<ul>
|
||||||
|
<li>Select "IT services" in targets menu to activate IT services mode.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 3">
|
||||||
|
<h5>IT service property</h5>
|
||||||
|
<ul>
|
||||||
|
<li>Zabbix returns the following availability information about IT service</li>
|
||||||
|
<li>Status - current status of the IT service</li>
|
||||||
|
<li>SLA - SLA for the given time interval</li>
|
||||||
|
<li>OK time - time the service was in OK state, in seconds</li>
|
||||||
|
<li>Problem time - time the service was in problem state, in seconds</li>
|
||||||
|
<li>Down time - time the service was in scheduled downtime, in seconds</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 4">
|
||||||
|
<h5>Text filter</h5>
|
||||||
|
<ul>
|
||||||
|
<li>Use regex to extract a part of the returned value.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
19
dist/datasource-zabbix/plugin.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"type": "datasource",
|
||||||
|
"name": "Zabbix",
|
||||||
|
"id": "alexanderzobnin-zabbix-datasource",
|
||||||
|
|
||||||
|
"metrics": true,
|
||||||
|
"annotations": true,
|
||||||
|
|
||||||
|
"info": {
|
||||||
|
"author": {
|
||||||
|
"name": "Alexander Zobnin",
|
||||||
|
"url": "https://github.com/alexanderzobnin/grafana-zabbix"
|
||||||
|
},
|
||||||
|
"logos": {
|
||||||
|
"small": "img/zabbix_app_logo.svg",
|
||||||
|
"large": "img/zabbix_app_logo.svg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
376
dist/datasource-zabbix/query.controller.js
vendored
Normal file
@@ -0,0 +1,376 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['app/plugins/sdk', 'angular', 'lodash', './utils', './metricFunctions', './migrations', './add-metric-function.directive', './metric-function-editor.directive', './css/query-editor.css!'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var QueryCtrl, angular, _, utils, metricFunctions, migrations, _createClass, ZabbixQueryController;
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _possibleConstructorReturn(self, call) {
|
||||||
|
if (!self) {
|
||||||
|
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
||||||
|
}
|
||||||
|
|
||||||
|
return call && (typeof call === "object" || typeof call === "function") ? call : self;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _inherits(subClass, superClass) {
|
||||||
|
if (typeof superClass !== "function" && superClass !== null) {
|
||||||
|
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
||||||
|
constructor: {
|
||||||
|
value: subClass,
|
||||||
|
enumerable: false,
|
||||||
|
writable: true,
|
||||||
|
configurable: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get list of metric names for bs-typeahead directive
|
||||||
|
function getMetricNames(scope, metricList) {
|
||||||
|
return _.uniq(_.map(scope.metric[metricList], 'name'));
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
setters: [function (_appPluginsSdk) {
|
||||||
|
QueryCtrl = _appPluginsSdk.QueryCtrl;
|
||||||
|
}, function (_angular) {
|
||||||
|
angular = _angular.default;
|
||||||
|
}, function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}, function (_utils) {
|
||||||
|
utils = _utils;
|
||||||
|
}, function (_metricFunctions) {
|
||||||
|
metricFunctions = _metricFunctions;
|
||||||
|
}, function (_migrations) {
|
||||||
|
migrations = _migrations;
|
||||||
|
}, function (_addMetricFunctionDirective) {}, function (_metricFunctionEditorDirective) {}, function (_cssQueryEditorCss) {}],
|
||||||
|
execute: function () {
|
||||||
|
_createClass = function () {
|
||||||
|
function defineProperties(target, props) {
|
||||||
|
for (var i = 0; i < props.length; i++) {
|
||||||
|
var descriptor = props[i];
|
||||||
|
descriptor.enumerable = descriptor.enumerable || false;
|
||||||
|
descriptor.configurable = true;
|
||||||
|
if ("value" in descriptor) descriptor.writable = true;
|
||||||
|
Object.defineProperty(target, descriptor.key, descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (Constructor, protoProps, staticProps) {
|
||||||
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
||||||
|
if (staticProps) defineProperties(Constructor, staticProps);
|
||||||
|
return Constructor;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
_export('ZabbixQueryController', ZabbixQueryController = function (_QueryCtrl) {
|
||||||
|
_inherits(ZabbixQueryController, _QueryCtrl);
|
||||||
|
|
||||||
|
// ZabbixQueryCtrl constructor
|
||||||
|
function ZabbixQueryController($scope, $injector, $rootScope, $sce, templateSrv) {
|
||||||
|
_classCallCheck(this, ZabbixQueryController);
|
||||||
|
|
||||||
|
var _this = _possibleConstructorReturn(this, (ZabbixQueryController.__proto__ || Object.getPrototypeOf(ZabbixQueryController)).call(this, $scope, $injector));
|
||||||
|
|
||||||
|
_this.zabbix = _this.datasource.zabbix;
|
||||||
|
|
||||||
|
// Use custom format for template variables
|
||||||
|
_this.replaceTemplateVars = _this.datasource.replaceTemplateVars;
|
||||||
|
_this.templateSrv = templateSrv;
|
||||||
|
|
||||||
|
_this.editorModes = {
|
||||||
|
0: { value: 'num', text: 'Metrics', mode: 0 },
|
||||||
|
1: { value: 'itservice', text: 'IT Services', mode: 1 },
|
||||||
|
2: { value: 'text', text: 'Text', mode: 2 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map functions for bs-typeahead
|
||||||
|
_this.getGroupNames = _.partial(getMetricNames, _this, 'groupList');
|
||||||
|
_this.getHostNames = _.partial(getMetricNames, _this, 'hostList');
|
||||||
|
_this.getApplicationNames = _.partial(getMetricNames, _this, 'appList');
|
||||||
|
_this.getItemNames = _.partial(getMetricNames, _this, 'itemList');
|
||||||
|
|
||||||
|
// Update metric suggestion when template variable was changed
|
||||||
|
$rootScope.$on('template-variable-value-updated', function () {
|
||||||
|
return _this.onVariableChange();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update metrics when item selected from dropdown
|
||||||
|
$scope.$on('typeahead-updated', function () {
|
||||||
|
_this.onTargetBlur();
|
||||||
|
});
|
||||||
|
|
||||||
|
_this.init = function () {
|
||||||
|
var target = this.target;
|
||||||
|
|
||||||
|
// Migrate old targets
|
||||||
|
target = migrations.migrate(target);
|
||||||
|
|
||||||
|
var scopeDefaults = {
|
||||||
|
metric: {},
|
||||||
|
oldTarget: _.cloneDeep(this.target),
|
||||||
|
queryOptionsText: this.renderQueryOptionsText()
|
||||||
|
};
|
||||||
|
_.defaults(this, scopeDefaults);
|
||||||
|
|
||||||
|
// Load default values
|
||||||
|
var targetDefaults = {
|
||||||
|
mode: 0,
|
||||||
|
group: { filter: "" },
|
||||||
|
host: { filter: "" },
|
||||||
|
application: { filter: "" },
|
||||||
|
item: { filter: "" },
|
||||||
|
functions: [],
|
||||||
|
options: {
|
||||||
|
showDisabledItems: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_.defaults(target, targetDefaults);
|
||||||
|
|
||||||
|
// Create function instances from saved JSON
|
||||||
|
target.functions = _.map(target.functions, function (func) {
|
||||||
|
return metricFunctions.createFuncInstance(func.def, func.params);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (target.mode === 0 || target.mode === 2) {
|
||||||
|
|
||||||
|
this.downsampleFunctionList = [{ name: "avg", value: "avg" }, { name: "min", value: "min" }, { name: "max", value: "max" }];
|
||||||
|
|
||||||
|
this.initFilters();
|
||||||
|
} else if (target.mode === 1) {
|
||||||
|
this.slaPropertyList = [{ name: "Status", property: "status" }, { name: "SLA", property: "sla" }, { name: "OK time", property: "okTime" }, { name: "Problem time", property: "problemTime" }, { name: "Down time", property: "downtimeTime" }];
|
||||||
|
this.itserviceList = [{ name: "test" }];
|
||||||
|
this.updateITServiceList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_this.init();
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(ZabbixQueryController, [{
|
||||||
|
key: 'initFilters',
|
||||||
|
value: function initFilters() {
|
||||||
|
var itemtype = this.editorModes[this.target.mode].value;
|
||||||
|
return Promise.all([this.suggestGroups(), this.suggestHosts(), this.suggestApps(), this.suggestItems(itemtype)]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestGroups',
|
||||||
|
value: function suggestGroups() {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
return this.zabbix.getAllGroups().then(function (groups) {
|
||||||
|
_this2.metric.groupList = groups;
|
||||||
|
return groups;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestHosts',
|
||||||
|
value: function suggestHosts() {
|
||||||
|
var _this3 = this;
|
||||||
|
|
||||||
|
var groupFilter = this.replaceTemplateVars(this.target.group.filter);
|
||||||
|
return this.zabbix.getAllHosts(groupFilter).then(function (hosts) {
|
||||||
|
_this3.metric.hostList = hosts;
|
||||||
|
return hosts;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestApps',
|
||||||
|
value: function suggestApps() {
|
||||||
|
var _this4 = this;
|
||||||
|
|
||||||
|
var groupFilter = this.replaceTemplateVars(this.target.group.filter);
|
||||||
|
var hostFilter = this.replaceTemplateVars(this.target.host.filter);
|
||||||
|
return this.zabbix.getAllApps(groupFilter, hostFilter).then(function (apps) {
|
||||||
|
_this4.metric.appList = apps;
|
||||||
|
return apps;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestItems',
|
||||||
|
value: function suggestItems() {
|
||||||
|
var _this5 = this;
|
||||||
|
|
||||||
|
var itemtype = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'num';
|
||||||
|
|
||||||
|
var groupFilter = this.replaceTemplateVars(this.target.group.filter);
|
||||||
|
var hostFilter = this.replaceTemplateVars(this.target.host.filter);
|
||||||
|
var appFilter = this.replaceTemplateVars(this.target.application.filter);
|
||||||
|
var options = {
|
||||||
|
itemtype: itemtype,
|
||||||
|
showDisabledItems: this.target.options.showDisabledItems
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.zabbix.getAllItems(groupFilter, hostFilter, appFilter, options).then(function (items) {
|
||||||
|
_this5.metric.itemList = items;
|
||||||
|
return items;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'isRegex',
|
||||||
|
value: function isRegex(str) {
|
||||||
|
return utils.isRegex(str);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'isVariable',
|
||||||
|
value: function isVariable(str) {
|
||||||
|
return utils.isTemplateVariable(str, this.templateSrv.variables);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'onTargetBlur',
|
||||||
|
value: function onTargetBlur() {
|
||||||
|
var newTarget = _.cloneDeep(this.target);
|
||||||
|
if (!_.isEqual(this.oldTarget, this.target)) {
|
||||||
|
this.oldTarget = newTarget;
|
||||||
|
this.targetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'onVariableChange',
|
||||||
|
value: function onVariableChange() {
|
||||||
|
if (this.isContainsVariables()) {
|
||||||
|
this.targetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'isContainsVariables',
|
||||||
|
value: function isContainsVariables() {
|
||||||
|
var _this6 = this;
|
||||||
|
|
||||||
|
return _.some(['group', 'host', 'application'], function (field) {
|
||||||
|
if (_this6.target[field] && _this6.target[field].filter) {
|
||||||
|
return utils.isTemplateVariable(_this6.target[field].filter, _this6.templateSrv.variables);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'parseTarget',
|
||||||
|
value: function parseTarget() {}
|
||||||
|
// Parse target
|
||||||
|
|
||||||
|
|
||||||
|
// Validate target and set validation info
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'validateTarget',
|
||||||
|
value: function validateTarget() {
|
||||||
|
// validate
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'targetChanged',
|
||||||
|
value: function targetChanged() {
|
||||||
|
this.initFilters();
|
||||||
|
this.parseTarget();
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'addFunction',
|
||||||
|
value: function addFunction(funcDef) {
|
||||||
|
var newFunc = metricFunctions.createFuncInstance(funcDef);
|
||||||
|
newFunc.added = true;
|
||||||
|
this.target.functions.push(newFunc);
|
||||||
|
|
||||||
|
this.moveAliasFuncLast();
|
||||||
|
|
||||||
|
if (newFunc.params.length && newFunc.added || newFunc.def.params.length === 0) {
|
||||||
|
this.targetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'removeFunction',
|
||||||
|
value: function removeFunction(func) {
|
||||||
|
this.target.functions = _.without(this.target.functions, func);
|
||||||
|
this.targetChanged();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'moveAliasFuncLast',
|
||||||
|
value: function moveAliasFuncLast() {
|
||||||
|
var aliasFunc = _.find(this.target.functions, function (func) {
|
||||||
|
return func.def.name === 'alias' || func.def.name === 'aliasByNode' || func.def.name === 'aliasByMetric';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (aliasFunc) {
|
||||||
|
this.target.functions = _.without(this.target.functions, aliasFunc);
|
||||||
|
this.target.functions.push(aliasFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'toggleQueryOptions',
|
||||||
|
value: function toggleQueryOptions() {
|
||||||
|
this.showQueryOptions = !this.showQueryOptions;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'onQueryOptionChange',
|
||||||
|
value: function onQueryOptionChange() {
|
||||||
|
this.queryOptionsText = this.renderQueryOptionsText();
|
||||||
|
this.onTargetBlur();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'renderQueryOptionsText',
|
||||||
|
value: function renderQueryOptionsText() {
|
||||||
|
var optionsMap = {
|
||||||
|
showDisabledItems: "Show disabled items"
|
||||||
|
};
|
||||||
|
var options = [];
|
||||||
|
_.forOwn(this.target.options, function (value, key) {
|
||||||
|
if (value) {
|
||||||
|
if (value === true) {
|
||||||
|
// Show only option name (if enabled) for boolean options
|
||||||
|
options.push(optionsMap[key]);
|
||||||
|
} else {
|
||||||
|
// Show "option = value" for another options
|
||||||
|
options.push(optionsMap[key] + " = " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return "Options: " + options.join(', ');
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'switchEditorMode',
|
||||||
|
value: function switchEditorMode(mode) {
|
||||||
|
this.target.mode = mode;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'updateITServiceList',
|
||||||
|
value: function updateITServiceList() {
|
||||||
|
var _this7 = this;
|
||||||
|
|
||||||
|
this.zabbix.getITService().then(function (iteservices) {
|
||||||
|
_this7.itserviceList = [];
|
||||||
|
_this7.itserviceList = _this7.itserviceList.concat(iteservices);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'selectITService',
|
||||||
|
value: function selectITService() {
|
||||||
|
if (!_.isEqual(this.oldTarget, this.target) && _.isEmpty(this.target.errors)) {
|
||||||
|
this.oldTarget = angular.copy(this.target);
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixQueryController;
|
||||||
|
}(QueryCtrl));
|
||||||
|
|
||||||
|
_export('ZabbixQueryController', ZabbixQueryController);
|
||||||
|
|
||||||
|
// Set templateUrl as static property
|
||||||
|
ZabbixQueryController.templateUrl = 'datasource-zabbix/partials/query.editor.html';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=query.controller.js.map
|
||||||
1
dist/datasource-zabbix/query.controller.js.map
vendored
Normal file
113
dist/datasource-zabbix/responseHandler.js
vendored
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['lodash'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Zabbix API history.get response to Grafana format
|
||||||
|
*
|
||||||
|
* @return {Array} Array of timeseries in Grafana format
|
||||||
|
* {
|
||||||
|
* target: "Metric name",
|
||||||
|
* datapoints: [[<value>, <unixtime>], ...]
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
function convertHistory(history, items, addHostName, convertPointCallback) {
|
||||||
|
/**
|
||||||
|
* Response should be in the format:
|
||||||
|
* data: [
|
||||||
|
* {
|
||||||
|
* target: "Metric name",
|
||||||
|
* datapoints: [[<value>, <unixtime>], ...]
|
||||||
|
* }, ...
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Group history by itemid
|
||||||
|
var grouped_history = _.groupBy(history, 'itemid');
|
||||||
|
var hosts = _.uniqBy(_.flatten(_.map(items, 'hosts')), 'hostid'); //uniqBy is needed to deduplicate
|
||||||
|
|
||||||
|
return _.map(grouped_history, function (hist, itemid) {
|
||||||
|
var item = _.find(items, { 'itemid': itemid });
|
||||||
|
var alias = item.name;
|
||||||
|
if (_.keys(hosts).length > 1 && addHostName) {
|
||||||
|
//only when actual multi hosts selected
|
||||||
|
var host = _.find(hosts, { 'hostid': item.hostid });
|
||||||
|
alias = host.name + ": " + alias;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
target: alias,
|
||||||
|
datapoints: _.map(hist, convertPointCallback)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleHistory(history, items) {
|
||||||
|
var addHostName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
||||||
|
|
||||||
|
return convertHistory(history, items, addHostName, convertHistoryPoint);
|
||||||
|
}function handleTrends(history, items, valueType) {
|
||||||
|
var addHostName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
|
||||||
|
|
||||||
|
var convertPointCallback = _.partial(convertTrendPoint, valueType);
|
||||||
|
return convertHistory(history, items, addHostName, convertPointCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSLAResponse(itservice, slaProperty, slaObject) {
|
||||||
|
var targetSLA = slaObject[itservice.serviceid].sla[0];
|
||||||
|
if (slaProperty.property === 'status') {
|
||||||
|
var targetStatus = parseInt(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]]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}function convertHistoryPoint(point) {
|
||||||
|
// Value must be a number for properly work
|
||||||
|
return [Number(point.value), point.clock * 1000];
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertTrendPoint(valueType, point) {
|
||||||
|
var value;
|
||||||
|
switch (valueType) {
|
||||||
|
case "min":
|
||||||
|
value = point.value_min;
|
||||||
|
break;
|
||||||
|
case "max":
|
||||||
|
value = point.value_max;
|
||||||
|
break;
|
||||||
|
case "avg":
|
||||||
|
value = point.value_avg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value = point.value_avg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [Number(value), point.clock * 1000];
|
||||||
|
}return {
|
||||||
|
setters: [function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
_export('default', {
|
||||||
|
handleHistory: handleHistory,
|
||||||
|
convertHistory: convertHistory,
|
||||||
|
handleTrends: handleTrends,
|
||||||
|
handleSLAResponse: handleSLAResponse
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fix for backward compatibility with lodash 2.4
|
||||||
|
if (!_.uniqBy) {
|
||||||
|
_.uniqBy = _.uniq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=responseHandler.js.map
|
||||||
1
dist/datasource-zabbix/responseHandler.js.map
vendored
Normal file
230
dist/datasource-zabbix/specs/datasource_specs.js
vendored
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
import {Datasource} from "../module";
|
||||||
|
import {zabbixTemplateFormat} from "../datasource";
|
||||||
|
import Q from "q";
|
||||||
|
import sinon from 'sinon';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
describe('ZabbixDatasource', () => {
|
||||||
|
let ctx = {};
|
||||||
|
let defined = sinon.match.defined;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ctx.instanceSettings = {
|
||||||
|
jsonData: {
|
||||||
|
username: 'zabbix',
|
||||||
|
password: 'zabbix',
|
||||||
|
trends: true,
|
||||||
|
trendsFrom: '7d'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ctx.templateSrv = {};
|
||||||
|
ctx.alertSrv = {};
|
||||||
|
ctx.zabbix = () => {};
|
||||||
|
|
||||||
|
ctx.ds = new Datasource(ctx.instanceSettings, ctx.templateSrv, ctx.alertSrv, ctx.zabbix);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When querying data', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
ctx.ds.replaceTemplateVars = (str) => str;
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.options = {
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
group: {filter: ""},
|
||||||
|
host: {filter: ""},
|
||||||
|
application: {filter: ""},
|
||||||
|
item: {filter: ""}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
range: {from: 'now-7d', to: 'now'}
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should return an empty array when no targets are set', (done) => {
|
||||||
|
let options = {
|
||||||
|
targets: [],
|
||||||
|
range: {from: 'now-6h', to: 'now'}
|
||||||
|
};
|
||||||
|
ctx.ds.query(options).then(result => {
|
||||||
|
expect(result.data).to.have.length(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use trends if it enabled and time more than trendsFrom', (done) => {
|
||||||
|
let ranges = ['now-7d', 'now-168h', 'now-1M', 'now-1y'];
|
||||||
|
|
||||||
|
_.forEach(ranges, range => {
|
||||||
|
ctx.options.range.from = range;
|
||||||
|
ctx.ds.queryNumericData = sinon.spy();
|
||||||
|
ctx.ds.query(ctx.options);
|
||||||
|
|
||||||
|
// Check that useTrends options is true
|
||||||
|
expect(ctx.ds.queryNumericData)
|
||||||
|
.to.have.been.calledWith(defined, defined, defined, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shouldnt use trends if it enabled and time less than trendsFrom', (done) => {
|
||||||
|
let ranges = ['now-6d', 'now-167h', 'now-1h', 'now-30m', 'now-30s'];
|
||||||
|
|
||||||
|
_.forEach(ranges, range => {
|
||||||
|
ctx.options.range.from = range;
|
||||||
|
ctx.ds.queryNumericData = sinon.spy();
|
||||||
|
ctx.ds.query(ctx.options);
|
||||||
|
|
||||||
|
// Check that useTrends options is false
|
||||||
|
expect(ctx.ds.queryNumericData)
|
||||||
|
.to.have.been.calledWith(defined, defined, defined, false);
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When replacing template variables', () => {
|
||||||
|
|
||||||
|
function testReplacingVariable(target, varValue, expectedResult, done) {
|
||||||
|
ctx.ds.templateSrv.replace = () => {
|
||||||
|
return zabbixTemplateFormat(varValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = ctx.ds.replaceTemplateVars(target);
|
||||||
|
expect(result).to.equal(expectedResult);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Alphanumerics, spaces, dots, dashes and underscores
|
||||||
|
* are allowed in Zabbix host name.
|
||||||
|
* 'AaBbCc0123 .-_'
|
||||||
|
*/
|
||||||
|
it('should return properly escaped regex', (done) => {
|
||||||
|
let target = '$host';
|
||||||
|
let template_var_value = 'AaBbCc0123 .-_';
|
||||||
|
let expected_result = '/^AaBbCc0123 \\.-_$/';
|
||||||
|
|
||||||
|
testReplacingVariable(target, template_var_value, expected_result, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Single-value variable
|
||||||
|
* $host = backend01
|
||||||
|
* $host => /^backend01|backend01$/
|
||||||
|
*/
|
||||||
|
it('should return proper regex for single value', (done) => {
|
||||||
|
let target = '$host';
|
||||||
|
let template_var_value = 'backend01';
|
||||||
|
let expected_result = '/^backend01$/';
|
||||||
|
|
||||||
|
testReplacingVariable(target, template_var_value, expected_result, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Multi-value variable
|
||||||
|
* $host = [backend01, backend02]
|
||||||
|
* $host => /^(backend01|backend01)$/
|
||||||
|
*/
|
||||||
|
it('should return proper regex for multi-value', (done) => {
|
||||||
|
let target = '$host';
|
||||||
|
let template_var_value = ['backend01', 'backend02'];
|
||||||
|
let expected_result = '/^(backend01|backend02)$/';
|
||||||
|
|
||||||
|
testReplacingVariable(target, template_var_value, expected_result, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When invoking metricFindQuery()', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
ctx.ds.replaceTemplateVars = (str) => str;
|
||||||
|
ctx.ds.zabbix = {
|
||||||
|
getGroups: () => Q.when([]),
|
||||||
|
getHosts: () => Q.when([]),
|
||||||
|
getApps: () => Q.when([]),
|
||||||
|
getItems: () => Q.when([])
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return groups', (done) => {
|
||||||
|
const tests = [
|
||||||
|
{query: '*', expect: '/.*/'},
|
||||||
|
{query: '', expect: ''},
|
||||||
|
{query: 'Backend', expect: 'Backend'},
|
||||||
|
{query: 'Back*', expect: 'Back*'}
|
||||||
|
];
|
||||||
|
|
||||||
|
let getGroups = sinon.spy(ctx.ds.zabbix, 'getGroups');
|
||||||
|
for (const test of tests) {
|
||||||
|
ctx.ds.metricFindQuery(test.query);
|
||||||
|
expect(getGroups).to.have.been.calledWith(test.expect);
|
||||||
|
getGroups.reset();
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return hosts', (done) => {
|
||||||
|
const tests = [
|
||||||
|
{query: '*.*', expect: '/.*/'},
|
||||||
|
{query: '.', expect: ''},
|
||||||
|
{query: 'Backend.*', expect: 'Backend'},
|
||||||
|
{query: 'Back*.', expect: 'Back*'}
|
||||||
|
];
|
||||||
|
|
||||||
|
let getHosts = sinon.spy(ctx.ds.zabbix, 'getHosts');
|
||||||
|
for (const test of tests) {
|
||||||
|
ctx.ds.metricFindQuery(test.query);
|
||||||
|
expect(getHosts).to.have.been.calledWith(test.expect);
|
||||||
|
getHosts.reset();
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return applications', (done) => {
|
||||||
|
const tests = [
|
||||||
|
{query: '*.*.*', expect: ['/.*/', '/.*/']},
|
||||||
|
{query: '.*.', expect: ['', '/.*/']},
|
||||||
|
{query: 'Backend.backend01.*', expect: ['Backend', 'backend01']},
|
||||||
|
{query: 'Back*.*.', expect: ['Back*', '/.*/']}
|
||||||
|
];
|
||||||
|
|
||||||
|
let getApps = sinon.spy(ctx.ds.zabbix, 'getApps');
|
||||||
|
for (const test of tests) {
|
||||||
|
ctx.ds.metricFindQuery(test.query);
|
||||||
|
expect(getApps).to.have.been.calledWith(test.expect[0], test.expect[1]);
|
||||||
|
getApps.reset();
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return items', (done) => {
|
||||||
|
const tests = [
|
||||||
|
{query: '*.*.*.*', expect: ['/.*/', '/.*/', '']},
|
||||||
|
{query: '.*.*.*', expect: ['', '/.*/', '']},
|
||||||
|
{query: 'Backend.backend01.*.*', expect: ['Backend', 'backend01', '']},
|
||||||
|
{query: 'Back*.*.cpu.*', expect: ['Back*', '/.*/', 'cpu']}
|
||||||
|
];
|
||||||
|
|
||||||
|
let getItems = sinon.spy(ctx.ds.zabbix, 'getItems');
|
||||||
|
for (const test of tests) {
|
||||||
|
ctx.ds.metricFindQuery(test.query);
|
||||||
|
expect(getItems)
|
||||||
|
.to.have.been.calledWith(test.expect[0], test.expect[1], test.expect[2]);
|
||||||
|
getItems.reset();
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should invoke method with proper arguments', (done) => {
|
||||||
|
let query = '*.*';
|
||||||
|
|
||||||
|
let getHosts = sinon.spy(ctx.ds.zabbix, 'getHosts');
|
||||||
|
ctx.ds.metricFindQuery(query);
|
||||||
|
expect(getHosts).to.have.been.calledWith('/.*/');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
111
dist/datasource-zabbix/specs/modules/datemath.js
vendored
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
var units = ['y', 'M', 'w', 'd', 'h', 'm', 's'];
|
||||||
|
|
||||||
|
export function parse(text, roundUp) {
|
||||||
|
if (!text) { return undefined; }
|
||||||
|
if (moment.isMoment(text)) { return text; }
|
||||||
|
if (_.isDate(text)) { return moment(text); }
|
||||||
|
|
||||||
|
var time;
|
||||||
|
var mathString = '';
|
||||||
|
var index;
|
||||||
|
var parseString;
|
||||||
|
|
||||||
|
if (text.substring(0, 3) === 'now') {
|
||||||
|
time = moment();
|
||||||
|
mathString = text.substring('now'.length);
|
||||||
|
} else {
|
||||||
|
index = text.indexOf('||');
|
||||||
|
if (index === -1) {
|
||||||
|
parseString = text;
|
||||||
|
mathString = ''; // nothing else
|
||||||
|
} else {
|
||||||
|
parseString = text.substring(0, index);
|
||||||
|
mathString = text.substring(index + 2);
|
||||||
|
}
|
||||||
|
// We're going to just require ISO8601 timestamps, k?
|
||||||
|
time = moment(parseString, moment.ISO_8601);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mathString.length) {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseDateMath(mathString, time, roundUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isValid(text) {
|
||||||
|
var date = parse(text);
|
||||||
|
if (!date) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moment.isMoment(date)) {
|
||||||
|
return date.isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseDateMath(mathString, time, roundUp) {
|
||||||
|
var dateTime = time;
|
||||||
|
var i = 0;
|
||||||
|
var len = mathString.length;
|
||||||
|
|
||||||
|
while (i < len) {
|
||||||
|
var c = mathString.charAt(i++);
|
||||||
|
var type;
|
||||||
|
var num;
|
||||||
|
var unit;
|
||||||
|
|
||||||
|
if (c === '/') {
|
||||||
|
type = 0;
|
||||||
|
} else if (c === '+') {
|
||||||
|
type = 1;
|
||||||
|
} else if (c === '-') {
|
||||||
|
type = 2;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(mathString.charAt(i))) {
|
||||||
|
num = 1;
|
||||||
|
} else if (mathString.length === 2) {
|
||||||
|
num = mathString.charAt(i);
|
||||||
|
} else {
|
||||||
|
var numFrom = i;
|
||||||
|
while (!isNaN(mathString.charAt(i))) {
|
||||||
|
i++;
|
||||||
|
if (i > 10) { return undefined; }
|
||||||
|
}
|
||||||
|
num = parseInt(mathString.substring(numFrom, i), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 0) {
|
||||||
|
// rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M)
|
||||||
|
if (num !== 1) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unit = mathString.charAt(i++);
|
||||||
|
|
||||||
|
if (!_.includes(units, unit)) {
|
||||||
|
return undefined;
|
||||||
|
} else {
|
||||||
|
if (type === 0) {
|
||||||
|
if (roundUp) {
|
||||||
|
dateTime.endOf(unit);
|
||||||
|
} else {
|
||||||
|
dateTime.startOf(unit);
|
||||||
|
}
|
||||||
|
} else if (type === 1) {
|
||||||
|
dateTime.add(num, unit);
|
||||||
|
} else if (type === 2) {
|
||||||
|
dateTime.subtract(num, unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dateTime;
|
||||||
|
}
|
||||||
49
dist/datasource-zabbix/specs/test-main.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// JSHint options
|
||||||
|
/* globals global: false */
|
||||||
|
|
||||||
|
import prunk from 'prunk';
|
||||||
|
import {jsdom} from 'jsdom';
|
||||||
|
import chai from 'chai';
|
||||||
|
// import sinon from 'sinon';
|
||||||
|
import sinonChai from 'sinon-chai';
|
||||||
|
import * as dateMath from './modules/datemath';
|
||||||
|
|
||||||
|
// Mock angular module
|
||||||
|
var angularMocks = {
|
||||||
|
module: function() {
|
||||||
|
return {
|
||||||
|
directive: function() {},
|
||||||
|
service: function() {},
|
||||||
|
factory: function() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var datemathMock = {
|
||||||
|
parse: dateMath.parse,
|
||||||
|
parseDateMath: dateMath.parseDateMath,
|
||||||
|
isValid: dateMath.isValid
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock Grafana modules that are not available outside of the core project
|
||||||
|
// Required for loading module.js
|
||||||
|
prunk.mock('./css/query-editor.css!', 'no css, dude.');
|
||||||
|
prunk.mock('app/plugins/sdk', {
|
||||||
|
QueryCtrl: null
|
||||||
|
});
|
||||||
|
prunk.mock('app/core/utils/datemath', datemathMock);
|
||||||
|
prunk.mock('angular', angularMocks);
|
||||||
|
prunk.mock('jquery', 'module not found');
|
||||||
|
|
||||||
|
// Setup jsdom
|
||||||
|
// Required for loading angularjs
|
||||||
|
global.document = jsdom('<html><head><script></script></head><body></body></html>');
|
||||||
|
global.window = global.document.parentWindow;
|
||||||
|
global.navigator = window.navigator = {};
|
||||||
|
global.Node = window.Node;
|
||||||
|
|
||||||
|
// Setup Chai
|
||||||
|
chai.should();
|
||||||
|
chai.use(sinonChai);
|
||||||
|
global.assert = chai.assert;
|
||||||
|
global.expect = chai.expect;
|
||||||
169
dist/datasource-zabbix/utils.js
vendored
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['lodash', 'moment'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _, moment, regexPattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand Zabbix item name
|
||||||
|
*
|
||||||
|
* @param {string} name item name, ie "CPU $2 time"
|
||||||
|
* @param {string} key item key, ie system.cpu.util[,system,avg1]
|
||||||
|
* @return {string} expanded name, ie "CPU system time"
|
||||||
|
*/
|
||||||
|
function expandItemName(name, key) {
|
||||||
|
|
||||||
|
// extract params from key:
|
||||||
|
// "system.cpu.util[,system,avg1]" --> ["", "system", "avg1"]
|
||||||
|
var key_params = key.substring(key.indexOf('[') + 1, key.lastIndexOf(']')).split(',');
|
||||||
|
|
||||||
|
// replace item parameters
|
||||||
|
for (var i = key_params.length; i >= 1; i--) {
|
||||||
|
name = name.replace('$' + i, key_params[i - 1]);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pattern for testing regex
|
||||||
|
|
||||||
|
_export('expandItemName', expandItemName);
|
||||||
|
|
||||||
|
function isRegex(str) {
|
||||||
|
return regexPattern.test(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
_export('isRegex', isRegex);
|
||||||
|
|
||||||
|
function isTemplateVariable(str, templateVariables) {
|
||||||
|
var variablePattern = /^\$\w+/;
|
||||||
|
if (variablePattern.test(str)) {
|
||||||
|
var variables = _.map(templateVariables, function (variable) {
|
||||||
|
return '$' + variable.name;
|
||||||
|
});
|
||||||
|
return _.includes(variables, str);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_export('isTemplateVariable', isTemplateVariable);
|
||||||
|
|
||||||
|
function buildRegex(str) {
|
||||||
|
var matches = str.match(regexPattern);
|
||||||
|
var pattern = matches[1];
|
||||||
|
var flags = matches[2] !== "" ? matches[2] : undefined;
|
||||||
|
return new RegExp(pattern, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need for template variables replace
|
||||||
|
// From Grafana's templateSrv.js
|
||||||
|
|
||||||
|
_export('buildRegex', buildRegex);
|
||||||
|
|
||||||
|
function escapeRegex(value) {
|
||||||
|
return value.replace(/[\\^$*+?.()|[\]{}\/]/g, '\\$&');
|
||||||
|
}
|
||||||
|
|
||||||
|
_export('escapeRegex', escapeRegex);
|
||||||
|
|
||||||
|
function parseInterval(interval) {
|
||||||
|
var intervalPattern = /(^[\d]+)(y|M|w|d|h|m|s)/g;
|
||||||
|
var momentInterval = intervalPattern.exec(interval);
|
||||||
|
return moment.duration(Number(momentInterval[1]), momentInterval[2]).valueOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
_export('parseInterval', parseInterval);
|
||||||
|
|
||||||
|
function parseTimeShiftInterval(interval) {
|
||||||
|
var intervalPattern = /^([\+\-]*)([\d]+)(y|M|w|d|h|m|s)/g;
|
||||||
|
var momentInterval = intervalPattern.exec(interval);
|
||||||
|
var duration = 0;
|
||||||
|
|
||||||
|
if (momentInterval[1] === '+') {
|
||||||
|
duration = 0 - moment.duration(Number(momentInterval[2]), momentInterval[3]).valueOf();
|
||||||
|
} else {
|
||||||
|
duration = moment.duration(Number(momentInterval[2]), momentInterval[3]).valueOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format acknowledges.
|
||||||
|
*
|
||||||
|
* @param {array} acknowledges array of Zabbix acknowledge objects
|
||||||
|
* @return {string} HTML-formatted table
|
||||||
|
*/
|
||||||
|
|
||||||
|
_export('parseTimeShiftInterval', parseTimeShiftInterval);
|
||||||
|
|
||||||
|
function formatAcknowledges(acknowledges) {
|
||||||
|
if (acknowledges.length) {
|
||||||
|
var formatted_acknowledges = '<br><br>Acknowledges:<br><table><tr><td><b>Time</b></td>' + '<td><b>User</b></td><td><b>Comments</b></td></tr>';
|
||||||
|
_.each(_.map(acknowledges, function (ack) {
|
||||||
|
var timestamp = moment.unix(ack.clock);
|
||||||
|
return '<tr><td><i>' + timestamp.format("DD MMM YYYY HH:mm:ss") + '</i></td><td>' + ack.alias + ' (' + ack.name + ' ' + ack.surname + ')' + '</td><td>' + ack.message + '</td></tr>';
|
||||||
|
}), function (ack) {
|
||||||
|
formatted_acknowledges = formatted_acknowledges.concat(ack);
|
||||||
|
});
|
||||||
|
formatted_acknowledges = formatted_acknowledges.concat('</table>');
|
||||||
|
return formatted_acknowledges;
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_export('formatAcknowledges', formatAcknowledges);
|
||||||
|
|
||||||
|
function convertToZabbixAPIUrl(url) {
|
||||||
|
var zabbixAPIUrlPattern = /.*api_jsonrpc.php$/;
|
||||||
|
var trimSlashPattern = /(.*?)[\/]*$/;
|
||||||
|
if (url.match(zabbixAPIUrlPattern)) {
|
||||||
|
return url;
|
||||||
|
} else {
|
||||||
|
return url.replace(trimSlashPattern, "$1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap function to prevent multiple calls
|
||||||
|
* when waiting for result.
|
||||||
|
*/
|
||||||
|
|
||||||
|
_export('convertToZabbixAPIUrl', convertToZabbixAPIUrl);
|
||||||
|
|
||||||
|
function callOnce(func, promiseKeeper) {
|
||||||
|
return function () {
|
||||||
|
if (!promiseKeeper) {
|
||||||
|
promiseKeeper = Promise.resolve(func.apply(this, arguments).then(function (result) {
|
||||||
|
promiseKeeper = null;
|
||||||
|
return result;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return promiseKeeper;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix for backward compatibility with lodash 2.4
|
||||||
|
|
||||||
|
_export('callOnce', callOnce);
|
||||||
|
|
||||||
|
return {
|
||||||
|
setters: [function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}, function (_moment) {
|
||||||
|
moment = _moment.default;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
_export('regexPattern', regexPattern = /^\/(.*)\/([gmi]*)$/m);
|
||||||
|
|
||||||
|
_export('regexPattern', regexPattern);
|
||||||
|
|
||||||
|
if (!_.includes) {
|
||||||
|
_.includes = _.contains;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=utils.js.map
|
||||||
1
dist/datasource-zabbix/utils.js.map
vendored
Normal file
278
dist/datasource-zabbix/zabbix.js
vendored
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['angular', 'lodash', './utils', './zabbixAPI.service.js', './zabbixCachingProxy.service.js'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var angular, _, utils, _createClass;
|
||||||
|
|
||||||
|
function _toConsumableArray(arr) {
|
||||||
|
if (Array.isArray(arr)) {
|
||||||
|
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
|
||||||
|
arr2[i] = arr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr2;
|
||||||
|
} else {
|
||||||
|
return Array.from(arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use factory() instead service() for multiple data sources support.
|
||||||
|
// Each Zabbix data source instance should initialize its own API instance.
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy) {
|
||||||
|
var Zabbix = function () {
|
||||||
|
function Zabbix(url, username, password, basicAuth, withCredentials, cacheTTL) {
|
||||||
|
_classCallCheck(this, Zabbix);
|
||||||
|
|
||||||
|
// Initialize Zabbix API
|
||||||
|
var ZabbixAPI = zabbixAPIService;
|
||||||
|
this.zabbixAPI = new ZabbixAPI(url, username, password, basicAuth, withCredentials);
|
||||||
|
|
||||||
|
// Initialize caching proxy for requests
|
||||||
|
var cacheOptions = {
|
||||||
|
enabled: true,
|
||||||
|
ttl: cacheTTL
|
||||||
|
};
|
||||||
|
this.cachingProxy = new ZabbixCachingProxy(this.zabbixAPI, cacheOptions);
|
||||||
|
|
||||||
|
// Proxy methods
|
||||||
|
this.getHistory = this.cachingProxy.getHistory.bind(this.cachingProxy);
|
||||||
|
|
||||||
|
this.getTrend = this.zabbixAPI.getTrend.bind(this.zabbixAPI);
|
||||||
|
this.getEvents = this.zabbixAPI.getEvents.bind(this.zabbixAPI);
|
||||||
|
this.getAcknowledges = this.zabbixAPI.getAcknowledges.bind(this.zabbixAPI);
|
||||||
|
this.getITService = this.zabbixAPI.getITService.bind(this.zabbixAPI);
|
||||||
|
this.getSLA = this.zabbixAPI.getSLA.bind(this.zabbixAPI);
|
||||||
|
this.getVersion = this.zabbixAPI.getVersion.bind(this.zabbixAPI);
|
||||||
|
this.login = this.zabbixAPI.login.bind(this.zabbixAPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(Zabbix, [{
|
||||||
|
key: 'getItemsFromTarget',
|
||||||
|
value: function getItemsFromTarget(target, options) {
|
||||||
|
var parts = ['group', 'host', 'application', 'item'];
|
||||||
|
var filters = _.map(parts, function (p) {
|
||||||
|
return target[p].filter;
|
||||||
|
});
|
||||||
|
return this.getItems.apply(this, _toConsumableArray(filters).concat([options]));
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getAllGroups',
|
||||||
|
value: function getAllGroups() {
|
||||||
|
return this.cachingProxy.getGroups();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getGroups',
|
||||||
|
value: function getGroups(groupFilter) {
|
||||||
|
return this.getAllGroups().then(function (groups) {
|
||||||
|
return findByFilter(groups, groupFilter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getAllHosts',
|
||||||
|
value: function getAllHosts(groupFilter) {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
return this.getGroups(groupFilter).then(function (groups) {
|
||||||
|
var groupids = _.map(groups, 'groupid');
|
||||||
|
return _this.cachingProxy.getHosts(groupids);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getHosts',
|
||||||
|
value: function getHosts(groupFilter, hostFilter) {
|
||||||
|
return this.getAllHosts(groupFilter).then(function (hosts) {
|
||||||
|
return findByFilter(hosts, hostFilter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getAllApps',
|
||||||
|
value: function getAllApps(groupFilter, hostFilter) {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
return this.getHosts(groupFilter, hostFilter).then(function (hosts) {
|
||||||
|
var hostids = _.map(hosts, 'hostid');
|
||||||
|
return _this2.cachingProxy.getApps(hostids);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getApps',
|
||||||
|
value: function getApps(groupFilter, hostFilter, appFilter) {
|
||||||
|
var _this3 = this;
|
||||||
|
|
||||||
|
return this.getHosts(groupFilter, hostFilter).then(function (hosts) {
|
||||||
|
var hostids = _.map(hosts, 'hostid');
|
||||||
|
if (appFilter) {
|
||||||
|
return _this3.cachingProxy.getApps(hostids).then(function (apps) {
|
||||||
|
return filterByQuery(apps, appFilter);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
appFilterEmpty: true,
|
||||||
|
hostids: hostids
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getAllItems',
|
||||||
|
value: function getAllItems(groupFilter, hostFilter, appFilter) {
|
||||||
|
var _this4 = this;
|
||||||
|
|
||||||
|
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
||||||
|
|
||||||
|
return this.getApps(groupFilter, hostFilter, appFilter).then(function (apps) {
|
||||||
|
if (apps.appFilterEmpty) {
|
||||||
|
return _this4.cachingProxy.getItems(apps.hostids, undefined, options.itemtype);
|
||||||
|
} else {
|
||||||
|
var appids = _.map(apps, 'applicationid');
|
||||||
|
return _this4.cachingProxy.getItems(undefined, appids, options.itemtype);
|
||||||
|
}
|
||||||
|
}).then(function (items) {
|
||||||
|
if (!options.showDisabledItems) {
|
||||||
|
items = _.filter(items, { 'status': '0' });
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getItems',
|
||||||
|
value: function getItems(groupFilter, hostFilter, appFilter, itemFilter) {
|
||||||
|
var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
|
||||||
|
|
||||||
|
return this.getAllItems(groupFilter, hostFilter, appFilter, options).then(function (items) {
|
||||||
|
return filterByQuery(items, itemFilter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getTriggers',
|
||||||
|
value: function getTriggers(groupFilter, hostFilter, appFilter, showTriggers) {
|
||||||
|
var _this5 = this;
|
||||||
|
|
||||||
|
var promises = [this.getGroups(groupFilter), this.getHosts(groupFilter, hostFilter), this.getApps(groupFilter, hostFilter, appFilter)];
|
||||||
|
|
||||||
|
return Promise.all(promises).then(function (results) {
|
||||||
|
var filteredGroups = results[0];
|
||||||
|
var filteredHosts = results[1];
|
||||||
|
var filteredApps = results[2];
|
||||||
|
var query = {};
|
||||||
|
|
||||||
|
if (appFilter) {
|
||||||
|
query.applicationids = _.flatten(_.map(filteredApps, 'applicationid'));
|
||||||
|
}
|
||||||
|
if (hostFilter) {
|
||||||
|
query.hostids = _.map(filteredHosts, 'hostid');
|
||||||
|
}
|
||||||
|
if (groupFilter) {
|
||||||
|
query.groupids = _.map(filteredGroups, 'groupid');
|
||||||
|
}
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}).then(function (query) {
|
||||||
|
return _this5.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return Zabbix;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return Zabbix;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find group, host, app or item by given name.
|
||||||
|
* @param list list of groups, apps or other
|
||||||
|
* @param name visible name
|
||||||
|
* @return array with finded element or undefined
|
||||||
|
*/
|
||||||
|
function findByName(list, name) {
|
||||||
|
var finded = _.find(list, { 'name': name });
|
||||||
|
if (finded) {
|
||||||
|
return [finded];
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 filterByRegex(list, regex) {
|
||||||
|
var filterPattern = utils.buildRegex(regex);
|
||||||
|
return _.filter(list, function (zbx_obj) {
|
||||||
|
return filterPattern.test(zbx_obj.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function findByFilter(list, filter) {
|
||||||
|
if (utils.isRegex(filter)) {
|
||||||
|
return filterByRegex(list, filter);
|
||||||
|
} else {
|
||||||
|
return findByName(list, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterByQuery(list, filter) {
|
||||||
|
if (utils.isRegex(filter)) {
|
||||||
|
return filterByRegex(list, filter);
|
||||||
|
} else {
|
||||||
|
return filterByName(list, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
setters: [function (_angular) {
|
||||||
|
angular = _angular.default;
|
||||||
|
}, function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}, function (_utils) {
|
||||||
|
utils = _utils;
|
||||||
|
}, function (_zabbixAPIServiceJs) {}, function (_zabbixCachingProxyServiceJs) {}],
|
||||||
|
execute: function () {
|
||||||
|
_createClass = function () {
|
||||||
|
function defineProperties(target, props) {
|
||||||
|
for (var i = 0; i < props.length; i++) {
|
||||||
|
var descriptor = props[i];
|
||||||
|
descriptor.enumerable = descriptor.enumerable || false;
|
||||||
|
descriptor.configurable = true;
|
||||||
|
if ("value" in descriptor) descriptor.writable = true;
|
||||||
|
Object.defineProperty(target, descriptor.key, descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (Constructor, protoProps, staticProps) {
|
||||||
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
||||||
|
if (staticProps) defineProperties(Constructor, staticProps);
|
||||||
|
return Constructor;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
angular.module('grafana.services').factory('Zabbix', ZabbixFactory);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=zabbix.js.map
|
||||||
1
dist/datasource-zabbix/zabbix.js.map
vendored
Normal file
397
dist/datasource-zabbix/zabbixAPI.service.js
vendored
Normal file
@@ -0,0 +1,397 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['angular', 'lodash', './utils', './zabbixAPICore.service'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var angular, _, utils, _createClass;
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function ZabbixAPIServiceFactory(alertSrv, zabbixAPICoreService) {
|
||||||
|
var ZabbixAPI = function () {
|
||||||
|
function ZabbixAPI(api_url, username, password, basicAuth, withCredentials) {
|
||||||
|
_classCallCheck(this, ZabbixAPI);
|
||||||
|
|
||||||
|
this.url = api_url;
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
this.auth = "";
|
||||||
|
|
||||||
|
this.requestOptions = {
|
||||||
|
basicAuth: basicAuth,
|
||||||
|
withCredentials: withCredentials
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loginPromise = null;
|
||||||
|
this.loginErrorCount = 0;
|
||||||
|
this.maxLoginAttempts = 3;
|
||||||
|
|
||||||
|
this.alertSrv = alertSrv;
|
||||||
|
this.zabbixAPICore = zabbixAPICoreService;
|
||||||
|
|
||||||
|
this.getTrend = this.getTrend_ZBXNEXT1193;
|
||||||
|
//getTrend = getTrend_30;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// Core method wrappers //
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
_createClass(ZabbixAPI, [{
|
||||||
|
key: 'request',
|
||||||
|
value: function request(method, params) {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
return this.zabbixAPICore.request(this.url, method, params, this.requestOptions, this.auth).catch(function (error) {
|
||||||
|
if (isNotAuthorized(error.data)) {
|
||||||
|
// Handle auth errors
|
||||||
|
_this.loginErrorCount++;
|
||||||
|
if (_this.loginErrorCount > _this.maxLoginAttempts) {
|
||||||
|
_this.loginErrorCount = 0;
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return _this.loginOnce().then(function () {
|
||||||
|
return _this.request(method, params);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle API errors
|
||||||
|
var message = error.data ? error.data : error.statusText;
|
||||||
|
_this.alertAPIError(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'alertAPIError',
|
||||||
|
value: function alertAPIError(message) {
|
||||||
|
var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5000;
|
||||||
|
|
||||||
|
this.alertSrv.set("Zabbix API Error", message, 'error', timeout);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'loginOnce',
|
||||||
|
value: function loginOnce() {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
if (!this.loginPromise) {
|
||||||
|
this.loginPromise = Promise.resolve(this.login().then(function (auth) {
|
||||||
|
_this2.auth = auth;
|
||||||
|
_this2.loginPromise = null;
|
||||||
|
return auth;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return this.loginPromise;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'login',
|
||||||
|
value: function login() {
|
||||||
|
return this.zabbixAPICore.login(this.url, this.username, this.password, this.requestOptions);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getVersion',
|
||||||
|
value: function getVersion() {
|
||||||
|
return this.zabbixAPICore.getVersion(this.url, this.requestOptions);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'acknowledgeEvent',
|
||||||
|
value: function acknowledgeEvent(eventid, message) {
|
||||||
|
var params = {
|
||||||
|
eventids: eventid,
|
||||||
|
message: message
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.request('event.acknowledge', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getGroups',
|
||||||
|
value: function getGroups() {
|
||||||
|
var params = {
|
||||||
|
output: ['name'],
|
||||||
|
sortfield: 'name',
|
||||||
|
real_hosts: true
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.request('hostgroup.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getHosts',
|
||||||
|
value: function getHosts(groupids) {
|
||||||
|
var params = {
|
||||||
|
output: ['name', 'host'],
|
||||||
|
sortfield: 'name'
|
||||||
|
};
|
||||||
|
if (groupids) {
|
||||||
|
params.groupids = groupids;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.request('host.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getApps',
|
||||||
|
value: function getApps(hostids) {
|
||||||
|
var params = {
|
||||||
|
output: ['applicationid', 'name'],
|
||||||
|
hostids: hostids
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.request('application.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getItems',
|
||||||
|
value: function getItems(hostids, appids, itemtype) {
|
||||||
|
var params = {
|
||||||
|
output: ['name', 'key_', 'value_type', 'hostid', 'status', 'state'],
|
||||||
|
sortfield: 'name',
|
||||||
|
webitems: true,
|
||||||
|
filter: {},
|
||||||
|
selectHosts: ['hostid', 'name']
|
||||||
|
};
|
||||||
|
if (hostids) {
|
||||||
|
params.hostids = hostids;
|
||||||
|
}
|
||||||
|
if (appids) {
|
||||||
|
params.applicationids = appids;
|
||||||
|
}
|
||||||
|
if (itemtype === 'num') {
|
||||||
|
// Return only numeric metrics
|
||||||
|
params.filter.value_type = [0, 3];
|
||||||
|
}
|
||||||
|
if (itemtype === 'text') {
|
||||||
|
// Return only text metrics
|
||||||
|
params.filter.value_type = [1, 2, 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.request('item.get', params).then(expandItems);
|
||||||
|
|
||||||
|
function expandItems(items) {
|
||||||
|
items.forEach(function (item) {
|
||||||
|
item.item = item.name;
|
||||||
|
item.name = utils.expandItemName(item.item, item.key_);
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getLastValue',
|
||||||
|
value: function getLastValue(itemid) {
|
||||||
|
var params = {
|
||||||
|
output: ['lastvalue'],
|
||||||
|
itemids: itemid
|
||||||
|
};
|
||||||
|
return this.request('item.get', params).then(function (items) {
|
||||||
|
return items.length ? items[0].lastvalue : null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getHistory',
|
||||||
|
value: function getHistory(items, timeFrom, timeTill) {
|
||||||
|
var _this3 = this;
|
||||||
|
|
||||||
|
// Group items by value type and perform request for each value type
|
||||||
|
var grouped_items = _.groupBy(items, 'value_type');
|
||||||
|
var promises = _.map(grouped_items, function (items, value_type) {
|
||||||
|
var itemids = _.map(items, 'itemid');
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
history: value_type,
|
||||||
|
itemids: itemids,
|
||||||
|
sortfield: 'clock',
|
||||||
|
sortorder: 'ASC',
|
||||||
|
time_from: timeFrom
|
||||||
|
};
|
||||||
|
|
||||||
|
// Relative queries (e.g. last hour) don't include an end time
|
||||||
|
if (timeTill) {
|
||||||
|
params.time_till = timeTill;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _this3.request('history.get', params);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises).then(_.flatten);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getTrend_ZBXNEXT1193',
|
||||||
|
value: function getTrend_ZBXNEXT1193(items, timeFrom, timeTill) {
|
||||||
|
var _this4 = this;
|
||||||
|
|
||||||
|
// Group items by value type and perform request for each value type
|
||||||
|
var grouped_items = _.groupBy(items, 'value_type');
|
||||||
|
var promises = _.map(grouped_items, function (items, value_type) {
|
||||||
|
var itemids = _.map(items, 'itemid');
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
trend: value_type,
|
||||||
|
itemids: itemids,
|
||||||
|
sortfield: 'clock',
|
||||||
|
sortorder: 'ASC',
|
||||||
|
time_from: timeFrom
|
||||||
|
};
|
||||||
|
|
||||||
|
// Relative queries (e.g. last hour) don't include an end time
|
||||||
|
if (timeTill) {
|
||||||
|
params.time_till = timeTill;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _this4.request('trend.get', params);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises).then(_.flatten);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getTrend_30',
|
||||||
|
value: function getTrend_30(items, time_from, time_till, value_type) {
|
||||||
|
var self = this;
|
||||||
|
var itemids = _.map(items, 'itemid');
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
output: ["itemid", "clock", value_type],
|
||||||
|
itemids: itemids,
|
||||||
|
time_from: time_from
|
||||||
|
};
|
||||||
|
|
||||||
|
// Relative queries (e.g. last hour) don't include an end time
|
||||||
|
if (time_till) {
|
||||||
|
params.time_till = time_till;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.request('trend.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getITService',
|
||||||
|
value: function getITService(serviceids) {
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
serviceids: serviceids
|
||||||
|
};
|
||||||
|
return this.request('service.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getSLA',
|
||||||
|
value: function getSLA(serviceids, timeFrom, timeTo) {
|
||||||
|
var params = {
|
||||||
|
serviceids: serviceids,
|
||||||
|
intervals: [{
|
||||||
|
from: timeFrom,
|
||||||
|
to: timeTo
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
return this.request('service.getsla', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getTriggers',
|
||||||
|
value: function getTriggers(groupids, hostids, applicationids, showTriggers, timeFrom, timeTo) {
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
groupids: groupids,
|
||||||
|
hostids: hostids,
|
||||||
|
applicationids: applicationids,
|
||||||
|
expandDescription: true,
|
||||||
|
expandData: true,
|
||||||
|
expandComment: true,
|
||||||
|
monitored: true,
|
||||||
|
skipDependent: true,
|
||||||
|
//only_true: true,
|
||||||
|
filter: {
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
selectGroups: ['name'],
|
||||||
|
selectHosts: ['name', 'host'],
|
||||||
|
selectItems: ['name', 'key_', 'lastvalue'],
|
||||||
|
selectLastEvent: 'extend'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (showTriggers) {
|
||||||
|
params.filter.value = showTriggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeFrom || timeTo) {
|
||||||
|
params.lastChangeSince = timeFrom;
|
||||||
|
params.lastChangeTill = timeTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.request('trigger.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getEvents',
|
||||||
|
value: function getEvents(objectids, timeFrom, timeTo, showEvents) {
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
time_from: timeFrom,
|
||||||
|
time_till: timeTo,
|
||||||
|
objectids: objectids,
|
||||||
|
select_acknowledges: 'extend',
|
||||||
|
selectHosts: 'extend',
|
||||||
|
value: showEvents
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.request('event.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getAcknowledges',
|
||||||
|
value: function getAcknowledges(eventids) {
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
eventids: eventids,
|
||||||
|
preservekeys: true,
|
||||||
|
select_acknowledges: 'extend',
|
||||||
|
sortfield: 'clock',
|
||||||
|
sortorder: 'DESC'
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.request('event.get', params).then(function (events) {
|
||||||
|
return _.filter(events, function (event) {
|
||||||
|
return event.acknowledges.length;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixAPI;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return ZabbixAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNotAuthorized(message) {
|
||||||
|
return message === "Session terminated, re-login, please." || message === "Not authorised." || message === "Not authorized.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setters: [function (_angular) {
|
||||||
|
angular = _angular.default;
|
||||||
|
}, function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}, function (_utils) {
|
||||||
|
utils = _utils;
|
||||||
|
}, function (_zabbixAPICoreService) {}],
|
||||||
|
execute: function () {
|
||||||
|
_createClass = function () {
|
||||||
|
function defineProperties(target, props) {
|
||||||
|
for (var i = 0; i < props.length; i++) {
|
||||||
|
var descriptor = props[i];
|
||||||
|
descriptor.enumerable = descriptor.enumerable || false;
|
||||||
|
descriptor.configurable = true;
|
||||||
|
if ("value" in descriptor) descriptor.writable = true;
|
||||||
|
Object.defineProperty(target, descriptor.key, descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (Constructor, protoProps, staticProps) {
|
||||||
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
||||||
|
if (staticProps) defineProperties(Constructor, staticProps);
|
||||||
|
return Constructor;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
angular.module('grafana.services').factory('zabbixAPIService', ZabbixAPIServiceFactory);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=zabbixAPI.service.js.map
|
||||||
1
dist/datasource-zabbix/zabbixAPI.service.js.map
vendored
Normal file
150
dist/datasource-zabbix/zabbixAPICore.service.js
vendored
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['angular'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var angular, _createClass, ZabbixAPICoreService, ZabbixAPIError;
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setters: [function (_angular) {
|
||||||
|
angular = _angular.default;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
_createClass = function () {
|
||||||
|
function defineProperties(target, props) {
|
||||||
|
for (var i = 0; i < props.length; i++) {
|
||||||
|
var descriptor = props[i];
|
||||||
|
descriptor.enumerable = descriptor.enumerable || false;
|
||||||
|
descriptor.configurable = true;
|
||||||
|
if ("value" in descriptor) descriptor.writable = true;
|
||||||
|
Object.defineProperty(target, descriptor.key, descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (Constructor, protoProps, staticProps) {
|
||||||
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
||||||
|
if (staticProps) defineProperties(Constructor, staticProps);
|
||||||
|
return Constructor;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
ZabbixAPICoreService = function () {
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function ZabbixAPICoreService(backendSrv) {
|
||||||
|
_classCallCheck(this, ZabbixAPICoreService);
|
||||||
|
|
||||||
|
this.backendSrv = backendSrv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request data from Zabbix API
|
||||||
|
* @return {object} response.result
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
_createClass(ZabbixAPICoreService, [{
|
||||||
|
key: 'request',
|
||||||
|
value: function request(api_url, method, params, options, auth) {
|
||||||
|
var requestData = {
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method: method,
|
||||||
|
params: params,
|
||||||
|
id: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auth === "") {
|
||||||
|
// Reject immediately if not authenticated
|
||||||
|
return Promise.reject(new ZabbixAPIError({ data: "Not authorised." }));
|
||||||
|
} else if (auth) {
|
||||||
|
// Set auth parameter only if it needed
|
||||||
|
requestData.auth = auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
url: api_url,
|
||||||
|
data: requestData,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set request options for basic auth
|
||||||
|
if (options.basicAuth || options.withCredentials) {
|
||||||
|
requestOptions.withCredentials = true;
|
||||||
|
}
|
||||||
|
if (options.basicAuth) {
|
||||||
|
requestOptions.headers.Authorization = options.basicAuth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.datasourceRequest(requestOptions);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'datasourceRequest',
|
||||||
|
value: function datasourceRequest(requestOptions) {
|
||||||
|
return this.backendSrv.datasourceRequest(requestOptions).then(function (response) {
|
||||||
|
if (!response.data) {
|
||||||
|
return Promise.reject(new ZabbixAPIError({ data: "General Error, no data" }));
|
||||||
|
} else if (response.data.error) {
|
||||||
|
|
||||||
|
// Handle Zabbix API errors
|
||||||
|
return Promise.reject(new ZabbixAPIError(response.data.error));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
return response.data.result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'login',
|
||||||
|
value: function login(api_url, username, password, options) {
|
||||||
|
var params = {
|
||||||
|
user: username,
|
||||||
|
password: password
|
||||||
|
};
|
||||||
|
return this.request(api_url, 'user.login', params, options, null);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getVersion',
|
||||||
|
value: function getVersion(api_url, options) {
|
||||||
|
return this.request(api_url, 'apiinfo.version', [], options);
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixAPICoreService;
|
||||||
|
}();
|
||||||
|
|
||||||
|
_export('ZabbixAPIError', ZabbixAPIError = function () {
|
||||||
|
function ZabbixAPIError(error) {
|
||||||
|
_classCallCheck(this, ZabbixAPIError);
|
||||||
|
|
||||||
|
this.code = error.code;
|
||||||
|
this.name = error.data;
|
||||||
|
this.message = error.data;
|
||||||
|
this.data = error.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(ZabbixAPIError, [{
|
||||||
|
key: 'toString',
|
||||||
|
value: function toString() {
|
||||||
|
return this.name + ": " + this.message;
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixAPIError;
|
||||||
|
}());
|
||||||
|
|
||||||
|
_export('ZabbixAPIError', ZabbixAPIError);
|
||||||
|
|
||||||
|
angular.module('grafana.services').service('zabbixAPICoreService', ZabbixAPICoreService);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=zabbixAPICore.service.js.map
|
||||||
1
dist/datasource-zabbix/zabbixAPICore.service.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["../../src/datasource-zabbix/zabbixAPICore.service.js"],"names":["angular","ZabbixAPICoreService","backendSrv","api_url","method","params","options","auth","requestData","jsonrpc","id","Promise","reject","ZabbixAPIError","data","requestOptions","url","headers","basicAuth","withCredentials","Authorization","datasourceRequest","then","response","error","result","username","password","user","request","code","name","message","module","service"],"mappings":";;;;;;;;;;;;;;;AAIOA,a;;;;;;;;;;;;;;;;;;;;;AAEDC,0B;;AAEJ;AACA,sCAAYC,UAAZ,EAAwB;AAAA;;AACtB,eAAKA,UAAL,GAAkBA,UAAlB;AACD;;AAED;;;;;;;;kCAIQC,O,EAASC,M,EAAQC,M,EAAQC,O,EAASC,I,EAAM;AAC9C,gBAAIC,cAAc;AAChBC,uBAAS,KADO;AAEhBL,sBAAQA,MAFQ;AAGhBC,sBAAQA,MAHQ;AAIhBK,kBAAI;AAJY,aAAlB;;AAOA,gBAAIH,SAAS,EAAb,EAAiB;AACf;AACA,qBAAOI,QAAQC,MAAR,CAAe,IAAIC,cAAJ,CAAmB,EAACC,MAAM,iBAAP,EAAnB,CAAf,CAAP;AACD,aAHD,MAGO,IAAIP,IAAJ,EAAU;AACf;AACAC,0BAAYD,IAAZ,GAAmBA,IAAnB;AACD;;AAED,gBAAIQ,iBAAiB;AACnBX,sBAAQ,MADW;AAEnBY,mBAAKb,OAFc;AAGnBW,oBAAMN,WAHa;AAInBS,uBAAS;AACP,gCAAgB;AADT;AAJU,aAArB;;AASA;AACA,gBAAIX,QAAQY,SAAR,IAAqBZ,QAAQa,eAAjC,EAAkD;AAChDJ,6BAAeI,eAAf,GAAiC,IAAjC;AACD;AACD,gBAAIb,QAAQY,SAAZ,EAAuB;AACrBH,6BAAeE,OAAf,CAAuBG,aAAvB,GAAuCd,QAAQY,SAA/C;AACD;;AAED,mBAAO,KAAKG,iBAAL,CAAuBN,cAAvB,CAAP;AACD;;;4CAEiBA,c,EAAgB;AAChC,mBAAO,KAAKb,UAAL,CAAgBmB,iBAAhB,CAAkCN,cAAlC,EACNO,IADM,CACD,oBAAY;AAChB,kBAAI,CAACC,SAAST,IAAd,EAAoB;AAClB,uBAAOH,QAAQC,MAAR,CAAe,IAAIC,cAAJ,CAAmB,EAACC,MAAM,wBAAP,EAAnB,CAAf,CAAP;AACD,eAFD,MAEO,IAAIS,SAAST,IAAT,CAAcU,KAAlB,EAAyB;;AAE9B;AACA,uBAAOb,QAAQC,MAAR,CAAe,IAAIC,cAAJ,CAAmBU,SAAST,IAAT,CAAcU,KAAjC,CAAf,CAAP;AACD;;AAED;AACA,qBAAOD,SAAST,IAAT,CAAcW,MAArB;AACD,aAZM,CAAP;AAaD;;;gCAMKtB,O,EAASuB,Q,EAAUC,Q,EAAUrB,O,EAAS;AAC1C,gBAAID,SAAS;AACXuB,oBAAMF,QADK;AAEXC,wBAAUA;AAFC,aAAb;AAIA,mBAAO,KAAKE,OAAL,CAAa1B,OAAb,EAAsB,YAAtB,EAAoCE,MAApC,EAA4CC,OAA5C,EAAqD,IAArD,CAAP;AACD;;;qCAMUH,O,EAASG,O,EAAS;AAC3B,mBAAO,KAAKuB,OAAL,CAAa1B,OAAb,EAAsB,iBAAtB,EAAyC,EAAzC,EAA6CG,OAA7C,CAAP;AACD;;;;;;gCAIUO,c;AACX,gCAAYW,KAAZ,EAAmB;AAAA;;AACjB,eAAKM,IAAL,GAAYN,MAAMM,IAAlB;AACA,eAAKC,IAAL,GAAYP,MAAMV,IAAlB;AACA,eAAKkB,OAAL,GAAeR,MAAMV,IAArB;AACA,eAAKA,IAAL,GAAYU,MAAMV,IAAlB;AACD;;;;qCAEU;AACT,mBAAO,KAAKiB,IAAL,GAAY,IAAZ,GAAmB,KAAKC,OAA/B;AACD;;;;;;;;AAGHhC,cACGiC,MADH,CACU,kBADV,EAEGC,OAFH,CAEW,sBAFX,EAEmCjC,oBAFnC","file":"zabbixAPICore.service.js","sourcesContent":["/**\n * General Zabbix API methods\n */\n\nimport angular from 'angular';\n\nclass ZabbixAPICoreService {\n\n /** @ngInject */\n constructor(backendSrv) {\n this.backendSrv = backendSrv;\n }\n\n /**\n * Request data from Zabbix API\n * @return {object} response.result\n */\n request(api_url, method, params, options, auth) {\n let requestData = {\n jsonrpc: '2.0',\n method: method,\n params: params,\n id: 1\n };\n\n if (auth === \"\") {\n // Reject immediately if not authenticated\n return Promise.reject(new ZabbixAPIError({data: \"Not authorised.\"}));\n } else if (auth) {\n // Set auth parameter only if it needed\n requestData.auth = auth;\n }\n\n let requestOptions = {\n method: 'POST',\n url: api_url,\n data: requestData,\n headers: {\n 'Content-Type': 'application/json'\n }\n };\n\n // Set request options for basic auth\n if (options.basicAuth || options.withCredentials) {\n requestOptions.withCredentials = true;\n }\n if (options.basicAuth) {\n requestOptions.headers.Authorization = options.basicAuth;\n }\n\n return this.datasourceRequest(requestOptions);\n }\n\n datasourceRequest(requestOptions) {\n return this.backendSrv.datasourceRequest(requestOptions)\n .then(response => {\n if (!response.data) {\n return Promise.reject(new ZabbixAPIError({data: \"General Error, no data\"}));\n } else if (response.data.error) {\n\n // Handle Zabbix API errors\n return Promise.reject(new ZabbixAPIError(response.data.error));\n }\n\n // Success\n return response.data.result;\n });\n }\n\n /**\n * Get authentication token.\n * @return {string} auth token\n */\n login(api_url, username, password, options) {\n let params = {\n user: username,\n password: password\n };\n return this.request(api_url, 'user.login', params, options, null);\n }\n\n /**\n * Get Zabbix API version\n * Matches the version of Zabbix starting from Zabbix 2.0.4\n */\n getVersion(api_url, options) {\n return this.request(api_url, 'apiinfo.version', [], options);\n }\n}\n\n// Define zabbix API exception type\nexport class ZabbixAPIError {\n constructor(error) {\n this.code = error.code;\n this.name = error.data;\n this.message = error.data;\n this.data = error.data;\n }\n\n toString() {\n return this.name + \": \" + this.message;\n }\n}\n\nangular\n .module('grafana.services')\n .service('zabbixAPICoreService', ZabbixAPICoreService);\n"]}
|
||||||
243
dist/datasource-zabbix/zabbixCachingProxy.service.js
vendored
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['angular', 'lodash'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var angular, _, _createClass;
|
||||||
|
|
||||||
|
function _toConsumableArray(arr) {
|
||||||
|
if (Array.isArray(arr)) {
|
||||||
|
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
|
||||||
|
arr2[i] = arr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr2;
|
||||||
|
} else {
|
||||||
|
return Array.from(arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use factory() instead service() for multiple datasources support.
|
||||||
|
// Each datasource instance must initialize its own cache.
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function ZabbixCachingProxyFactory() {
|
||||||
|
var ZabbixCachingProxy = function () {
|
||||||
|
function ZabbixCachingProxy(zabbixAPI, cacheOptions) {
|
||||||
|
_classCallCheck(this, ZabbixCachingProxy);
|
||||||
|
|
||||||
|
this.zabbixAPI = zabbixAPI;
|
||||||
|
this.cacheEnabled = cacheOptions.enabled;
|
||||||
|
this.ttl = cacheOptions.ttl || 600000; // 10 minutes by default
|
||||||
|
|
||||||
|
// Internal objects for data storing
|
||||||
|
this.cache = {
|
||||||
|
groups: {},
|
||||||
|
hosts: {},
|
||||||
|
applications: {},
|
||||||
|
items: {},
|
||||||
|
history: {},
|
||||||
|
trends: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.historyPromises = {};
|
||||||
|
|
||||||
|
// Don't run duplicated history requests
|
||||||
|
this.getHistory = callAPIRequestOnce(_.bind(this.zabbixAPI.getHistory, this.zabbixAPI), this.historyPromises, getHistoryRequestHash);
|
||||||
|
|
||||||
|
// Don't run duplicated requests
|
||||||
|
this.groupPromises = {};
|
||||||
|
this.getGroupsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getGroups, this.zabbixAPI), this.groupPromises, getRequestHash);
|
||||||
|
|
||||||
|
this.hostPromises = {};
|
||||||
|
this.getHostsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getHosts, this.zabbixAPI), this.hostPromises, getRequestHash);
|
||||||
|
|
||||||
|
this.appPromises = {};
|
||||||
|
this.getAppsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getApps, this.zabbixAPI), this.appPromises, getRequestHash);
|
||||||
|
|
||||||
|
this.itemPromises = {};
|
||||||
|
this.getItemsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getItems, this.zabbixAPI), this.itemPromises, getRequestHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(ZabbixCachingProxy, [{
|
||||||
|
key: 'isExpired',
|
||||||
|
value: function isExpired(cacheObject) {
|
||||||
|
if (cacheObject) {
|
||||||
|
var object_age = Date.now() - cacheObject.timestamp;
|
||||||
|
return !(cacheObject.timestamp && object_age < this.ttl);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'proxyRequest',
|
||||||
|
value: function proxyRequest(request, params, cacheObject) {
|
||||||
|
var hash = getRequestHash(params);
|
||||||
|
if (this.cacheEnabled && !this.isExpired(cacheObject[hash])) {
|
||||||
|
return Promise.resolve(cacheObject[hash].value);
|
||||||
|
} else {
|
||||||
|
return request.apply(undefined, _toConsumableArray(params)).then(function (result) {
|
||||||
|
cacheObject[hash] = {
|
||||||
|
value: result,
|
||||||
|
timestamp: Date.now()
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getGroups',
|
||||||
|
value: function getGroups() {
|
||||||
|
return this.proxyRequest(this.getGroupsOnce, [], this.cache.groups);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getHosts',
|
||||||
|
value: function getHosts(groupids) {
|
||||||
|
return this.proxyRequest(this.getHostsOnce, [groupids], this.cache.hosts);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getApps',
|
||||||
|
value: function getApps(hostids) {
|
||||||
|
return this.proxyRequest(this.getAppsOnce, [hostids], this.cache.applications);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getItems',
|
||||||
|
value: function getItems(hostids, appids, itemtype) {
|
||||||
|
var params = [hostids, appids, itemtype];
|
||||||
|
return this.proxyRequest(this.getItemsOnce, params, this.cache.items);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getHistoryFromCache',
|
||||||
|
value: function getHistoryFromCache(items, time_from, time_till) {
|
||||||
|
var historyStorage = this.cache.history;
|
||||||
|
var full_history;
|
||||||
|
var expired = _.filter(_.keyBy(items, 'itemid'), function (item, itemid) {
|
||||||
|
return !historyStorage[itemid];
|
||||||
|
});
|
||||||
|
if (expired.length) {
|
||||||
|
return this.zabbixAPI.getHistory(expired, time_from, time_till).then(function (history) {
|
||||||
|
var grouped_history = _.groupBy(history, 'itemid');
|
||||||
|
_.forEach(expired, function (item) {
|
||||||
|
var itemid = item.itemid;
|
||||||
|
historyStorage[itemid] = item;
|
||||||
|
historyStorage[itemid].time_from = time_from;
|
||||||
|
historyStorage[itemid].time_till = time_till;
|
||||||
|
historyStorage[itemid].history = grouped_history[itemid];
|
||||||
|
});
|
||||||
|
full_history = _.map(items, function (item) {
|
||||||
|
return historyStorage[item.itemid].history;
|
||||||
|
});
|
||||||
|
return _.flatten(full_history, true);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
full_history = _.map(items, function (item) {
|
||||||
|
return historyStorage[item.itemid].history;
|
||||||
|
});
|
||||||
|
return Promise.resolve(_.flatten(full_history, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getHistoryFromAPI',
|
||||||
|
value: function getHistoryFromAPI(items, time_from, time_till) {
|
||||||
|
return this.zabbixAPI.getHistory(items, time_from, time_till);
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixCachingProxy;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return ZabbixCachingProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap zabbix API request to prevent multiple calls
|
||||||
|
* with same params when waiting for result.
|
||||||
|
*/
|
||||||
|
function callAPIRequestOnce(func, promiseKeeper, argsHashFunc) {
|
||||||
|
return function () {
|
||||||
|
var hash = argsHashFunc(arguments);
|
||||||
|
if (!promiseKeeper[hash]) {
|
||||||
|
promiseKeeper[hash] = Promise.resolve(func.apply(this, arguments).then(function (result) {
|
||||||
|
promiseKeeper[hash] = null;
|
||||||
|
return result;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return promiseKeeper[hash];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRequestHash(args) {
|
||||||
|
var requestStamp = _.map(args, function (arg) {
|
||||||
|
if (arg === undefined) {
|
||||||
|
return 'undefined';
|
||||||
|
} else {
|
||||||
|
if (_.isArray(arg)) {
|
||||||
|
return arg.sort().toString();
|
||||||
|
} else {
|
||||||
|
return arg.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).join();
|
||||||
|
return requestStamp.getHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHistoryRequestHash(args) {
|
||||||
|
var itemids = _.map(args[0], 'itemid');
|
||||||
|
var stamp = itemids.join() + args[1] + args[2];
|
||||||
|
return stamp.getHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setters: [function (_angular) {
|
||||||
|
angular = _angular.default;
|
||||||
|
}, function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
_createClass = function () {
|
||||||
|
function defineProperties(target, props) {
|
||||||
|
for (var i = 0; i < props.length; i++) {
|
||||||
|
var descriptor = props[i];
|
||||||
|
descriptor.enumerable = descriptor.enumerable || false;
|
||||||
|
descriptor.configurable = true;
|
||||||
|
if ("value" in descriptor) descriptor.writable = true;
|
||||||
|
Object.defineProperty(target, descriptor.key, descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (Constructor, protoProps, staticProps) {
|
||||||
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
||||||
|
if (staticProps) defineProperties(Constructor, staticProps);
|
||||||
|
return Constructor;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
angular.module('grafana.services').factory('ZabbixCachingProxy', ZabbixCachingProxyFactory);String.prototype.getHash = function () {
|
||||||
|
var hash = 0,
|
||||||
|
i,
|
||||||
|
chr,
|
||||||
|
len;
|
||||||
|
if (this.length !== 0) {
|
||||||
|
for (i = 0, len = this.length; i < len; i++) {
|
||||||
|
chr = this.charCodeAt(i);
|
||||||
|
hash = (hash << 5) - hash + chr;
|
||||||
|
hash |= 0; // Convert to 32bit integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fix for backward compatibility with lodash 2.4
|
||||||
|
if (!_.keyBy) {
|
||||||
|
_.keyBy = _.indexBy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=zabbixCachingProxy.service.js.map
|
||||||
1
dist/datasource-zabbix/zabbixCachingProxy.service.js.map
vendored
Normal file
BIN
dist/img/screenshot-annotations.png
vendored
Normal file
|
After Width: | Height: | Size: 173 KiB |
BIN
dist/img/screenshot-dashboard01.png
vendored
Normal file
|
After Width: | Height: | Size: 371 KiB |
BIN
dist/img/screenshot-metric_editor.png
vendored
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
dist/img/screenshot-showcase.png
vendored
Normal file
|
After Width: | Height: | Size: 255 KiB |
BIN
dist/img/screenshot-triggers.png
vendored
Normal file
|
After Width: | Height: | Size: 168 KiB |
107
dist/img/zabbix_app_logo.svg
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.0"
|
||||||
|
id="Layer_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
width="100px"
|
||||||
|
height="100px"
|
||||||
|
viewBox="692 0 100 100"
|
||||||
|
style="enable-background:new 692 0 100 100;"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:version="0.91 r"
|
||||||
|
sodipodi:docname="zabbix_app_logo.svg"
|
||||||
|
enable-background="new"><metadata
|
||||||
|
id="metadata13"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs11"><linearGradient
|
||||||
|
id="SVGID_1_"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="2.6005001"
|
||||||
|
y1="65.475197"
|
||||||
|
x2="94.377701"
|
||||||
|
y2="30.245199"><stop
|
||||||
|
id="stop34"
|
||||||
|
style="stop-color:#58595B"
|
||||||
|
offset="0.2583" /><stop
|
||||||
|
id="stop32"
|
||||||
|
style="stop-color:#646C70"
|
||||||
|
offset="0.2917" /><stop
|
||||||
|
id="stop30"
|
||||||
|
style="stop-color:#6C8087"
|
||||||
|
offset="0.3398" /><stop
|
||||||
|
id="stop28"
|
||||||
|
style="stop-color:#6D8F9B"
|
||||||
|
offset="0.3927" /><stop
|
||||||
|
id="stop26"
|
||||||
|
style="stop-color:#689BAA"
|
||||||
|
offset="0.4499" /><stop
|
||||||
|
id="stop24"
|
||||||
|
style="stop-color:#5FA3B5"
|
||||||
|
offset="0.5128" /><stop
|
||||||
|
id="stop22"
|
||||||
|
style="stop-color:#53A8BD"
|
||||||
|
offset="0.5837" /><stop
|
||||||
|
id="stop20"
|
||||||
|
style="stop-color:#47ABC2"
|
||||||
|
offset="0.6674" /><stop
|
||||||
|
id="stop18"
|
||||||
|
style="stop-color:#3FAEC5"
|
||||||
|
offset="0.7759" /><stop
|
||||||
|
id="stop16"
|
||||||
|
style="stop-color:#3CAFC7"
|
||||||
|
offset="1" /><stop
|
||||||
|
id="stop14"
|
||||||
|
style="stop-color:#3BB0C9"
|
||||||
|
offset="1" /></linearGradient></defs><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1615"
|
||||||
|
inkscape:window-height="1026"
|
||||||
|
id="namedview9"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="4.285"
|
||||||
|
inkscape:cx="50.424685"
|
||||||
|
inkscape:cy="23.581186"
|
||||||
|
inkscape:window-x="65"
|
||||||
|
inkscape:window-y="24"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="g5194" /><style
|
||||||
|
type="text/css"
|
||||||
|
id="style3">
|
||||||
|
.st0{fill:#787878;}
|
||||||
|
</style><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="g5194"
|
||||||
|
inkscape:label="Zabbix BG Original"
|
||||||
|
style="display:inline"><rect
|
||||||
|
style="fill:#d40000;fill-opacity:1"
|
||||||
|
id="rect5196"
|
||||||
|
width="100"
|
||||||
|
height="100"
|
||||||
|
x="692"
|
||||||
|
y="0" /></g><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer6"
|
||||||
|
inkscape:label="Zabbix Original Z"
|
||||||
|
style="display:inline"><path
|
||||||
|
d="m 715.54426,16.689227 52.91147,0 0,6.87033 -42.58255,52.167008 43.62047,0 0,7.584207 -54.9873,0 0,-6.871516 42.58255,-52.166552 -41.54464,0 0,-7.583477 z"
|
||||||
|
style="display:inline;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||||
|
id="path4169-6"
|
||||||
|
inkscape:connector-curvature="0" /></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.5 KiB |
16
dist/module.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['./components/config'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var ZabbixAppConfigCtrl;
|
||||||
|
return {
|
||||||
|
setters: [function (_componentsConfig) {
|
||||||
|
ZabbixAppConfigCtrl = _componentsConfig.ZabbixAppConfigCtrl;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
_export('ConfigCtrl', ZabbixAppConfigCtrl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=module.js.map
|
||||||
1
dist/module.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["../src/module.js"],"names":["ZabbixAppConfigCtrl"],"mappings":";;;;;;;;AAAQA,yB,qBAAAA,mB;;;4BAGNA,mB","file":"module.js","sourcesContent":["import {ZabbixAppConfigCtrl} from './components/config';\n\nexport {\n ZabbixAppConfigCtrl as ConfigCtrl\n};\n"]}
|
||||||
126
dist/panel-triggers/ack-tooltip.directive.js
vendored
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['angular', 'jquery', 'tether-drop'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var angular, $, Drop;
|
||||||
|
return {
|
||||||
|
setters: [function (_angular) {
|
||||||
|
angular = _angular.default;
|
||||||
|
}, function (_jquery) {
|
||||||
|
$ = _jquery.default;
|
||||||
|
}, function (_tetherDrop) {
|
||||||
|
Drop = _tetherDrop.default;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
angular.module('grafana.directives').directive('ackTooltip', function ($sanitize, $compile) {
|
||||||
|
var buttonTemplate = '<a bs-tooltip="\'Acknowledges ({{trigger.acknowledges.length}})\'"' + '<i ng-class="' + "{'fa fa-comments': trigger.acknowledges.length, " + "'fa fa-comments-o': !trigger.acknowledges.length, " + '}"></i></a>';
|
||||||
|
|
||||||
|
return {
|
||||||
|
scope: {
|
||||||
|
ack: "=",
|
||||||
|
trigger: "=",
|
||||||
|
onAck: "=",
|
||||||
|
context: "="
|
||||||
|
},
|
||||||
|
link: function link(scope, element) {
|
||||||
|
var acknowledges = scope.ack;
|
||||||
|
var $button = $(buttonTemplate);
|
||||||
|
$button.appendTo(element);
|
||||||
|
|
||||||
|
$button.click(function () {
|
||||||
|
var tooltip = '<div>';
|
||||||
|
|
||||||
|
if (acknowledges && acknowledges.length) {
|
||||||
|
tooltip += '<table class="table"><thead><tr>' + '<th class="ack-time">Time</th>' + '<th class="ack-user">User</th>' + '<th class="ack-comments">Comments</th>' + '</tr></thead><tbody>';
|
||||||
|
var _iteratorNormalCompletion = true;
|
||||||
|
var _didIteratorError = false;
|
||||||
|
var _iteratorError = undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (var _iterator = acknowledges[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||||
|
var ack = _step.value;
|
||||||
|
|
||||||
|
tooltip += '<tr><td>' + ack.time + '</td>' + '<td>' + ack.user + '</td>' + '<td>' + ack.message + '</td></tr>';
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
_didIteratorError = true;
|
||||||
|
_iteratorError = err;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
||||||
|
_iterator.return();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (_didIteratorError) {
|
||||||
|
throw _iteratorError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltip += '</tbody></table>';
|
||||||
|
} else {
|
||||||
|
tooltip += 'Add acknowledge';
|
||||||
|
}
|
||||||
|
|
||||||
|
var addAckButtonTemplate = '<div class="ack-add-button">' + '<button id="add-acknowledge-btn"' + 'class="btn btn-mini btn-inverse gf-form-button">' + '<i class="fa fa-plus"></i>' + '</button></div>';
|
||||||
|
tooltip += addAckButtonTemplate;
|
||||||
|
tooltip += '</div>';
|
||||||
|
|
||||||
|
var drop = new Drop({
|
||||||
|
target: element[0],
|
||||||
|
content: tooltip,
|
||||||
|
position: "bottom left",
|
||||||
|
classes: 'drop-popover ack-tooltip',
|
||||||
|
openOn: 'hover',
|
||||||
|
hoverCloseDelay: 500,
|
||||||
|
tetherOptions: {
|
||||||
|
constraints: [{ to: 'window', pin: true, attachment: "both" }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
drop.open();
|
||||||
|
drop.on('close', closeDrop);
|
||||||
|
|
||||||
|
$('#add-acknowledge-btn').on('click', onAddAckButtonClick);
|
||||||
|
|
||||||
|
function onAddAckButtonClick() {
|
||||||
|
var inputTemplate = '<div class="ack-input-group">' + '<input type="text" id="ack-message">' + '<button id="send-ack-button"' + 'class="btn btn-mini btn-inverse gf-form-button">' + 'Acknowledge </button>' + '<button id="cancel-ack-button"' + 'class="btn btn-mini btn-inverse gf-form-button">' + 'Cancel' + '</button></input></div>';
|
||||||
|
|
||||||
|
var $input = $(inputTemplate);
|
||||||
|
var $addAckButton = $('.ack-tooltip .ack-add-button');
|
||||||
|
$addAckButton.replaceWith($input);
|
||||||
|
$('.ack-tooltip #cancel-ack-button').on('click', onAckCancelButtonClick);
|
||||||
|
$('.ack-tooltip #send-ack-button').on('click', onAckSendlButtonClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAckCancelButtonClick() {
|
||||||
|
$('.ack-tooltip .ack-input-group').replaceWith(addAckButtonTemplate);
|
||||||
|
$('#add-acknowledge-btn').on('click', onAddAckButtonClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAckSendlButtonClick() {
|
||||||
|
var message = $('.ack-tooltip #ack-message')[0].value;
|
||||||
|
var onAck = scope.onAck.bind(scope.context);
|
||||||
|
onAck(scope.trigger, message).then(function () {
|
||||||
|
closeDrop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDrop() {
|
||||||
|
setTimeout(function () {
|
||||||
|
drop.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$compile(element.contents())(scope);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=ack-tooltip.directive.js.map
|
||||||
1
dist/panel-triggers/ack-tooltip.directive.js.map
vendored
Normal file
96
dist/panel-triggers/css/panel_triggers.css
vendored
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
.triggers-panel-wrapper .panel-content {
|
||||||
|
padding: 0; }
|
||||||
|
|
||||||
|
.triggers-panel-wrapper .panel-title-container {
|
||||||
|
padding-bottom: 4px; }
|
||||||
|
|
||||||
|
.triggers-panel-scroll {
|
||||||
|
overflow: auto; }
|
||||||
|
|
||||||
|
.triggers-panel-container {
|
||||||
|
padding-top: 2.2em;
|
||||||
|
position: relative; }
|
||||||
|
|
||||||
|
.triggers-panel-footer {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 90%;
|
||||||
|
line-height: 2px; }
|
||||||
|
.triggers-panel-footer ul {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-bottom: 0; }
|
||||||
|
.triggers-panel-footer ul > li {
|
||||||
|
display: inline; }
|
||||||
|
.triggers-panel-footer ul > li > a {
|
||||||
|
float: left;
|
||||||
|
padding: 4px 12px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-left-width: 0; }
|
||||||
|
.triggers-panel-footer ul > li > a:hover {
|
||||||
|
background-color: #333; }
|
||||||
|
.triggers-panel-footer ul > li > a.active {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #33B5E5; }
|
||||||
|
|
||||||
|
.triggers-panel-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse; }
|
||||||
|
.triggers-panel-table th {
|
||||||
|
padding: 0; }
|
||||||
|
.triggers-panel-table th:first-child .triggers-panel-table-header-inner {
|
||||||
|
padding-left: 15px; }
|
||||||
|
.triggers-panel-table td {
|
||||||
|
padding: 0.45em 0 0.45em 1.1em;
|
||||||
|
border-bottom: 2px solid #141414;
|
||||||
|
border-right: 2px solid #141414; }
|
||||||
|
.triggers-panel-table td:first-child {
|
||||||
|
padding-left: 15px; }
|
||||||
|
.triggers-panel-table td:last-child {
|
||||||
|
border-right: none; }
|
||||||
|
|
||||||
|
.triggers-panel-header-bg {
|
||||||
|
background: #242222;
|
||||||
|
border-top: 2px solid #141414;
|
||||||
|
border-bottom: 2px solid #141414;
|
||||||
|
height: 2.0em;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0; }
|
||||||
|
|
||||||
|
.triggers-panel-table-header-inner {
|
||||||
|
padding: 0.45em 0 0.45em 1.1em;
|
||||||
|
text-align: left;
|
||||||
|
color: #33B5E5;
|
||||||
|
position: absolute;
|
||||||
|
top: 0; }
|
||||||
|
|
||||||
|
.triggers-panel-width-hack {
|
||||||
|
visibility: hidden;
|
||||||
|
height: 0px;
|
||||||
|
line-height: 0px; }
|
||||||
|
|
||||||
|
.ack-tooltip .drop-content {
|
||||||
|
max-width: 70rem !important;
|
||||||
|
min-width: 30rem !important; }
|
||||||
|
|
||||||
|
.ack-tooltip .ack-comments {
|
||||||
|
width: 60%; }
|
||||||
|
|
||||||
|
.ack-tooltip .ack-add-button {
|
||||||
|
padding-top: 1rem; }
|
||||||
|
|
||||||
|
.ack-tooltip table td, .ack-tooltip th {
|
||||||
|
padding-right: 1rem; }
|
||||||
|
|
||||||
|
.ack-tooltip .ack-input-group {
|
||||||
|
padding-top: 1rem; }
|
||||||
|
.ack-tooltip .ack-input-group input {
|
||||||
|
border: 1px solid;
|
||||||
|
border-radius: 2px;
|
||||||
|
width: 50%; }
|
||||||
|
.ack-tooltip .ack-input-group button {
|
||||||
|
margin-left: 1rem; }
|
||||||
|
|
||||||
|
/*# sourceMappingURL=panel_triggers.css.map */
|
||||||
9
dist/panel-triggers/css/panel_triggers.css.map
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"file": "panel_triggers.css",
|
||||||
|
"sources": [
|
||||||
|
"../../../src/panel-triggers/sass/panel_triggers.scss"
|
||||||
|
],
|
||||||
|
"mappings": "AAOA,AACE,uBADqB,CACrB,cAAc,CAAC;EACb,OAAO,EAAE,CAAE,GACZ;;AAHH,AAIE,uBAJqB,CAIrB,sBAAsB,CAAC;EACrB,cAAc,EAAE,GAAI,GACrB;;AAGH,AAAA,sBAAsB,CAAC;EACrB,QAAQ,EAAE,IAAK,GAChB;;AAED,AAAA,yBAAyB,CAAC;EACxB,WAAW,EAAE,KAAM;EACnB,QAAQ,EAAE,QAAS,GACpB;;AAED,AAAA,sBAAsB,CAAC;EACrB,UAAU,EAAE,MAAO;EACnB,SAAS,EAAE,GAAI;EACf,WAAW,EAAE,GAAI,GA0BlB;EA7BD,AAKE,sBALoB,CAKpB,EAAE,CAAC;IACD,QAAQ,EAAE,QAAS;IACnB,OAAO,EAAE,YAAa;IACtB,WAAW,EAAE,CAAE;IACf,aAAa,EAAE,CAAE,GAClB;EAVH,AAWO,sBAXe,CAWpB,EAAE,GAAG,EAAE,CAAC;IACN,OAAO,EAAE,MAAO,GACjB;EAbH,AAcY,sBAdU,CAcpB,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACV,KAAK,EAAE,IAAK;IACZ,OAAO,EAAE,QAAS;IAClB,eAAe,EAAE,IAAK;IACtB,iBAAiB,EAAE,CAAE,GAUtB;IA5BH,AAcY,sBAdU,CAcpB,EAAE,GAAG,EAAE,GAAG,CAAC,AAMR,MAAM,CAAC;MACN,gBAAgB,EA9CM,IAAI,GA+C3B;IAtBL,AAcY,sBAdU,CAcpB,EAAE,GAAG,EAAE,GAAG,CAAC,AAUR,OAAO,CAAC;MACP,WAAW,EAAE,IAAK;MAClB,KAAK,EAlDc,OAAO,GAmD3B;;AAIL,AAAA,qBAAqB,CAAC;EACpB,KAAK,EAAE,IAAK;EACZ,eAAe,EAAE,QAAS,GAwB3B;EA1BD,AAIE,qBAJmB,CAInB,EAAE,CAAC;IACD,OAAO,EAAE,CAAE,GAOZ;IAZH,AAQM,qBARe,CAInB,EAAE,AAGC,YAAY,CACX,kCAAkC,CAAC;MACjC,YAAY,EAAE,IAAK,GACpB;EAVP,AAcE,qBAdmB,CAcnB,EAAE,CAAC;IACD,OAAO,EAAE,qBAAsB;IAC/B,aAAa,EAAE,GAAG,CAAC,KAAK,CArET,OAAG;IAsElB,YAAY,EAAE,GAAG,CAAC,KAAK,CAtER,OAAG,GA8EnB;IAzBH,AAcE,qBAdmB,CAcnB,EAAE,AAKC,YAAY,CAAC;MACZ,YAAY,EAAE,IAAK,GACpB;IArBL,AAcE,qBAdmB,CAcnB,EAAE,AAQC,WAAW,CAAC;MACX,YAAY,EAAE,IAAK,GACpB;;AAIL,AAAA,yBAAyB,CAAC;EACxB,UAAU,EAhFgB,OAAO;EAiFjC,UAAU,EAAE,GAAG,CAAC,KAAK,CAnFJ,OAAG;EAoFpB,aAAa,EAAE,GAAG,CAAC,KAAK,CApFP,OAAG;EAqFpB,MAAM,EAAE,KAAM;EACd,QAAQ,EAAE,QAAS;EACnB,GAAG,EAAE,CAAE;EACP,KAAK,EAAE,CAAE;EACT,IAAI,EAAE,CAAE,GACT;;AAED,AAAA,kCAAkC,CAAC;EACjC,OAAO,EAAE,qBAAsB;EAC/B,UAAU,EAAE,IAAK;EACjB,KAAK,EAjGkB,OAAO;EAkG9B,QAAQ,EAAE,QAAS;EACnB,GAAG,EAAE,CAAE,GACR;;AAED,AAAA,0BAA0B,CAAC;EACzB,UAAU,EAAE,MAAO;EACnB,MAAM,EAAE,GAAI;EACZ,WAAW,EAAE,GAAI,GAClB;;AAED,AACE,YADU,CACV,aAAa,CAAC;EAEZ,SAAS,EAAE,gBAAiB;EAC5B,SAAS,EAAE,gBAAiB,GAC7B;;AALH,AAOE,YAPU,CAOV,aAAa,CAAC;EACZ,KAAK,EAAE,GAAI,GACZ;;AATH,AAWE,YAXU,CAWV,eAAe,CAAC;EACd,WAAW,EAAE,IAAK,GACnB;;AAbH,AAeQ,YAfI,CAeV,KAAK,CAAC,EAAE,EAfV,AAeY,YAfA,CAeA,EAAE,CAAC;EACX,aAAa,EAAE,IAAK,GACrB;;AAjBH,AAmBE,YAnBU,CAmBV,gBAAgB,CAAC;EACf,WAAW,EAAE,IAAK,GAWnB;EA/BH,AAsBI,YAtBQ,CAmBV,gBAAgB,CAGd,KAAK,CAAC;IACJ,MAAM,EAAE,SAAU;IAClB,aAAa,EAAE,GAAI;IACnB,KAAK,EAAE,GAAI,GACZ;EA1BL,AA4BI,YA5BQ,CAmBV,gBAAgB,CASd,MAAM,CAAC;IACL,WAAW,EAAE,IAAK,GACnB",
|
||||||
|
"names": []
|
||||||
|
}
|
||||||
256
dist/panel-triggers/editor.html
vendored
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
<div class="editor-row">
|
||||||
|
<div class="section gf-form-group">
|
||||||
|
<h5 class="section-heading">Select triggers</h5>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form max-width-20">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Group</label>
|
||||||
|
<input type="text"
|
||||||
|
ng-model="editor.panel.triggers.group.filter"
|
||||||
|
bs-typeahead="editor.getGroupNames"
|
||||||
|
ng-blur="editor.parseTarget()"
|
||||||
|
data-min-length=0
|
||||||
|
data-items=100
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-class="{
|
||||||
|
'zbx-variable': editor.isVariable(editor.panel.triggers.group.filter),
|
||||||
|
'zbx-regex': editor.isRegex(editor.panel.triggers.group.filter)
|
||||||
|
}">
|
||||||
|
</div>
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Host</label>
|
||||||
|
<input type="text"
|
||||||
|
ng-model="editor.panel.triggers.host.filter"
|
||||||
|
bs-typeahead="editor.getHostNames"
|
||||||
|
ng-blur="editor.parseTarget()"
|
||||||
|
data-min-length=0
|
||||||
|
data-items=100
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-class="{
|
||||||
|
'zbx-variable': editor.isVariable(editor.panel.triggers.host.filter),
|
||||||
|
'zbx-regex': editor.isRegex(editor.panel.triggers.host.filter)
|
||||||
|
}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form max-width-20">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Application</label>
|
||||||
|
<input type="text"
|
||||||
|
ng-model="editor.panel.triggers.application.filter"
|
||||||
|
bs-typeahead="editor.getApplicationNames"
|
||||||
|
ng-blur="editor.parseTarget()"
|
||||||
|
data-min-length=0
|
||||||
|
data-items=100
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-class="{
|
||||||
|
'zbx-variable': editor.isVariable(editor.panel.triggers.application.filter),
|
||||||
|
'zbx-regex': editor.isRegex(editor.panel.triggers.application.filter)
|
||||||
|
}">
|
||||||
|
</div>
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Trigger</label>
|
||||||
|
<input type="text"
|
||||||
|
ng-model="editor.panel.triggers.trigger.filter"
|
||||||
|
ng-blur="editor.parseTarget()"
|
||||||
|
placeholder="trigger name"
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-style="editor.panel.triggers.trigger.style"
|
||||||
|
empty-to-null>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section gf-form-group">
|
||||||
|
<h5 class="section-heading">Data source</h5>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<div class="gf-form-select-wrapper">
|
||||||
|
<select class="gf-form-input"
|
||||||
|
ng-model="editor.panel.datasource"
|
||||||
|
ng-options="ds for ds in editor.datasources"
|
||||||
|
ng-change="editor.datasourceChanged()">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="editor-row">
|
||||||
|
<div class="section gf-form-group">
|
||||||
|
<h5 class="section-heading">Options</h5>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label width-8">Acknowledged</label>
|
||||||
|
<div class="gf-form-select-wrapper">
|
||||||
|
<select class="gf-form-input"
|
||||||
|
ng-model="editor.panel.showTriggers"
|
||||||
|
ng-options="f for f in editor.ackFilters"
|
||||||
|
ng-change="editor.panelCtrl.refresh()">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label width-12">Limit triggers number to</label>
|
||||||
|
<input class="gf-form-input width-5"
|
||||||
|
type="number"
|
||||||
|
ng-model="editor.panel.limit"
|
||||||
|
ng-model-onblur
|
||||||
|
ng-change="editor.panelCtrl.refresh()">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label width-8">Sort by</label>
|
||||||
|
<div class="gf-form-select-wrapper">
|
||||||
|
<select class="gf-form-input"
|
||||||
|
ng-model="editor.panel.sortTriggersBy"
|
||||||
|
ng-options="f.text for f in editor.sortByFields track by f.value"
|
||||||
|
ng-change="editor.panelCtrl.refresh()">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label width-8">Show events</label>
|
||||||
|
<div class="gf-form-select-wrapper">
|
||||||
|
<select class="gf-form-input"
|
||||||
|
ng-model="editor.panel.showEvents"
|
||||||
|
ng-options="f.text for f in editor.showEventsFields track by f.value"
|
||||||
|
ng-change="editor.panelCtrl.refresh()">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section gf-form-group">
|
||||||
|
<h5 class="section-heading">Show fields</h5>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label-class="width-8"
|
||||||
|
label="Host name"
|
||||||
|
checked="editor.panel.hostField"
|
||||||
|
on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label-class="width-12"
|
||||||
|
label="Host technical name"
|
||||||
|
checked="editor.panel.hostTechNameField"
|
||||||
|
on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label-class="width-5"
|
||||||
|
label="Status"
|
||||||
|
checked="editor.panel.statusField"
|
||||||
|
on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label-class="width-5"
|
||||||
|
label="Severity"
|
||||||
|
checked="editor.panel.severityField"
|
||||||
|
on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label-class="width-7"
|
||||||
|
label="Last change"
|
||||||
|
checked="editor.panel.lastChangeField"
|
||||||
|
on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label-class="width-4"
|
||||||
|
label="Age"
|
||||||
|
checked="editor.panel.ageField"
|
||||||
|
on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label-class="width-4"
|
||||||
|
label="Info"
|
||||||
|
checked="editor.panel.infoField"
|
||||||
|
on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label-class="width-14"
|
||||||
|
label="Custom Last change format"
|
||||||
|
checked="editor.panel.customLastChangeFormat"
|
||||||
|
on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
<div class="gf-form" ng-if="editor.panel.customLastChangeFormat">
|
||||||
|
<label class="gf-form-label width-3">
|
||||||
|
<a href="http://momentjs.com/docs/#/displaying/format/" target="_blank">
|
||||||
|
<tip>See moment.js dosc for time format.</tip>
|
||||||
|
</a>
|
||||||
|
</label>
|
||||||
|
<input class="gf-form-input width-18"
|
||||||
|
type="text"
|
||||||
|
placeholder="dddd, MMMM Do YYYY, h:mm:ss a"
|
||||||
|
empty-to-null
|
||||||
|
ng-model-onblur
|
||||||
|
ng-model="editor.panel.lastChangeFormat"
|
||||||
|
ng-change="editor.panelCtrl.refresh()">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="editor-row">
|
||||||
|
<div class="section gf-form-group">
|
||||||
|
<h5 class="section-heading">Customize triggers severity and colors</h5>
|
||||||
|
<div class="gf-form-inline" ng-repeat="trigger in editor.panel.triggerSeverity">
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label width-3">{{ trigger.priority }}</label>
|
||||||
|
<input type="text"
|
||||||
|
class="gf-form-input width-12"
|
||||||
|
empty-to-null
|
||||||
|
ng-model="trigger.severity"
|
||||||
|
style="color: white"
|
||||||
|
ng-style="{background: trigger.color}"
|
||||||
|
ng-model-onblur
|
||||||
|
ng-change="editor.panelCtrl.refresh()">
|
||||||
|
<span class="gf-form-label">
|
||||||
|
<spectrum-picker ng-model="trigger.color" ng-change="editor.panelCtrl.refresh()"></spectrum-picker>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label-class="width-0"
|
||||||
|
label="Show"
|
||||||
|
checked="trigger.show"
|
||||||
|
on-change="editor.panelCtrl.refresh()">
|
||||||
|
</gf-form-switch>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label width-3"> </label>
|
||||||
|
<label class="gf-form-label width-12"
|
||||||
|
ng-style="{background:editor.panel.okEventColor}">
|
||||||
|
OK event color
|
||||||
|
</label>
|
||||||
|
<span class="gf-form-label">
|
||||||
|
<spectrum-picker ng-model="editor.panel.okEventColor" ng-change="editor.panelCtrl.refresh()"></spectrum-picker>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label width-3"> </label>
|
||||||
|
<label class="gf-form-label width-12"
|
||||||
|
ng-style="{background:editor.panel.ackEventColor}">
|
||||||
|
Acknowledged color
|
||||||
|
</label>
|
||||||
|
<span class="gf-form-label">
|
||||||
|
<spectrum-picker ng-model="editor.panel.ackEventColor" ng-change="editor.panelCtrl.refresh()"></spectrum-picker>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label-class="width-0"
|
||||||
|
label="Show"
|
||||||
|
checked="editor.panel.markAckEvents"
|
||||||
|
on-change="editor.panelCtrl.refresh()">
|
||||||
|
</gf-form-switch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
225
dist/panel-triggers/editor.js
vendored
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['lodash', '../datasource-zabbix/utils', '../datasource-zabbix/css/query-editor.css!'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _, utils, _createClass, TriggerPanelEditorCtrl;
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get list of metric names for bs-typeahead directive
|
||||||
|
function getMetricNames(scope, metricList) {
|
||||||
|
return _.uniq(_.map(scope.metric[metricList], 'name'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function triggerPanelEditor() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: true,
|
||||||
|
templateUrl: 'public/plugins/alexanderzobnin-zabbix-app/panel-triggers/editor.html',
|
||||||
|
controller: TriggerPanelEditorCtrl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_export('triggerPanelEditor', triggerPanelEditor);
|
||||||
|
|
||||||
|
return {
|
||||||
|
setters: [function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}, function (_datasourceZabbixUtils) {
|
||||||
|
utils = _datasourceZabbixUtils;
|
||||||
|
}, function (_datasourceZabbixCssQueryEditorCss) {}],
|
||||||
|
execute: function () {
|
||||||
|
_createClass = function () {
|
||||||
|
function defineProperties(target, props) {
|
||||||
|
for (var i = 0; i < props.length; i++) {
|
||||||
|
var descriptor = props[i];
|
||||||
|
descriptor.enumerable = descriptor.enumerable || false;
|
||||||
|
descriptor.configurable = true;
|
||||||
|
if ("value" in descriptor) descriptor.writable = true;
|
||||||
|
Object.defineProperty(target, descriptor.key, descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (Constructor, protoProps, staticProps) {
|
||||||
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
||||||
|
if (staticProps) defineProperties(Constructor, staticProps);
|
||||||
|
return Constructor;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
TriggerPanelEditorCtrl = function () {
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function TriggerPanelEditorCtrl($scope, $rootScope, uiSegmentSrv, datasourceSrv, templateSrv, popoverSrv) {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
_classCallCheck(this, TriggerPanelEditorCtrl);
|
||||||
|
|
||||||
|
$scope.editor = this;
|
||||||
|
this.panelCtrl = $scope.ctrl;
|
||||||
|
this.panel = this.panelCtrl.panel;
|
||||||
|
|
||||||
|
this.datasourceSrv = datasourceSrv;
|
||||||
|
this.templateSrv = templateSrv;
|
||||||
|
this.popoverSrv = popoverSrv;
|
||||||
|
|
||||||
|
// Map functions for bs-typeahead
|
||||||
|
this.getGroupNames = _.partial(getMetricNames, this, 'groupList');
|
||||||
|
this.getHostNames = _.partial(getMetricNames, this, 'hostList');
|
||||||
|
this.getApplicationNames = _.partial(getMetricNames, this, 'appList');
|
||||||
|
|
||||||
|
// Update metric suggestion when template variable was changed
|
||||||
|
$rootScope.$on('template-variable-value-updated', function () {
|
||||||
|
return _this.onVariableChange();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ackFilters = ['all triggers', 'unacknowledged', 'acknowledged'];
|
||||||
|
|
||||||
|
this.sortByFields = [{ text: 'last change', value: 'lastchange' }, { text: 'severity', value: 'priority' }];
|
||||||
|
|
||||||
|
this.showEventsFields = [{ text: 'All', value: [0, 1] }, { text: 'OK', value: [0] }, { text: 'Problems', value: 1 }];
|
||||||
|
|
||||||
|
// Load scope defaults
|
||||||
|
var scopeDefaults = {
|
||||||
|
metric: {},
|
||||||
|
inputStyles: {},
|
||||||
|
oldTarget: _.cloneDeep(this.panel.triggers)
|
||||||
|
};
|
||||||
|
_.defaults(this, scopeDefaults);
|
||||||
|
|
||||||
|
// Set default datasource
|
||||||
|
this.datasources = _.map(this.getZabbixDataSources(), 'name');
|
||||||
|
if (!this.panel.datasource) {
|
||||||
|
this.panel.datasource = this.datasources[0];
|
||||||
|
}
|
||||||
|
// Load datasource
|
||||||
|
this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
|
||||||
|
_this.datasource = datasource;
|
||||||
|
_this.zabbix = datasource.zabbix;
|
||||||
|
_this.queryBuilder = datasource.queryBuilder;
|
||||||
|
_this.initFilters();
|
||||||
|
_this.panelCtrl.refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(TriggerPanelEditorCtrl, [{
|
||||||
|
key: 'initFilters',
|
||||||
|
value: function initFilters() {
|
||||||
|
return Promise.all([this.suggestGroups(), this.suggestHosts(), this.suggestApps()]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestGroups',
|
||||||
|
value: function suggestGroups() {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
return this.zabbix.getAllGroups().then(function (groups) {
|
||||||
|
_this2.metric.groupList = groups;
|
||||||
|
return groups;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestHosts',
|
||||||
|
value: function suggestHosts() {
|
||||||
|
var _this3 = this;
|
||||||
|
|
||||||
|
var groupFilter = this.datasource.replaceTemplateVars(this.panel.triggers.group.filter);
|
||||||
|
return this.zabbix.getAllHosts(groupFilter).then(function (hosts) {
|
||||||
|
_this3.metric.hostList = hosts;
|
||||||
|
return hosts;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestApps',
|
||||||
|
value: function suggestApps() {
|
||||||
|
var _this4 = this;
|
||||||
|
|
||||||
|
var groupFilter = this.datasource.replaceTemplateVars(this.panel.triggers.group.filter);
|
||||||
|
var hostFilter = this.datasource.replaceTemplateVars(this.panel.triggers.host.filter);
|
||||||
|
return this.zabbix.getAllApps(groupFilter, hostFilter).then(function (apps) {
|
||||||
|
_this4.metric.appList = apps;
|
||||||
|
return apps;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'onVariableChange',
|
||||||
|
value: function onVariableChange() {
|
||||||
|
if (this.isContainsVariables()) {
|
||||||
|
this.targetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'isContainsVariables',
|
||||||
|
value: function isContainsVariables() {
|
||||||
|
var _this5 = this;
|
||||||
|
|
||||||
|
return _.some(['group', 'host', 'application'], function (field) {
|
||||||
|
return utils.isTemplateVariable(_this5.panel.triggers[field].filter, _this5.templateSrv.variables);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'targetChanged',
|
||||||
|
value: function targetChanged() {
|
||||||
|
this.initFilters();
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'parseTarget',
|
||||||
|
value: function parseTarget() {
|
||||||
|
this.initFilters();
|
||||||
|
var newTarget = _.cloneDeep(this.panel.triggers);
|
||||||
|
if (!_.isEqual(this.oldTarget, this.panel.triggers)) {
|
||||||
|
this.oldTarget = newTarget;
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'refreshTriggerSeverity',
|
||||||
|
value: function refreshTriggerSeverity() {
|
||||||
|
_.each(this.triggerList, function (trigger) {
|
||||||
|
trigger.color = this.panel.triggerSeverity[trigger.priority].color;
|
||||||
|
trigger.severity = this.panel.triggerSeverity[trigger.priority].severity;
|
||||||
|
});
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'datasourceChanged',
|
||||||
|
value: function datasourceChanged() {
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'changeTriggerSeverityColor',
|
||||||
|
value: function changeTriggerSeverityColor(trigger, color) {
|
||||||
|
this.panel.triggerSeverity[trigger.priority].color = color;
|
||||||
|
this.refreshTriggerSeverity();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'isRegex',
|
||||||
|
value: function isRegex(str) {
|
||||||
|
return utils.isRegex(str);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'isVariable',
|
||||||
|
value: function isVariable(str) {
|
||||||
|
return utils.isTemplateVariable(str, this.templateSrv.variables);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getZabbixDataSources',
|
||||||
|
value: function getZabbixDataSources() {
|
||||||
|
var ZABBIX_DS_ID = 'alexanderzobnin-zabbix-datasource';
|
||||||
|
return _.filter(this.datasourceSrv.getMetricSources(), function (datasource) {
|
||||||
|
return datasource.meta.id === ZABBIX_DS_ID && datasource.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return TriggerPanelEditorCtrl;
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=editor.js.map
|
||||||
1
dist/panel-triggers/editor.js.map
vendored
Normal file
124
dist/panel-triggers/module.html
vendored
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
<div class="triggers-panel-container">
|
||||||
|
<div class="triggers-panel-header-bg"></div>
|
||||||
|
<div class="triggers-panel-scroll">
|
||||||
|
<table class="triggers-panel-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th ng-if="ctrl.panel.hostField" style="width: 15%">
|
||||||
|
<div class="triggers-panel-table-header-inner pointer">
|
||||||
|
Host
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th ng-if="ctrl.panel.hostTechNameField" style="width: 15%">
|
||||||
|
<div class="triggers-panel-table-header-inner pointer">
|
||||||
|
Technical Name
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th ng-if="ctrl.panel.statusField" style="width: 85px">
|
||||||
|
<div class="triggers-panel-table-header-inner pointer">Status</div>
|
||||||
|
</th>
|
||||||
|
<th ng-if="ctrl.panel.severityField" style="width: 120px">
|
||||||
|
<div class="triggers-panel-table-header-inner pointer">Severity</div>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<div class="triggers-panel-table-header-inner pointer">Issue</div>
|
||||||
|
</th>
|
||||||
|
<th ng-if="ctrl.panel.lastChangeField" style="width: 220px">
|
||||||
|
<div class="triggers-panel-table-header-inner pointer">Last change</div>
|
||||||
|
</th>
|
||||||
|
<th ng-if="ctrl.panel.ageField" style="width: 180px">
|
||||||
|
<div class="triggers-panel-table-header-inner pointer">Age</div>
|
||||||
|
</th>
|
||||||
|
<th ng-if="ctrl.panel.infoField" style="width: 100px">
|
||||||
|
<div class="triggers-panel-table-header-inner pointer">Info</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="trigger in ctrl.triggerList">
|
||||||
|
|
||||||
|
<td ng-if="ctrl.panel.hostField">
|
||||||
|
<div>
|
||||||
|
<span><strong>{{trigger.host}}</strong></span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td ng-if="ctrl.panel.hostTechNameField">
|
||||||
|
<div>
|
||||||
|
<span><strong>{{trigger.hostTechName}}</strong></span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td ng-if="ctrl.panel.statusField" style="background-color: {{trigger.color}}; color: white">
|
||||||
|
<div>
|
||||||
|
{{ctrl.triggerStatusMap[trigger.value]}}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td ng-if="ctrl.panel.severityField" style="background-color: {{trigger.color}}; color: white">
|
||||||
|
<div>
|
||||||
|
{{trigger.severity}}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td style="background-color: {{trigger.color}}; color: white">
|
||||||
|
<div>
|
||||||
|
{{trigger.description}}
|
||||||
|
<a ng-if="trigger.comments"
|
||||||
|
role="button"
|
||||||
|
ng-click="ctrl.switchComment(trigger)"
|
||||||
|
class="pointer"
|
||||||
|
style="float: right; padding-right: 8px"
|
||||||
|
bs-tooltip="'Show additional trigger description'"
|
||||||
|
data-placement="top">
|
||||||
|
<i class="fa fa-file-text-o"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Trigger comments -->
|
||||||
|
<div class="collapse"
|
||||||
|
id="comments-{{trigger.triggerid}}"
|
||||||
|
ng-if="trigger.showComment">
|
||||||
|
<div>
|
||||||
|
<small>{{trigger.comments}}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td ng-if="ctrl.panel.lastChangeField">
|
||||||
|
{{trigger.lastchange}}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td ng-if="ctrl.panel.ageField">
|
||||||
|
{{trigger.age}}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td ng-if="ctrl.panel.infoField">
|
||||||
|
|
||||||
|
<!-- Trigger Url -->
|
||||||
|
<a ng-if="trigger.url"
|
||||||
|
href="{{trigger.url}}"
|
||||||
|
target="_blank">
|
||||||
|
<i class="fa fa-external-link"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Trigger state -->
|
||||||
|
<span ng-if="trigger.state === '1'"
|
||||||
|
bs-tooltip="'{{trigger.error}}'">
|
||||||
|
<i class="fa fa-question-circle"></i>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!-- Trigger acknowledges -->
|
||||||
|
<ack-tooltip
|
||||||
|
ack="trigger.acknowledges"
|
||||||
|
trigger="trigger"
|
||||||
|
on-ack="ctrl.acknowledgeTrigger"
|
||||||
|
context="ctrl">
|
||||||
|
</ack-tooltip>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="triggers-panel-footer"></div>
|
||||||
321
dist/panel-triggers/module.js
vendored
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register(['lodash', 'moment', '../datasource-zabbix/utils', 'app/plugins/sdk', './editor', './ack-tooltip.directive', './css/panel_triggers.css!'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _, moment, utils, MetricsPanelCtrl, triggerPanelEditor, _createClass, defaultSeverity, panelDefaults, triggerStatusMap, defaultTimeFormat, TriggerPanelCtrl;
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _possibleConstructorReturn(self, call) {
|
||||||
|
if (!self) {
|
||||||
|
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
||||||
|
}
|
||||||
|
|
||||||
|
return call && (typeof call === "object" || typeof call === "function") ? call : self;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _inherits(subClass, superClass) {
|
||||||
|
if (typeof superClass !== "function" && superClass !== null) {
|
||||||
|
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
||||||
|
constructor: {
|
||||||
|
value: subClass,
|
||||||
|
enumerable: false,
|
||||||
|
writable: true,
|
||||||
|
configurable: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterTriggers(triggers, triggerFilter) {
|
||||||
|
if (utils.isRegex(triggerFilter)) {
|
||||||
|
return _.filter(triggers, function (trigger) {
|
||||||
|
return utils.buildRegex(triggerFilter).test(trigger.description);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return _.filter(triggers, function (trigger) {
|
||||||
|
return trigger.description === triggerFilter;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setters: [function (_lodash) {
|
||||||
|
_ = _lodash.default;
|
||||||
|
}, function (_moment) {
|
||||||
|
moment = _moment.default;
|
||||||
|
}, function (_datasourceZabbixUtils) {
|
||||||
|
utils = _datasourceZabbixUtils;
|
||||||
|
}, function (_appPluginsSdk) {
|
||||||
|
MetricsPanelCtrl = _appPluginsSdk.MetricsPanelCtrl;
|
||||||
|
}, function (_editor) {
|
||||||
|
triggerPanelEditor = _editor.triggerPanelEditor;
|
||||||
|
}, function (_ackTooltipDirective) {}, function (_cssPanel_triggersCss) {}],
|
||||||
|
execute: function () {
|
||||||
|
_createClass = function () {
|
||||||
|
function defineProperties(target, props) {
|
||||||
|
for (var i = 0; i < props.length; i++) {
|
||||||
|
var descriptor = props[i];
|
||||||
|
descriptor.enumerable = descriptor.enumerable || false;
|
||||||
|
descriptor.configurable = true;
|
||||||
|
if ("value" in descriptor) descriptor.writable = true;
|
||||||
|
Object.defineProperty(target, descriptor.key, descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (Constructor, protoProps, staticProps) {
|
||||||
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
||||||
|
if (staticProps) defineProperties(Constructor, staticProps);
|
||||||
|
return Constructor;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
defaultSeverity = [{ priority: 0, severity: 'Not classified', color: '#B7DBAB', show: true }, { priority: 1, severity: 'Information', color: '#82B5D8', show: true }, { priority: 2, severity: 'Warning', color: '#E5AC0E', show: true }, { priority: 3, severity: 'Average', color: '#C15C17', show: true }, { priority: 4, severity: 'High', color: '#BF1B00', show: true }, { priority: 5, severity: 'Disaster', color: '#890F02', show: true }];
|
||||||
|
panelDefaults = {
|
||||||
|
datasource: null,
|
||||||
|
triggers: {
|
||||||
|
group: { filter: "" },
|
||||||
|
host: { filter: "" },
|
||||||
|
application: { filter: "" },
|
||||||
|
trigger: { filter: "" }
|
||||||
|
},
|
||||||
|
hostField: true,
|
||||||
|
statusField: false,
|
||||||
|
severityField: false,
|
||||||
|
lastChangeField: true,
|
||||||
|
ageField: true,
|
||||||
|
infoField: true,
|
||||||
|
limit: 10,
|
||||||
|
showTriggers: 'all triggers',
|
||||||
|
sortTriggersBy: { text: 'last change', value: 'lastchange' },
|
||||||
|
showEvents: { text: 'Problems', value: '1' },
|
||||||
|
triggerSeverity: defaultSeverity,
|
||||||
|
okEventColor: 'rgba(0, 245, 153, 0.45)',
|
||||||
|
ackEventColor: 'rgba(0, 0, 0, 0)'
|
||||||
|
};
|
||||||
|
triggerStatusMap = {
|
||||||
|
'0': 'OK',
|
||||||
|
'1': 'Problem'
|
||||||
|
};
|
||||||
|
defaultTimeFormat = "DD MMM YYYY HH:mm:ss";
|
||||||
|
|
||||||
|
_export('PanelCtrl', _export('TriggerPanelCtrl', TriggerPanelCtrl = function (_MetricsPanelCtrl) {
|
||||||
|
_inherits(TriggerPanelCtrl, _MetricsPanelCtrl);
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function TriggerPanelCtrl($scope, $injector, $element, datasourceSrv, templateSrv, contextSrv) {
|
||||||
|
_classCallCheck(this, TriggerPanelCtrl);
|
||||||
|
|
||||||
|
var _this = _possibleConstructorReturn(this, (TriggerPanelCtrl.__proto__ || Object.getPrototypeOf(TriggerPanelCtrl)).call(this, $scope, $injector));
|
||||||
|
|
||||||
|
_this.datasourceSrv = datasourceSrv;
|
||||||
|
_this.templateSrv = templateSrv;
|
||||||
|
_this.contextSrv = contextSrv;
|
||||||
|
_this.triggerStatusMap = triggerStatusMap;
|
||||||
|
_this.defaultTimeFormat = defaultTimeFormat;
|
||||||
|
|
||||||
|
// Load panel defaults
|
||||||
|
// _.cloneDeep() need for prevent changing shared defaultSeverity.
|
||||||
|
// Load object "by value" istead "by reference".
|
||||||
|
_.defaults(_this.panel, _.cloneDeep(panelDefaults));
|
||||||
|
|
||||||
|
_this.triggerList = [];
|
||||||
|
_this.refreshData();
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override onInitMetricsPanelEditMode() method from MetricsPanelCtrl.
|
||||||
|
* We don't need metric editor from Metrics Panel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
_createClass(TriggerPanelCtrl, [{
|
||||||
|
key: 'onInitMetricsPanelEditMode',
|
||||||
|
value: function onInitMetricsPanelEditMode() {
|
||||||
|
this.addEditorTab('Options', triggerPanelEditor, 2);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'refresh',
|
||||||
|
value: function refresh() {
|
||||||
|
this.onMetricsPanelRefresh();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'onMetricsPanelRefresh',
|
||||||
|
value: function onMetricsPanelRefresh() {
|
||||||
|
// ignore fetching data if another panel is in fullscreen
|
||||||
|
if (this.otherPanelInFullscreenMode()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refreshData();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'refreshData',
|
||||||
|
value: function refreshData() {
|
||||||
|
// clear loading/error state
|
||||||
|
delete this.error;
|
||||||
|
this.loading = true;
|
||||||
|
this.setTimeQueryStart();
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Load datasource
|
||||||
|
return this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
|
||||||
|
var zabbix = datasource.zabbix;
|
||||||
|
var showEvents = self.panel.showEvents.value;
|
||||||
|
var triggerFilter = self.panel.triggers;
|
||||||
|
|
||||||
|
// Replace template variables
|
||||||
|
var groupFilter = datasource.replaceTemplateVars(triggerFilter.group.filter);
|
||||||
|
var hostFilter = datasource.replaceTemplateVars(triggerFilter.host.filter);
|
||||||
|
var appFilter = datasource.replaceTemplateVars(triggerFilter.application.filter);
|
||||||
|
|
||||||
|
var getTriggers = zabbix.getTriggers(groupFilter, hostFilter, appFilter, showEvents);
|
||||||
|
return getTriggers.then(function (triggers) {
|
||||||
|
return _.map(triggers, function (trigger) {
|
||||||
|
var triggerObj = trigger;
|
||||||
|
|
||||||
|
// Format last change and age
|
||||||
|
trigger.lastchangeUnix = Number(trigger.lastchange);
|
||||||
|
var timestamp = moment.unix(trigger.lastchangeUnix);
|
||||||
|
if (self.panel.customLastChangeFormat) {
|
||||||
|
// User defined format
|
||||||
|
triggerObj.lastchange = timestamp.format(self.panel.lastChangeFormat);
|
||||||
|
} else {
|
||||||
|
triggerObj.lastchange = timestamp.format(self.defaultTimeFormat);
|
||||||
|
}
|
||||||
|
triggerObj.age = timestamp.fromNow(true);
|
||||||
|
|
||||||
|
// Set host that the trigger belongs
|
||||||
|
if (trigger.hosts.length) {
|
||||||
|
triggerObj.host = trigger.hosts[0].name;
|
||||||
|
triggerObj.hostTechName = trigger.hosts[0].host;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set color
|
||||||
|
if (trigger.value === '1') {
|
||||||
|
// Problem state
|
||||||
|
triggerObj.color = self.panel.triggerSeverity[trigger.priority].color;
|
||||||
|
} else {
|
||||||
|
// OK state
|
||||||
|
triggerObj.color = self.panel.okEventColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerObj.severity = self.panel.triggerSeverity[trigger.priority].severity;
|
||||||
|
return triggerObj;
|
||||||
|
});
|
||||||
|
}).then(function (triggerList) {
|
||||||
|
|
||||||
|
// Request acknowledges for trigger
|
||||||
|
var eventids = _.map(triggerList, function (trigger) {
|
||||||
|
return trigger.lastEvent.eventid;
|
||||||
|
});
|
||||||
|
|
||||||
|
return zabbix.getAcknowledges(eventids).then(function (events) {
|
||||||
|
|
||||||
|
// Map events to triggers
|
||||||
|
_.each(triggerList, function (trigger) {
|
||||||
|
var event = _.find(events, function (event) {
|
||||||
|
return event.eventid === trigger.lastEvent.eventid;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
trigger.acknowledges = _.map(event.acknowledges, function (ack) {
|
||||||
|
var timestamp = moment.unix(ack.clock);
|
||||||
|
if (self.panel.customLastChangeFormat) {
|
||||||
|
ack.time = timestamp.format(self.panel.lastChangeFormat);
|
||||||
|
} else {
|
||||||
|
ack.time = timestamp.format(self.defaultTimeFormat);
|
||||||
|
}
|
||||||
|
ack.user = ack.alias + ' (' + ack.name + ' ' + ack.surname + ')';
|
||||||
|
return ack;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mark acknowledged triggers with different color
|
||||||
|
if (self.panel.markAckEvents && trigger.acknowledges.length) {
|
||||||
|
trigger.color = self.panel.ackEventColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter triggers by description
|
||||||
|
var triggerFilter = self.panel.triggers.trigger.filter;
|
||||||
|
if (triggerFilter) {
|
||||||
|
triggerList = filterTriggers(triggerList, triggerFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter acknowledged triggers
|
||||||
|
if (self.panel.showTriggers === 'unacknowledged') {
|
||||||
|
triggerList = _.filter(triggerList, function (trigger) {
|
||||||
|
return !trigger.acknowledges;
|
||||||
|
});
|
||||||
|
} else if (self.panel.showTriggers === 'acknowledged') {
|
||||||
|
triggerList = _.filter(triggerList, 'acknowledges');
|
||||||
|
} else {
|
||||||
|
triggerList = triggerList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter triggers by severity
|
||||||
|
triggerList = _.filter(triggerList, function (trigger) {
|
||||||
|
return self.panel.triggerSeverity[trigger.priority].show;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort triggers
|
||||||
|
if (self.panel.sortTriggersBy.value === 'priority') {
|
||||||
|
triggerList = _.sortBy(triggerList, 'priority').reverse();
|
||||||
|
} else {
|
||||||
|
triggerList = _.sortBy(triggerList, 'lastchangeUnix').reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit triggers number
|
||||||
|
self.triggerList = triggerList.slice(0, self.panel.limit);
|
||||||
|
|
||||||
|
// Notify panel that request is finished
|
||||||
|
self.setTimeQueryEnd();
|
||||||
|
self.loading = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'switchComment',
|
||||||
|
value: function switchComment(trigger) {
|
||||||
|
trigger.showComment = !trigger.showComment;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'acknowledgeTrigger',
|
||||||
|
value: function acknowledgeTrigger(trigger, message) {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
var eventid = trigger.lastEvent.eventid;
|
||||||
|
var grafana_user = this.contextSrv.user.name;
|
||||||
|
var ack_message = grafana_user + ' (Grafana): ' + message;
|
||||||
|
return this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
|
||||||
|
var zabbixAPI = datasource.zabbix.zabbixAPI;
|
||||||
|
return zabbixAPI.acknowledgeEvent(eventid, ack_message).then(function () {
|
||||||
|
_this2.refresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return TriggerPanelCtrl;
|
||||||
|
}(MetricsPanelCtrl)));
|
||||||
|
|
||||||
|
TriggerPanelCtrl.templateUrl = 'panel-triggers/module.html';
|
||||||
|
_export('TriggerPanelCtrl', TriggerPanelCtrl);
|
||||||
|
|
||||||
|
_export('PanelCtrl', TriggerPanelCtrl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=module.js.map
|
||||||
1
dist/panel-triggers/module.js.map
vendored
Normal file
12
dist/panel-triggers/plugin.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"type": "panel",
|
||||||
|
"name": "Zabbix Triggers",
|
||||||
|
"id": "alexanderzobnin-zabbix-triggers-panel",
|
||||||
|
|
||||||
|
"info": {
|
||||||
|
"author": {
|
||||||
|
"name": "Alexander Zobnin",
|
||||||
|
"url": "https://github.com/alexanderzobnin/grafana-zabbix"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
65
dist/plugin.json
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"type": "app",
|
||||||
|
"name": "Zabbix",
|
||||||
|
"id": "alexanderzobnin-zabbix-app",
|
||||||
|
|
||||||
|
"css": {
|
||||||
|
"dark": "css/dark.css",
|
||||||
|
"light": "css/light.css"
|
||||||
|
},
|
||||||
|
|
||||||
|
"info": {
|
||||||
|
"description": "Zabbix plugin for Grafana",
|
||||||
|
"author": {
|
||||||
|
"name": "Alexander Zobnin",
|
||||||
|
"url": "https://github.com/alexanderzobnin"
|
||||||
|
},
|
||||||
|
"keywords": ["zabbix"],
|
||||||
|
"logos": {
|
||||||
|
"small": "img/zabbix_app_logo.svg",
|
||||||
|
"large": "img/zabbix_app_logo.svg"
|
||||||
|
},
|
||||||
|
"links": [
|
||||||
|
{"name": "GitHub", "url": "https://github.com/alexanderzobnin/grafana-zabbix"},
|
||||||
|
{"name": "Docs", "url": "http://docs.grafana-zabbix.org"},
|
||||||
|
{"name": "License", "url": "https://github.com/alexanderzobnin/grafana-zabbix/blob/master/LICENSE.md"}
|
||||||
|
],
|
||||||
|
"screenshots": [
|
||||||
|
{"name": "Showcase", "path": "img/screenshot-showcase.png"},
|
||||||
|
{"name": "Dashboard", "path": "img/screenshot-dashboard01.png"},
|
||||||
|
{"name": "Annotations", "path": "img/screenshot-annotations.png"},
|
||||||
|
{"name": "Metric Editor", "path": "img/screenshot-metric_editor.png"},
|
||||||
|
{"name": "Triggers", "path": "img/screenshot-triggers.png"}
|
||||||
|
],
|
||||||
|
"version": "3.2.0",
|
||||||
|
"updated": "2016-12-20"
|
||||||
|
},
|
||||||
|
|
||||||
|
"includes": [
|
||||||
|
{
|
||||||
|
"type": "datasource",
|
||||||
|
"name": "Zabbix Datasource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "panel",
|
||||||
|
"name": "Triggers Panel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "dashboard",
|
||||||
|
"name": "Zabbix Server Dashboard",
|
||||||
|
"path": "dashboards/zabbix_server_dashboard.json",
|
||||||
|
"addToNav": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "dashboard",
|
||||||
|
"name": "Template Linux Server",
|
||||||
|
"path": "dashboards/template_linux_server.json",
|
||||||
|
"addToNav": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"dependencies": {
|
||||||
|
"grafanaVersion": "3.x.x",
|
||||||
|
"plugins": []
|
||||||
|
}
|
||||||
|
}
|
||||||
13
dist/test/components/config.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
var ZabbixAppConfigCtrl = exports.ZabbixAppConfigCtrl = function ZabbixAppConfigCtrl() {
|
||||||
|
_classCallCheck(this, ZabbixAppConfigCtrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
ZabbixAppConfigCtrl.templateUrl = 'components/config.html';
|
||||||
116
dist/test/datasource-zabbix/add-metric-function.directive.js
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _angular = require('angular');
|
||||||
|
|
||||||
|
var _angular2 = _interopRequireDefault(_angular);
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _jquery = require('jquery');
|
||||||
|
|
||||||
|
var _jquery2 = _interopRequireDefault(_jquery);
|
||||||
|
|
||||||
|
var _metricFunctions = require('./metricFunctions');
|
||||||
|
|
||||||
|
var metricFunctions = _interopRequireWildcard(_metricFunctions);
|
||||||
|
|
||||||
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
_angular2.default.module('grafana.directives').directive('addMetricFunction', function ($compile) {
|
||||||
|
var inputTemplate = '<input type="text"' + ' class="gf-form-input"' + ' spellcheck="false" style="display:none"></input>';
|
||||||
|
|
||||||
|
var buttonTemplate = '<a class="gf-form-label tight-form-func dropdown-toggle query-part"' + ' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown">' + '<i class="fa fa-plus"></i></a>';
|
||||||
|
|
||||||
|
return {
|
||||||
|
link: function link($scope, elem) {
|
||||||
|
var categories = metricFunctions.getCategories();
|
||||||
|
var allFunctions = getAllFunctionNames(categories);
|
||||||
|
|
||||||
|
$scope.functionMenu = createFunctionDropDownMenu(categories);
|
||||||
|
|
||||||
|
var $input = (0, _jquery2.default)(inputTemplate);
|
||||||
|
var $button = (0, _jquery2.default)(buttonTemplate);
|
||||||
|
$input.appendTo(elem);
|
||||||
|
$button.appendTo(elem);
|
||||||
|
|
||||||
|
$input.attr('data-provide', 'typeahead');
|
||||||
|
$input.typeahead({
|
||||||
|
source: allFunctions,
|
||||||
|
minLength: 1,
|
||||||
|
items: 10,
|
||||||
|
updater: function updater(value) {
|
||||||
|
var funcDef = metricFunctions.getFuncDef(value);
|
||||||
|
if (!funcDef) {
|
||||||
|
// try find close match
|
||||||
|
value = value.toLowerCase();
|
||||||
|
funcDef = _lodash2.default.find(allFunctions, function (funcName) {
|
||||||
|
return funcName.toLowerCase().indexOf(value) === 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!funcDef) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.$apply(function () {
|
||||||
|
$scope.addFunction(funcDef);
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.trigger('blur');
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$button.click(function () {
|
||||||
|
$button.hide();
|
||||||
|
$input.show();
|
||||||
|
$input.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.keyup(function () {
|
||||||
|
elem.toggleClass('open', $input.val() === '');
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.blur(function () {
|
||||||
|
// clicking the function dropdown menu wont
|
||||||
|
// work if you remove class at once
|
||||||
|
setTimeout(function () {
|
||||||
|
$input.val('');
|
||||||
|
$input.hide();
|
||||||
|
$button.show();
|
||||||
|
elem.removeClass('open');
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
$compile(elem.contents())($scope);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function getAllFunctionNames(categories) {
|
||||||
|
return _lodash2.default.reduce(categories, function (list, category) {
|
||||||
|
_lodash2.default.each(category, function (func) {
|
||||||
|
list.push(func.name);
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFunctionDropDownMenu(categories) {
|
||||||
|
return _lodash2.default.map(categories, function (list, category) {
|
||||||
|
return {
|
||||||
|
text: category,
|
||||||
|
submenu: _lodash2.default.map(list, function (value) {
|
||||||
|
return {
|
||||||
|
text: value.name,
|
||||||
|
click: "ctrl.addFunction('" + value.name + "')"
|
||||||
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
330
dist/test/datasource-zabbix/dataProcessor.js
vendored
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _utils = require('./utils');
|
||||||
|
|
||||||
|
var utils = _interopRequireWildcard(_utils);
|
||||||
|
|
||||||
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downsample datapoints series
|
||||||
|
*/
|
||||||
|
function downsampleSeries(datapoints, time_to, ms_interval, func) {
|
||||||
|
var downsampledSeries = [];
|
||||||
|
var timeWindow = {
|
||||||
|
from: time_to * 1000 - ms_interval,
|
||||||
|
to: time_to * 1000
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (func === "max") {
|
||||||
|
downsampledSeries.push([_lodash2.default.max(frame), timeWindow.to]);
|
||||||
|
} else if (func === "min") {
|
||||||
|
downsampledSeries.push([_lodash2.default.min(frame), timeWindow.to]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// avg by default
|
||||||
|
else {
|
||||||
|
downsampledSeries.push([value_avg, timeWindow.to]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift time window
|
||||||
|
timeWindow.to = timeWindow.from;
|
||||||
|
timeWindow.from -= ms_interval;
|
||||||
|
|
||||||
|
points_sum = 0;
|
||||||
|
points_num = 0;
|
||||||
|
frame = [];
|
||||||
|
|
||||||
|
// Process point again
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return downsampledSeries.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Group points by given time interval
|
||||||
|
* datapoints: [[<value>, <unixtime>], ...]
|
||||||
|
*/
|
||||||
|
function groupBy(interval, groupByCallback, datapoints) {
|
||||||
|
var ms_interval = utils.parseInterval(interval);
|
||||||
|
|
||||||
|
// Calculate frame timestamps
|
||||||
|
var frames = _lodash2.default.groupBy(datapoints, function (point) {
|
||||||
|
// Calculate time for group of points
|
||||||
|
return Math.floor(point[1] / ms_interval) * ms_interval;
|
||||||
|
});
|
||||||
|
|
||||||
|
// frame: { '<unixtime>': [[<value>, <unixtime>], ...] }
|
||||||
|
// return [{ '<unixtime>': <value> }, { '<unixtime>': <value> }, ...]
|
||||||
|
var grouped = _lodash2.default.mapValues(frames, function (frame) {
|
||||||
|
var points = _lodash2.default.map(frame, function (point) {
|
||||||
|
return point[0];
|
||||||
|
});
|
||||||
|
return groupByCallback(points);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert points to Grafana format
|
||||||
|
return sortByTime(_lodash2.default.map(grouped, function (value, timestamp) {
|
||||||
|
return [Number(value), Number(timestamp)];
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function sumSeries(timeseries) {
|
||||||
|
|
||||||
|
// Calculate new points for interpolation
|
||||||
|
var new_timestamps = _lodash2.default.uniq(_lodash2.default.map(_lodash2.default.flatten(timeseries, true), function (point) {
|
||||||
|
return point[1];
|
||||||
|
}));
|
||||||
|
new_timestamps = _lodash2.default.sortBy(new_timestamps);
|
||||||
|
|
||||||
|
var interpolated_timeseries = _lodash2.default.map(timeseries, function (series) {
|
||||||
|
var timestamps = _lodash2.default.map(series, function (point) {
|
||||||
|
return point[1];
|
||||||
|
});
|
||||||
|
var new_points = _lodash2.default.map(_lodash2.default.difference(new_timestamps, timestamps), function (timestamp) {
|
||||||
|
return [null, timestamp];
|
||||||
|
});
|
||||||
|
var new_series = series.concat(new_points);
|
||||||
|
return sortByTime(new_series);
|
||||||
|
});
|
||||||
|
|
||||||
|
_lodash2.default.each(interpolated_timeseries, interpolateSeries);
|
||||||
|
|
||||||
|
var new_timeseries = [];
|
||||||
|
var sum;
|
||||||
|
for (var i = new_timestamps.length - 1; i >= 0; i--) {
|
||||||
|
sum = 0;
|
||||||
|
for (var j = interpolated_timeseries.length - 1; j >= 0; j--) {
|
||||||
|
sum += interpolated_timeseries[j][i][0];
|
||||||
|
}
|
||||||
|
new_timeseries.push([sum, new_timestamps[i]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortByTime(new_timeseries);
|
||||||
|
}
|
||||||
|
|
||||||
|
function limit(order, n, orderByFunc, timeseries) {
|
||||||
|
var orderByCallback = aggregationFunctions[orderByFunc];
|
||||||
|
var sortByIteratee = function sortByIteratee(ts) {
|
||||||
|
var values = _lodash2.default.map(ts.datapoints, function (point) {
|
||||||
|
return point[0];
|
||||||
|
});
|
||||||
|
return orderByCallback(values);
|
||||||
|
};
|
||||||
|
var sortedTimeseries = _lodash2.default.sortBy(timeseries, sortByIteratee);
|
||||||
|
if (order === 'bottom') {
|
||||||
|
return sortedTimeseries.slice(0, n);
|
||||||
|
} else {
|
||||||
|
return sortedTimeseries.slice(-n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function AVERAGE(values) {
|
||||||
|
var sum = 0;
|
||||||
|
_lodash2.default.each(values, function (value) {
|
||||||
|
sum += value;
|
||||||
|
});
|
||||||
|
return sum / values.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function MIN(values) {
|
||||||
|
return _lodash2.default.min(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MAX(values) {
|
||||||
|
return _lodash2.default.max(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MEDIAN(values) {
|
||||||
|
var sorted = _lodash2.default.sortBy(values);
|
||||||
|
return sorted[Math.floor(sorted.length / 2)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAlias(alias, timeseries) {
|
||||||
|
timeseries.target = alias;
|
||||||
|
return timeseries;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAliasByRegex(alias, timeseries) {
|
||||||
|
timeseries.target = extractText(timeseries.target, alias);
|
||||||
|
return timeseries;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractText(str, pattern) {
|
||||||
|
var extractPattern = new RegExp(pattern);
|
||||||
|
var extractedValue = extractPattern.exec(str);
|
||||||
|
extractedValue = extractedValue[0];
|
||||||
|
return extractedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
function scale(factor, datapoints) {
|
||||||
|
return _lodash2.default.map(datapoints, function (point) {
|
||||||
|
return [point[0] * factor, point[1]];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function delta(datapoints) {
|
||||||
|
var newSeries = [];
|
||||||
|
var deltaValue = void 0;
|
||||||
|
for (var i = 1; i < datapoints.length; i++) {
|
||||||
|
deltaValue = datapoints[i][0] - datapoints[i - 1][0];
|
||||||
|
newSeries.push([deltaValue, datapoints[i][1]]);
|
||||||
|
}
|
||||||
|
return newSeries;
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupByWrapper(interval, groupFunc, datapoints) {
|
||||||
|
var groupByCallback = aggregationFunctions[groupFunc];
|
||||||
|
return groupBy(interval, groupByCallback, datapoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
function aggregateByWrapper(interval, aggregateFunc, datapoints) {
|
||||||
|
// Flatten all points in frame and then just use groupBy()
|
||||||
|
var flattenedPoints = _lodash2.default.flatten(datapoints, true);
|
||||||
|
var groupByCallback = aggregationFunctions[aggregateFunc];
|
||||||
|
return groupBy(interval, groupByCallback, flattenedPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
function aggregateWrapper(groupByCallback, interval, datapoints) {
|
||||||
|
var flattenedPoints = _lodash2.default.flatten(datapoints, true);
|
||||||
|
return groupBy(interval, groupByCallback, flattenedPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortByTime(series) {
|
||||||
|
return _lodash2.default.sortBy(series, function (point) {
|
||||||
|
return point[1];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interpolate series with gaps
|
||||||
|
*/
|
||||||
|
function interpolateSeries(series) {
|
||||||
|
var left, right;
|
||||||
|
|
||||||
|
// Interpolate series
|
||||||
|
for (var i = series.length - 1; i >= 0; i--) {
|
||||||
|
if (!series[i][0]) {
|
||||||
|
left = findNearestLeft(series, series[i]);
|
||||||
|
right = findNearestRight(series, series[i]);
|
||||||
|
if (!left) {
|
||||||
|
left = right;
|
||||||
|
}
|
||||||
|
if (!right) {
|
||||||
|
right = left;
|
||||||
|
}
|
||||||
|
series[i][0] = linearInterpolation(series[i][1], left, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
|
function linearInterpolation(timestamp, left, right) {
|
||||||
|
if (left[1] === right[1]) {
|
||||||
|
return (left[0] + right[0]) / 2;
|
||||||
|
} else {
|
||||||
|
return left[0] + (right[0] - left[0]) / (right[1] - left[1]) * (timestamp - left[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findNearestRight(series, point) {
|
||||||
|
var point_index = _lodash2.default.indexOf(series, point);
|
||||||
|
var nearestRight;
|
||||||
|
for (var i = point_index; i < series.length; i++) {
|
||||||
|
if (series[i][0] !== null) {
|
||||||
|
return series[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nearestRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findNearestLeft(series, point) {
|
||||||
|
var point_index = _lodash2.default.indexOf(series, point);
|
||||||
|
var nearestLeft;
|
||||||
|
for (var i = point_index; i > 0; i--) {
|
||||||
|
if (series[i][0] !== null) {
|
||||||
|
return series[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nearestLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
function timeShift(interval, range) {
|
||||||
|
var shift = utils.parseTimeShiftInterval(interval) / 1000;
|
||||||
|
return range.map(function (time) {
|
||||||
|
return time - shift;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function unShiftTimeSeries(interval, datapoints) {
|
||||||
|
var unshift = utils.parseTimeShiftInterval(interval);
|
||||||
|
return datapoints.map(function (dp) {
|
||||||
|
return [dp[0], dp[1] + unshift];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var metricFunctions = {
|
||||||
|
groupBy: groupByWrapper,
|
||||||
|
scale: scale,
|
||||||
|
delta: delta,
|
||||||
|
aggregateBy: aggregateByWrapper,
|
||||||
|
average: _lodash2.default.partial(aggregateWrapper, AVERAGE),
|
||||||
|
min: _lodash2.default.partial(aggregateWrapper, MIN),
|
||||||
|
max: _lodash2.default.partial(aggregateWrapper, MAX),
|
||||||
|
median: _lodash2.default.partial(aggregateWrapper, MEDIAN),
|
||||||
|
sumSeries: sumSeries,
|
||||||
|
top: _lodash2.default.partial(limit, 'top'),
|
||||||
|
bottom: _lodash2.default.partial(limit, 'bottom'),
|
||||||
|
timeShift: timeShift,
|
||||||
|
setAlias: setAlias,
|
||||||
|
setAliasByRegex: setAliasByRegex
|
||||||
|
};
|
||||||
|
|
||||||
|
var aggregationFunctions = {
|
||||||
|
avg: AVERAGE,
|
||||||
|
min: MIN,
|
||||||
|
max: MAX,
|
||||||
|
median: MEDIAN
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.default = {
|
||||||
|
downsampleSeries: downsampleSeries,
|
||||||
|
groupBy: groupBy,
|
||||||
|
AVERAGE: AVERAGE,
|
||||||
|
MIN: MIN,
|
||||||
|
MAX: MAX,
|
||||||
|
MEDIAN: MEDIAN,
|
||||||
|
unShiftTimeSeries: unShiftTimeSeries,
|
||||||
|
|
||||||
|
get aggregationFunctions() {
|
||||||
|
return aggregationFunctions;
|
||||||
|
},
|
||||||
|
|
||||||
|
get metricFunctions() {
|
||||||
|
return metricFunctions;
|
||||||
|
}
|
||||||
|
};
|
||||||
582
dist/test/datasource-zabbix/datasource.js
vendored
Normal file
@@ -0,0 +1,582 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.zabbixTemplateFormat = exports.ZabbixAPIDatasource = undefined;
|
||||||
|
|
||||||
|
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
|
||||||
|
|
||||||
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); //import angular from 'angular';
|
||||||
|
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _datemath = require('app/core/utils/datemath');
|
||||||
|
|
||||||
|
var dateMath = _interopRequireWildcard(_datemath);
|
||||||
|
|
||||||
|
var _utils = require('./utils');
|
||||||
|
|
||||||
|
var utils = _interopRequireWildcard(_utils);
|
||||||
|
|
||||||
|
var _migrations = require('./migrations');
|
||||||
|
|
||||||
|
var migrations = _interopRequireWildcard(_migrations);
|
||||||
|
|
||||||
|
var _metricFunctions = require('./metricFunctions');
|
||||||
|
|
||||||
|
var metricFunctions = _interopRequireWildcard(_metricFunctions);
|
||||||
|
|
||||||
|
var _dataProcessor = require('./dataProcessor');
|
||||||
|
|
||||||
|
var _dataProcessor2 = _interopRequireDefault(_dataProcessor);
|
||||||
|
|
||||||
|
var _responseHandler = require('./responseHandler');
|
||||||
|
|
||||||
|
var _responseHandler2 = _interopRequireDefault(_responseHandler);
|
||||||
|
|
||||||
|
require('./zabbix.js');
|
||||||
|
|
||||||
|
var _zabbixAPICoreService = require('./zabbixAPICore.service.js');
|
||||||
|
|
||||||
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
var ZabbixAPIDatasource = function () {
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function ZabbixAPIDatasource(instanceSettings, templateSrv, alertSrv, Zabbix) {
|
||||||
|
_classCallCheck(this, ZabbixAPIDatasource);
|
||||||
|
|
||||||
|
this.templateSrv = templateSrv;
|
||||||
|
this.alertSrv = alertSrv;
|
||||||
|
|
||||||
|
// General data source settings
|
||||||
|
this.name = instanceSettings.name;
|
||||||
|
this.url = instanceSettings.url;
|
||||||
|
this.basicAuth = instanceSettings.basicAuth;
|
||||||
|
this.withCredentials = instanceSettings.withCredentials;
|
||||||
|
|
||||||
|
// Zabbix API credentials
|
||||||
|
this.username = instanceSettings.jsonData.username;
|
||||||
|
this.password = instanceSettings.jsonData.password;
|
||||||
|
|
||||||
|
// Use trends instead history since specified time
|
||||||
|
this.trends = instanceSettings.jsonData.trends;
|
||||||
|
this.trendsFrom = instanceSettings.jsonData.trendsFrom || '7d';
|
||||||
|
|
||||||
|
// Set cache update interval
|
||||||
|
var ttl = instanceSettings.jsonData.cacheTTL || '1h';
|
||||||
|
this.cacheTTL = utils.parseInterval(ttl);
|
||||||
|
|
||||||
|
this.zabbix = new Zabbix(this.url, this.username, this.password, this.basicAuth, this.withCredentials, this.cacheTTL);
|
||||||
|
|
||||||
|
// Use custom format for template variables
|
||||||
|
this.replaceTemplateVars = _lodash2.default.partial(replaceTemplateVars, this.templateSrv);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////
|
||||||
|
// Datasource methods //
|
||||||
|
////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query panel data. Calls for each panel in dashboard.
|
||||||
|
* @param {Object} options Contains time range, targets and other info.
|
||||||
|
* @return {Object} Grafana metrics object with timeseries data for each target.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
_createClass(ZabbixAPIDatasource, [{
|
||||||
|
key: 'query',
|
||||||
|
value: function query(options) {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
var timeFrom = Math.ceil(dateMath.parse(options.range.from) / 1000);
|
||||||
|
var timeTo = Math.ceil(dateMath.parse(options.range.to) / 1000);
|
||||||
|
|
||||||
|
var useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000);
|
||||||
|
var useTrends = timeFrom <= useTrendsFrom && this.trends;
|
||||||
|
|
||||||
|
// Create request for each target
|
||||||
|
var promises = _lodash2.default.map(options.targets, function (target) {
|
||||||
|
// Prevent changes of original object
|
||||||
|
target = _lodash2.default.cloneDeep(target);
|
||||||
|
_this.replaceTargetVariables(target, options);
|
||||||
|
|
||||||
|
// Apply Time-related functions (timeShift(), etc)
|
||||||
|
var timeFunctions = bindFunctionDefs(target.functions, 'Time');
|
||||||
|
if (timeFunctions.length) {
|
||||||
|
var _sequence = sequence(timeFunctions)([timeFrom, timeTo]),
|
||||||
|
_sequence2 = _slicedToArray(_sequence, 2),
|
||||||
|
time_from = _sequence2[0],
|
||||||
|
time_to = _sequence2[1];
|
||||||
|
|
||||||
|
timeFrom = time_from;
|
||||||
|
timeTo = time_to;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metrics or Text query mode
|
||||||
|
if (target.mode !== 1) {
|
||||||
|
// Migrate old targets
|
||||||
|
target = migrations.migrate(target);
|
||||||
|
|
||||||
|
// Don't request undefined and hidden targets
|
||||||
|
if (target.hide || !target.group || !target.host || !target.item) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target.mode || target.mode === 0) {
|
||||||
|
return _this.queryNumericData(target, timeFrom, timeTo, useTrends);
|
||||||
|
} else if (target.mode === 2) {
|
||||||
|
return _this.queryTextData(target, timeFrom, timeTo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IT services mode
|
||||||
|
else if (target.mode === 1) {
|
||||||
|
// Don't show undefined and hidden targets
|
||||||
|
if (target.hide || !target.itservice || !target.slaProperty) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return _this.zabbix.getSLA(target.itservice.serviceid, timeFrom, timeTo).then(function (slaObject) {
|
||||||
|
return _responseHandler2.default.handleSLAResponse(target.itservice, target.slaProperty, slaObject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Data for panel (all targets)
|
||||||
|
return Promise.all(_lodash2.default.flatten(promises)).then(_lodash2.default.flatten).then(function (timeseries_data) {
|
||||||
|
return downsampleSeries(timeseries_data, options);
|
||||||
|
}).then(function (data) {
|
||||||
|
return { data: data };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'queryNumericData',
|
||||||
|
value: function queryNumericData(target, timeFrom, timeTo, useTrends) {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
itemtype: 'num'
|
||||||
|
};
|
||||||
|
return this.zabbix.getItemsFromTarget(target, options).then(function (items) {
|
||||||
|
var getHistoryPromise = void 0;
|
||||||
|
|
||||||
|
if (useTrends) {
|
||||||
|
(function () {
|
||||||
|
var valueType = _this2.getTrendValueType(target);
|
||||||
|
getHistoryPromise = _this2.zabbix.getTrend(items, timeFrom, timeTo).then(function (history) {
|
||||||
|
return _responseHandler2.default.handleTrends(history, items, valueType);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
} else {
|
||||||
|
// Use history
|
||||||
|
getHistoryPromise = _this2.zabbix.getHistory(items, timeFrom, timeTo).then(function (history) {
|
||||||
|
return _responseHandler2.default.handleHistory(history, items);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return getHistoryPromise.then(function (timeseries_data) {
|
||||||
|
return _this2.applyDataProcessingFunctions(timeseries_data, target);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getTrendValueType',
|
||||||
|
value: function getTrendValueType(target) {
|
||||||
|
// Find trendValue() function and get specified trend value
|
||||||
|
var trendFunctions = _lodash2.default.map(metricFunctions.getCategories()['Trends'], 'name');
|
||||||
|
var trendValueFunc = _lodash2.default.find(target.functions, function (func) {
|
||||||
|
return _lodash2.default.includes(trendFunctions, func.def.name);
|
||||||
|
});
|
||||||
|
return trendValueFunc ? trendValueFunc.params[0] : "avg";
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'applyDataProcessingFunctions',
|
||||||
|
value: function applyDataProcessingFunctions(timeseries_data, target) {
|
||||||
|
var transformFunctions = bindFunctionDefs(target.functions, 'Transform');
|
||||||
|
var aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate');
|
||||||
|
var filterFunctions = bindFunctionDefs(target.functions, 'Filter');
|
||||||
|
var aliasFunctions = bindFunctionDefs(target.functions, 'Alias');
|
||||||
|
|
||||||
|
// Apply transformation functions
|
||||||
|
timeseries_data = _lodash2.default.map(timeseries_data, function (timeseries) {
|
||||||
|
timeseries.datapoints = sequence(transformFunctions)(timeseries.datapoints);
|
||||||
|
return timeseries;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Apply filter functions
|
||||||
|
if (filterFunctions.length) {
|
||||||
|
timeseries_data = sequence(filterFunctions)(timeseries_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply aggregations
|
||||||
|
if (aggregationFunctions.length) {
|
||||||
|
(function () {
|
||||||
|
var dp = _lodash2.default.map(timeseries_data, 'datapoints');
|
||||||
|
dp = sequence(aggregationFunctions)(dp);
|
||||||
|
|
||||||
|
var aggFuncNames = _lodash2.default.map(metricFunctions.getCategories()['Aggregate'], 'name');
|
||||||
|
var lastAgg = _lodash2.default.findLast(target.functions, function (func) {
|
||||||
|
return _lodash2.default.includes(aggFuncNames, func.def.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
timeseries_data = [{
|
||||||
|
target: lastAgg.text,
|
||||||
|
datapoints: dp
|
||||||
|
}];
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply alias functions
|
||||||
|
_lodash2.default.forEach(timeseries_data, sequence(aliasFunctions));
|
||||||
|
|
||||||
|
// Apply Time-related functions (timeShift(), etc)
|
||||||
|
// Find timeShift() function and get specified trend value
|
||||||
|
this.applyTimeShiftFunction(timeseries_data, target);
|
||||||
|
|
||||||
|
return timeseries_data;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'applyTimeShiftFunction',
|
||||||
|
value: function applyTimeShiftFunction(timeseries_data, target) {
|
||||||
|
// Find timeShift() function and get specified interval
|
||||||
|
var timeShiftFunc = _lodash2.default.find(target.functions, function (func) {
|
||||||
|
return func.def.name === 'timeShift';
|
||||||
|
});
|
||||||
|
if (timeShiftFunc) {
|
||||||
|
(function () {
|
||||||
|
var shift = timeShiftFunc.params[0];
|
||||||
|
_lodash2.default.forEach(timeseries_data, function (series) {
|
||||||
|
series.datapoints = _dataProcessor2.default.unShiftTimeSeries(shift, series.datapoints);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'queryTextData',
|
||||||
|
value: function queryTextData(target, timeFrom, timeTo) {
|
||||||
|
var _this3 = this;
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
itemtype: 'text'
|
||||||
|
};
|
||||||
|
return this.zabbix.getItemsFromTarget(target, options).then(function (items) {
|
||||||
|
if (items.length) {
|
||||||
|
return _this3.zabbix.getHistory(items, timeFrom, timeTo).then(function (history) {
|
||||||
|
return _responseHandler2.default.convertHistory(history, items, false, function (point) {
|
||||||
|
var value = point.value;
|
||||||
|
|
||||||
|
// Regex-based extractor
|
||||||
|
if (target.textFilter) {
|
||||||
|
value = extractText(point.value, target.textFilter, target.useCaptureGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [value, point.clock * 1000];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test connection to Zabbix API
|
||||||
|
* @return {object} Connection status and Zabbix API version
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'testDatasource',
|
||||||
|
value: function testDatasource() {
|
||||||
|
var _this4 = this;
|
||||||
|
|
||||||
|
var zabbixVersion = void 0;
|
||||||
|
return this.zabbix.getVersion().then(function (version) {
|
||||||
|
zabbixVersion = version;
|
||||||
|
return _this4.zabbix.login();
|
||||||
|
}).then(function () {
|
||||||
|
return {
|
||||||
|
status: "success",
|
||||||
|
title: "Success",
|
||||||
|
message: "Zabbix API version: " + zabbixVersion
|
||||||
|
};
|
||||||
|
}).catch(function (error) {
|
||||||
|
if (error instanceof _zabbixAPICoreService.ZabbixAPIError) {
|
||||||
|
return {
|
||||||
|
status: "error",
|
||||||
|
title: error.message,
|
||||||
|
message: error.data
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
status: "error",
|
||||||
|
title: "Connection failed",
|
||||||
|
message: "Could not connect to given url"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// Templating //
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find metrics from templated request.
|
||||||
|
*
|
||||||
|
* @param {string} query Query from Templating
|
||||||
|
* @return {string} Metric name - group, host, app or item or list
|
||||||
|
* of metrics in "{metric1,metcic2,...,metricN}" format.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'metricFindQuery',
|
||||||
|
value: function metricFindQuery(query) {
|
||||||
|
var _this5 = this;
|
||||||
|
|
||||||
|
var result = void 0;
|
||||||
|
var parts = [];
|
||||||
|
|
||||||
|
// Split query. Query structure: group.host.app.item
|
||||||
|
_lodash2.default.each(query.split('.'), function (part) {
|
||||||
|
part = _this5.replaceTemplateVars(part, {});
|
||||||
|
|
||||||
|
// Replace wildcard to regex
|
||||||
|
if (part === '*') {
|
||||||
|
part = '/.*/';
|
||||||
|
}
|
||||||
|
parts.push(part);
|
||||||
|
});
|
||||||
|
var template = _lodash2.default.zipObject(['group', 'host', 'app', 'item'], parts);
|
||||||
|
|
||||||
|
// Get items
|
||||||
|
if (parts.length === 4) {
|
||||||
|
// Search for all items, even it's not belong to any application
|
||||||
|
if (template.app === '/.*/') {
|
||||||
|
template.app = '';
|
||||||
|
}
|
||||||
|
result = this.zabbix.getItems(template.group, template.host, template.app, template.item);
|
||||||
|
} else if (parts.length === 3) {
|
||||||
|
// Get applications
|
||||||
|
result = this.zabbix.getApps(template.group, template.host, template.app);
|
||||||
|
} else if (parts.length === 2) {
|
||||||
|
// Get hosts
|
||||||
|
result = this.zabbix.getHosts(template.group, template.host);
|
||||||
|
} else if (parts.length === 1) {
|
||||||
|
// Get groups
|
||||||
|
result = this.zabbix.getGroups(template.group);
|
||||||
|
} else {
|
||||||
|
result = Promise.resolve([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.then(function (metrics) {
|
||||||
|
return metrics.map(formatMetric);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
// Annotations //
|
||||||
|
/////////////////
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'annotationQuery',
|
||||||
|
value: function annotationQuery(options) {
|
||||||
|
var _this6 = this;
|
||||||
|
|
||||||
|
var timeFrom = Math.ceil(dateMath.parse(options.rangeRaw.from) / 1000);
|
||||||
|
var timeTo = Math.ceil(dateMath.parse(options.rangeRaw.to) / 1000);
|
||||||
|
var annotation = options.annotation;
|
||||||
|
var showOkEvents = annotation.showOkEvents ? [0, 1] : 1;
|
||||||
|
|
||||||
|
// Show all triggers
|
||||||
|
var showTriggers = [0, 1];
|
||||||
|
|
||||||
|
var getTriggers = this.zabbix.getTriggers(this.replaceTemplateVars(annotation.group, {}), this.replaceTemplateVars(annotation.host, {}), this.replaceTemplateVars(annotation.application, {}), showTriggers);
|
||||||
|
|
||||||
|
return getTriggers.then(function (triggers) {
|
||||||
|
|
||||||
|
// Filter triggers by description
|
||||||
|
if (utils.isRegex(annotation.trigger)) {
|
||||||
|
triggers = _lodash2.default.filter(triggers, function (trigger) {
|
||||||
|
return utils.buildRegex(annotation.trigger).test(trigger.description);
|
||||||
|
});
|
||||||
|
} else if (annotation.trigger) {
|
||||||
|
triggers = _lodash2.default.filter(triggers, function (trigger) {
|
||||||
|
return trigger.description === annotation.trigger;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove events below the chose severity
|
||||||
|
triggers = _lodash2.default.filter(triggers, function (trigger) {
|
||||||
|
return Number(trigger.priority) >= Number(annotation.minseverity);
|
||||||
|
});
|
||||||
|
|
||||||
|
var objectids = _lodash2.default.map(triggers, 'triggerid');
|
||||||
|
return _this6.zabbix.getEvents(objectids, timeFrom, timeTo, showOkEvents).then(function (events) {
|
||||||
|
var indexedTriggers = _lodash2.default.keyBy(triggers, 'triggerid');
|
||||||
|
|
||||||
|
// Hide acknowledged events if option enabled
|
||||||
|
if (annotation.hideAcknowledged) {
|
||||||
|
events = _lodash2.default.filter(events, function (event) {
|
||||||
|
return !event.acknowledges.length;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return _lodash2.default.map(events, function (event) {
|
||||||
|
var tags = void 0;
|
||||||
|
if (annotation.showHostname) {
|
||||||
|
tags = _lodash2.default.map(event.hosts, 'name');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show event type (OK or Problem)
|
||||||
|
var title = Number(event.value) ? 'Problem' : 'OK';
|
||||||
|
|
||||||
|
var formatted_acknowledges = utils.formatAcknowledges(event.acknowledges);
|
||||||
|
return {
|
||||||
|
annotation: annotation,
|
||||||
|
time: event.clock * 1000,
|
||||||
|
title: title,
|
||||||
|
tags: tags,
|
||||||
|
text: indexedTriggers[event.objectid].description + formatted_acknowledges
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace template variables
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'replaceTargetVariables',
|
||||||
|
value: function replaceTargetVariables(target, options) {
|
||||||
|
var _this7 = this;
|
||||||
|
|
||||||
|
var parts = ['group', 'host', 'application', 'item'];
|
||||||
|
parts.forEach(function (p) {
|
||||||
|
if (target[p] && target[p].filter) {
|
||||||
|
target[p].filter = _this7.replaceTemplateVars(target[p].filter, options.scopedVars);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
target.textFilter = this.replaceTemplateVars(target.textFilter, options.scopedVars);
|
||||||
|
|
||||||
|
_lodash2.default.forEach(target.functions, function (func) {
|
||||||
|
func.params = func.params.map(function (param) {
|
||||||
|
if (typeof param === 'number') {
|
||||||
|
return +_this7.templateSrv.replace(param.toString(), options.scopedVars);
|
||||||
|
} else {
|
||||||
|
return _this7.templateSrv.replace(param, options.scopedVars);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixAPIDatasource;
|
||||||
|
}();
|
||||||
|
|
||||||
|
function bindFunctionDefs(functionDefs, category) {
|
||||||
|
var aggregationFunctions = _lodash2.default.map(metricFunctions.getCategories()[category], 'name');
|
||||||
|
var aggFuncDefs = _lodash2.default.filter(functionDefs, function (func) {
|
||||||
|
return _lodash2.default.includes(aggregationFunctions, func.def.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
return _lodash2.default.map(aggFuncDefs, function (func) {
|
||||||
|
var funcInstance = metricFunctions.createFuncInstance(func.def, func.params);
|
||||||
|
return funcInstance.bindFunction(_dataProcessor2.default.metricFunctions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function downsampleSeries(timeseries_data, options) {
|
||||||
|
return _lodash2.default.map(timeseries_data, function (timeseries) {
|
||||||
|
if (timeseries.datapoints.length > options.maxDataPoints) {
|
||||||
|
timeseries.datapoints = _dataProcessor2.default.groupBy(options.interval, _dataProcessor2.default.AVERAGE, timeseries.datapoints);
|
||||||
|
}
|
||||||
|
return timeseries;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMetric(metricObj) {
|
||||||
|
return {
|
||||||
|
text: metricObj.name,
|
||||||
|
expandable: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom formatter for template variables.
|
||||||
|
* Default Grafana "regex" formatter returns
|
||||||
|
* value1|value2
|
||||||
|
* This formatter returns
|
||||||
|
* (value1|value2)
|
||||||
|
* This format needed for using in complex regex with
|
||||||
|
* template variables, for example
|
||||||
|
* /CPU $cpu_item.*time/ where $cpu_item is system,user,iowait
|
||||||
|
*/
|
||||||
|
function zabbixTemplateFormat(value) {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return utils.escapeRegex(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var escapedValues = _lodash2.default.map(value, utils.escapeRegex);
|
||||||
|
return '(' + escapedValues.join('|') + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If template variables are used in request, replace it using regex format
|
||||||
|
* and wrap with '/' for proper multi-value work. Example:
|
||||||
|
* $variable selected as a, b, c
|
||||||
|
* We use filter $variable
|
||||||
|
* $variable -> a|b|c -> /a|b|c/
|
||||||
|
* /$variable/ -> /a|b|c/ -> /a|b|c/
|
||||||
|
*/
|
||||||
|
function replaceTemplateVars(templateSrv, target, scopedVars) {
|
||||||
|
var replacedTarget = templateSrv.replace(target, scopedVars, zabbixTemplateFormat);
|
||||||
|
if (target !== replacedTarget && !utils.isRegex(replacedTarget)) {
|
||||||
|
replacedTarget = '/^' + replacedTarget + '$/';
|
||||||
|
}
|
||||||
|
return replacedTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractText(str, pattern, useCaptureGroups) {
|
||||||
|
var extractPattern = new RegExp(pattern);
|
||||||
|
var extractedValue = extractPattern.exec(str);
|
||||||
|
if (extractedValue) {
|
||||||
|
if (useCaptureGroups) {
|
||||||
|
extractedValue = extractedValue[1];
|
||||||
|
} else {
|
||||||
|
extractedValue = extractedValue[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply function one by one:
|
||||||
|
// sequence([a(), b(), c()]) = c(b(a()));
|
||||||
|
function sequence(funcsArray) {
|
||||||
|
return function (result) {
|
||||||
|
for (var i = 0; i < funcsArray.length; i++) {
|
||||||
|
result = funcsArray[i].call(this, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.ZabbixAPIDatasource = ZabbixAPIDatasource;
|
||||||
|
exports.zabbixTemplateFormat = zabbixTemplateFormat;
|
||||||
|
|
||||||
|
// Fix for backward compatibility with lodash 2.4
|
||||||
|
|
||||||
|
if (!_lodash2.default.includes) {
|
||||||
|
_lodash2.default.includes = _lodash2.default.contains;
|
||||||
|
}
|
||||||
|
if (!_lodash2.default.keyBy) {
|
||||||
|
_lodash2.default.keyBy = _lodash2.default.indexBy;
|
||||||
|
}
|
||||||
246
dist/test/datasource-zabbix/metric-function-editor.directive.js
vendored
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _angular = require('angular');
|
||||||
|
|
||||||
|
var _angular2 = _interopRequireDefault(_angular);
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _jquery = require('jquery');
|
||||||
|
|
||||||
|
var _jquery2 = _interopRequireDefault(_jquery);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
_angular2.default.module('grafana.directives').directive('metricFunctionEditor', function ($compile, templateSrv) {
|
||||||
|
|
||||||
|
var funcSpanTemplate = '<a ng-click="">{{func.def.name}}</a><span>(</span>';
|
||||||
|
var paramTemplate = '<input type="text" style="display:none"' + ' class="input-mini tight-form-func-param"></input>';
|
||||||
|
|
||||||
|
var funcControlsTemplate = '<div class="tight-form-func-controls">' + '<span class="pointer fa fa-arrow-left"></span>' + '<span class="pointer fa fa-question-circle"></span>' + '<span class="pointer fa fa-remove" ></span>' + '<span class="pointer fa fa-arrow-right"></span>' + '</div>';
|
||||||
|
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
link: function postLink($scope, elem) {
|
||||||
|
var $funcLink = (0, _jquery2.default)(funcSpanTemplate);
|
||||||
|
var $funcControls = (0, _jquery2.default)(funcControlsTemplate);
|
||||||
|
var ctrl = $scope.ctrl;
|
||||||
|
var func = $scope.func;
|
||||||
|
var funcDef = func.def;
|
||||||
|
var scheduledRelink = false;
|
||||||
|
var paramCountAtLink = 0;
|
||||||
|
|
||||||
|
function clickFuncParam(paramIndex) {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
|
||||||
|
var $link = (0, _jquery2.default)(this);
|
||||||
|
var $input = $link.next();
|
||||||
|
|
||||||
|
$input.val(func.params[paramIndex]);
|
||||||
|
$input.css('width', $link.width() + 16 + 'px');
|
||||||
|
|
||||||
|
$link.hide();
|
||||||
|
$input.show();
|
||||||
|
$input.focus();
|
||||||
|
$input.select();
|
||||||
|
|
||||||
|
var typeahead = $input.data('typeahead');
|
||||||
|
if (typeahead) {
|
||||||
|
$input.val('');
|
||||||
|
typeahead.lookup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduledRelinkIfNeeded() {
|
||||||
|
if (paramCountAtLink === func.params.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scheduledRelink) {
|
||||||
|
scheduledRelink = true;
|
||||||
|
setTimeout(function () {
|
||||||
|
relink();
|
||||||
|
scheduledRelink = false;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputBlur(paramIndex) {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
var $input = (0, _jquery2.default)(this);
|
||||||
|
var $link = $input.prev();
|
||||||
|
var newValue = $input.val();
|
||||||
|
|
||||||
|
if (newValue !== '' || func.def.params[paramIndex].optional) {
|
||||||
|
$link.html(templateSrv.highlightVariablesAsHtml(newValue));
|
||||||
|
|
||||||
|
func.updateParam($input.val(), paramIndex);
|
||||||
|
scheduledRelinkIfNeeded();
|
||||||
|
|
||||||
|
$scope.$apply(function () {
|
||||||
|
ctrl.targetChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.hide();
|
||||||
|
$link.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputKeyPress(paramIndex, e) {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
if (e.which === 13) {
|
||||||
|
inputBlur.call(this, paramIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputKeyDown() {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
this.style.width = (3 + this.value.length) * 8 + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTypeahead($input, paramIndex) {
|
||||||
|
$input.attr('data-provide', 'typeahead');
|
||||||
|
|
||||||
|
var options = funcDef.params[paramIndex].options;
|
||||||
|
if (funcDef.params[paramIndex].type === 'int' || funcDef.params[paramIndex].type === 'float') {
|
||||||
|
options = _lodash2.default.map(options, function (val) {
|
||||||
|
return val.toString();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$input.typeahead({
|
||||||
|
source: options,
|
||||||
|
minLength: 0,
|
||||||
|
items: 20,
|
||||||
|
updater: function updater(value) {
|
||||||
|
setTimeout(function () {
|
||||||
|
inputBlur.call($input[0], paramIndex);
|
||||||
|
}, 0);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var typeahead = $input.data('typeahead');
|
||||||
|
typeahead.lookup = function () {
|
||||||
|
this.query = this.$element.val() || '';
|
||||||
|
return this.process(this.source);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleFuncControls() {
|
||||||
|
var targetDiv = elem.closest('.tight-form');
|
||||||
|
|
||||||
|
if (elem.hasClass('show-function-controls')) {
|
||||||
|
elem.removeClass('show-function-controls');
|
||||||
|
targetDiv.removeClass('has-open-function');
|
||||||
|
$funcControls.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
elem.addClass('show-function-controls');
|
||||||
|
targetDiv.addClass('has-open-function');
|
||||||
|
|
||||||
|
$funcControls.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addElementsAndCompile() {
|
||||||
|
$funcControls.appendTo(elem);
|
||||||
|
$funcLink.appendTo(elem);
|
||||||
|
|
||||||
|
_lodash2.default.each(funcDef.params, function (param, index) {
|
||||||
|
if (param.optional && func.params.length <= index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index > 0) {
|
||||||
|
(0, _jquery2.default)('<span>, </span>').appendTo(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
var paramValue = templateSrv.highlightVariablesAsHtml(func.params[index]);
|
||||||
|
var $paramLink = (0, _jquery2.default)('<a ng-click="" class="graphite-func-param-link">' + paramValue + '</a>');
|
||||||
|
var $input = (0, _jquery2.default)(paramTemplate);
|
||||||
|
|
||||||
|
paramCountAtLink++;
|
||||||
|
|
||||||
|
$paramLink.appendTo(elem);
|
||||||
|
$input.appendTo(elem);
|
||||||
|
|
||||||
|
$input.blur(_lodash2.default.partial(inputBlur, index));
|
||||||
|
$input.keyup(inputKeyDown);
|
||||||
|
$input.keypress(_lodash2.default.partial(inputKeyPress, index));
|
||||||
|
$paramLink.click(_lodash2.default.partial(clickFuncParam, index));
|
||||||
|
|
||||||
|
if (funcDef.params[index].options) {
|
||||||
|
addTypeahead($input, index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
(0, _jquery2.default)('<span>)</span>').appendTo(elem);
|
||||||
|
|
||||||
|
$compile(elem.contents())($scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ifJustAddedFocusFistParam() {
|
||||||
|
if ($scope.func.added) {
|
||||||
|
$scope.func.added = false;
|
||||||
|
setTimeout(function () {
|
||||||
|
elem.find('.graphite-func-param-link').first().click();
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerFuncControlsToggle() {
|
||||||
|
$funcLink.click(toggleFuncControls);
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerFuncControlsActions() {
|
||||||
|
$funcControls.click(function (e) {
|
||||||
|
var $target = (0, _jquery2.default)(e.target);
|
||||||
|
if ($target.hasClass('fa-remove')) {
|
||||||
|
toggleFuncControls();
|
||||||
|
$scope.$apply(function () {
|
||||||
|
ctrl.removeFunction($scope.func);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($target.hasClass('fa-arrow-left')) {
|
||||||
|
$scope.$apply(function () {
|
||||||
|
_lodash2.default.move($scope.target.functions, $scope.$index, $scope.$index - 1);
|
||||||
|
ctrl.targetChanged();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($target.hasClass('fa-arrow-right')) {
|
||||||
|
$scope.$apply(function () {
|
||||||
|
_lodash2.default.move($scope.target.functions, $scope.$index, $scope.$index + 1);
|
||||||
|
ctrl.targetChanged();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($target.hasClass('fa-question-circle')) {
|
||||||
|
var docSite = "http://docs.grafana-zabbix.org/reference/functions/";
|
||||||
|
window.open(docSite + '#' + funcDef.name.toLowerCase(), '_blank');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function relink() {
|
||||||
|
elem.children().remove();
|
||||||
|
|
||||||
|
addElementsAndCompile();
|
||||||
|
ifJustAddedFocusFistParam();
|
||||||
|
registerFuncControlsToggle();
|
||||||
|
registerFuncControlsActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
relink();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
292
dist/test/datasource-zabbix/metricFunctions.js
vendored
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
|
||||||
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||||
|
|
||||||
|
exports.createFuncInstance = createFuncInstance;
|
||||||
|
exports.getFuncDef = getFuncDef;
|
||||||
|
exports.getCategories = getCategories;
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _jquery = require('jquery');
|
||||||
|
|
||||||
|
var _jquery2 = _interopRequireDefault(_jquery);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
var index = [];
|
||||||
|
var categories = {
|
||||||
|
Transform: [],
|
||||||
|
Aggregate: [],
|
||||||
|
Filter: [],
|
||||||
|
Trends: [],
|
||||||
|
Time: [],
|
||||||
|
Alias: []
|
||||||
|
};
|
||||||
|
|
||||||
|
function addFuncDef(funcDef) {
|
||||||
|
funcDef.params = funcDef.params || [];
|
||||||
|
funcDef.defaultParams = funcDef.defaultParams || [];
|
||||||
|
|
||||||
|
if (funcDef.category) {
|
||||||
|
categories[funcDef.category].push(funcDef);
|
||||||
|
}
|
||||||
|
index[funcDef.name] = funcDef;
|
||||||
|
index[funcDef.shortName || funcDef.name] = funcDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'groupBy',
|
||||||
|
category: 'Transform',
|
||||||
|
params: [{ name: 'interval', type: 'string' }, { name: 'function', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
|
||||||
|
defaultParams: ['1m', 'avg']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'scale',
|
||||||
|
category: 'Transform',
|
||||||
|
params: [{ name: 'factor', type: 'float', options: [100, 0.01, 10, -1] }],
|
||||||
|
defaultParams: [100]
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'delta',
|
||||||
|
category: 'Transform',
|
||||||
|
params: [],
|
||||||
|
defaultParams: []
|
||||||
|
});
|
||||||
|
|
||||||
|
// Aggregate
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'sumSeries',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [],
|
||||||
|
defaultParams: []
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'median',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [{ name: 'interval', type: 'string' }],
|
||||||
|
defaultParams: ['1m']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'average',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [{ name: 'interval', type: 'string' }],
|
||||||
|
defaultParams: ['1m']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'min',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [{ name: 'interval', type: 'string' }],
|
||||||
|
defaultParams: ['1m']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'max',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [{ name: 'interval', type: 'string' }],
|
||||||
|
defaultParams: ['1m']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'aggregateBy',
|
||||||
|
category: 'Aggregate',
|
||||||
|
params: [{ name: 'interval', type: 'string' }, { name: 'function', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
|
||||||
|
defaultParams: ['1m', 'avg']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'top',
|
||||||
|
category: 'Filter',
|
||||||
|
params: [{ name: 'number', type: 'int' }, { name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
|
||||||
|
defaultParams: [5, 'avg']
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'bottom',
|
||||||
|
category: 'Filter',
|
||||||
|
params: [{ name: 'number', type: 'int' }, { name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
|
||||||
|
defaultParams: [5, 'avg']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Trends
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'trendValue',
|
||||||
|
category: 'Trends',
|
||||||
|
params: [{ name: 'type', type: 'string', options: ['avg', 'min', 'max'] }],
|
||||||
|
defaultParams: ['avg']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Time
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'timeShift',
|
||||||
|
category: 'Time',
|
||||||
|
params: [{ name: 'interval', type: 'string', options: ['24h', '7d', '1M', '+24h', '-24h'] }],
|
||||||
|
defaultParams: ['24h']
|
||||||
|
});
|
||||||
|
|
||||||
|
//Alias
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'setAlias',
|
||||||
|
category: 'Alias',
|
||||||
|
params: [{ name: 'alias', type: 'string' }],
|
||||||
|
defaultParams: []
|
||||||
|
});
|
||||||
|
|
||||||
|
addFuncDef({
|
||||||
|
name: 'setAliasByRegex',
|
||||||
|
category: 'Alias',
|
||||||
|
params: [{ name: 'aliasByRegex', type: 'string' }],
|
||||||
|
defaultParams: []
|
||||||
|
});
|
||||||
|
|
||||||
|
_lodash2.default.each(categories, function (funcList, catName) {
|
||||||
|
categories[catName] = _lodash2.default.sortBy(funcList, 'name');
|
||||||
|
});
|
||||||
|
|
||||||
|
var FuncInstance = function () {
|
||||||
|
function FuncInstance(funcDef, params) {
|
||||||
|
_classCallCheck(this, FuncInstance);
|
||||||
|
|
||||||
|
this.def = funcDef;
|
||||||
|
|
||||||
|
if (params) {
|
||||||
|
this.params = params;
|
||||||
|
} else {
|
||||||
|
// Create with default params
|
||||||
|
this.params = [];
|
||||||
|
this.params = funcDef.defaultParams.slice(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateText();
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(FuncInstance, [{
|
||||||
|
key: 'bindFunction',
|
||||||
|
value: function bindFunction(metricFunctions) {
|
||||||
|
var func = metricFunctions[this.def.name];
|
||||||
|
if (func) {
|
||||||
|
|
||||||
|
// Bind function arguments
|
||||||
|
var bindedFunc = func;
|
||||||
|
var param;
|
||||||
|
for (var i = 0; i < this.params.length; i++) {
|
||||||
|
param = this.params[i];
|
||||||
|
|
||||||
|
// Convert numeric params
|
||||||
|
if (this.def.params[i].type === 'int' || this.def.params[i].type === 'float') {
|
||||||
|
param = Number(param);
|
||||||
|
}
|
||||||
|
bindedFunc = _lodash2.default.partial(bindedFunc, param);
|
||||||
|
}
|
||||||
|
return bindedFunc;
|
||||||
|
} else {
|
||||||
|
throw { message: 'Method not found ' + this.def.name };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'render',
|
||||||
|
value: function render(metricExp) {
|
||||||
|
var str = this.def.name + '(';
|
||||||
|
var parameters = _lodash2.default.map(this.params, function (value, index) {
|
||||||
|
|
||||||
|
var paramType = this.def.params[index].type;
|
||||||
|
if (paramType === 'int' || paramType === 'float' || paramType === 'value_or_series' || paramType === 'boolean') {
|
||||||
|
return value;
|
||||||
|
} else if (paramType === 'int_or_interval' && _jquery2.default.isNumeric(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "'" + value + "'";
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
if (metricExp) {
|
||||||
|
parameters.unshift(metricExp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str + parameters.join(', ') + ')';
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: '_hasMultipleParamsInString',
|
||||||
|
value: function _hasMultipleParamsInString(strValue, index) {
|
||||||
|
if (strValue.indexOf(',') === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.def.params[index + 1] && this.def.params[index + 1].optional;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'updateParam',
|
||||||
|
value: function updateParam(strValue, index) {
|
||||||
|
// handle optional parameters
|
||||||
|
// if string contains ',' and next param is optional, split and update both
|
||||||
|
if (this._hasMultipleParamsInString(strValue, index)) {
|
||||||
|
_lodash2.default.each(strValue.split(','), function (partVal, idx) {
|
||||||
|
this.updateParam(partVal.trim(), idx);
|
||||||
|
}, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strValue === '' && this.def.params[index].optional) {
|
||||||
|
this.params.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
this.params[index] = strValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateText();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'updateText',
|
||||||
|
value: function updateText() {
|
||||||
|
if (this.params.length === 0) {
|
||||||
|
this.text = this.def.name + '()';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = this.def.name + '(';
|
||||||
|
text += this.params.join(', ');
|
||||||
|
text += ')';
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return FuncInstance;
|
||||||
|
}();
|
||||||
|
|
||||||
|
function createFuncInstance(funcDef, params) {
|
||||||
|
if (_lodash2.default.isString(funcDef)) {
|
||||||
|
if (!index[funcDef]) {
|
||||||
|
throw { message: 'Method not found ' + name };
|
||||||
|
}
|
||||||
|
funcDef = index[funcDef];
|
||||||
|
}
|
||||||
|
return new FuncInstance(funcDef, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFuncDef(name) {
|
||||||
|
return index[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCategories() {
|
||||||
|
return categories;
|
||||||
|
}
|
||||||
48
dist/test/datasource-zabbix/migrations.js
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.isGrafana2target = isGrafana2target;
|
||||||
|
exports.migrateFrom2To3version = migrateFrom2To3version;
|
||||||
|
exports.migrate = migrate;
|
||||||
|
/**
|
||||||
|
* Query format migration.
|
||||||
|
* This module can detect query format version and make migration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isGrafana2target(target) {
|
||||||
|
if (!target.mode || target.mode === 0 || target.mode === 2) {
|
||||||
|
if ((target.hostFilter || target.itemFilter || target.downsampleFunction || target.host && target.host.host) && target.item.filter === undefined && target.host.filter === undefined) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateFrom2To3version(target) {
|
||||||
|
target.group.filter = target.group.name === "*" ? "/.*/" : target.group.name;
|
||||||
|
target.host.filter = target.host.name === "*" ? convertToRegex(target.hostFilter) : target.host.name;
|
||||||
|
target.application.filter = target.application.name === "*" ? "" : target.application.name;
|
||||||
|
target.item.filter = target.item.name === "All" ? convertToRegex(target.itemFilter) : target.item.name;
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrate(target) {
|
||||||
|
if (isGrafana2target(target)) {
|
||||||
|
return migrateFrom2To3version(target);
|
||||||
|
} else {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertToRegex(str) {
|
||||||
|
if (str) {
|
||||||
|
return '/' + str + '/';
|
||||||
|
} else {
|
||||||
|
return '/.*/';
|
||||||
|
}
|
||||||
|
}
|
||||||
36
dist/test/datasource-zabbix/module.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.AnnotationsQueryCtrl = exports.QueryOptionsCtrl = exports.QueryCtrl = exports.ConfigCtrl = exports.Datasource = undefined;
|
||||||
|
|
||||||
|
var _datasource = require('./datasource');
|
||||||
|
|
||||||
|
var _query = require('./query.controller');
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
var ZabbixConfigController = function ZabbixConfigController() {
|
||||||
|
_classCallCheck(this, ZabbixConfigController);
|
||||||
|
};
|
||||||
|
|
||||||
|
ZabbixConfigController.templateUrl = 'datasource-zabbix/partials/config.html';
|
||||||
|
|
||||||
|
var ZabbixQueryOptionsController = function ZabbixQueryOptionsController() {
|
||||||
|
_classCallCheck(this, ZabbixQueryOptionsController);
|
||||||
|
};
|
||||||
|
|
||||||
|
ZabbixQueryOptionsController.templateUrl = 'datasource-zabbix/partials/query.options.html';
|
||||||
|
|
||||||
|
var ZabbixAnnotationsQueryController = function ZabbixAnnotationsQueryController() {
|
||||||
|
_classCallCheck(this, ZabbixAnnotationsQueryController);
|
||||||
|
};
|
||||||
|
|
||||||
|
ZabbixAnnotationsQueryController.templateUrl = 'datasource-zabbix/partials/annotations.editor.html';
|
||||||
|
|
||||||
|
exports.Datasource = _datasource.ZabbixAPIDatasource;
|
||||||
|
exports.ConfigCtrl = ZabbixConfigController;
|
||||||
|
exports.QueryCtrl = _query.ZabbixQueryController;
|
||||||
|
exports.QueryOptionsCtrl = ZabbixQueryOptionsController;
|
||||||
|
exports.AnnotationsQueryCtrl = ZabbixAnnotationsQueryController;
|
||||||
378
dist/test/datasource-zabbix/query.controller.js
vendored
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.ZabbixQueryController = undefined;
|
||||||
|
|
||||||
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||||
|
|
||||||
|
var _sdk = require('app/plugins/sdk');
|
||||||
|
|
||||||
|
var _angular = require('angular');
|
||||||
|
|
||||||
|
var _angular2 = _interopRequireDefault(_angular);
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _utils = require('./utils');
|
||||||
|
|
||||||
|
var utils = _interopRequireWildcard(_utils);
|
||||||
|
|
||||||
|
var _metricFunctions = require('./metricFunctions');
|
||||||
|
|
||||||
|
var metricFunctions = _interopRequireWildcard(_metricFunctions);
|
||||||
|
|
||||||
|
var _migrations = require('./migrations');
|
||||||
|
|
||||||
|
var migrations = _interopRequireWildcard(_migrations);
|
||||||
|
|
||||||
|
require('./add-metric-function.directive');
|
||||||
|
|
||||||
|
require('./metric-function-editor.directive');
|
||||||
|
|
||||||
|
require('./css/query-editor.css!');
|
||||||
|
|
||||||
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||||||
|
|
||||||
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||||
|
|
||||||
|
var ZabbixQueryController = exports.ZabbixQueryController = function (_QueryCtrl) {
|
||||||
|
_inherits(ZabbixQueryController, _QueryCtrl);
|
||||||
|
|
||||||
|
// ZabbixQueryCtrl constructor
|
||||||
|
function ZabbixQueryController($scope, $injector, $rootScope, $sce, templateSrv) {
|
||||||
|
_classCallCheck(this, ZabbixQueryController);
|
||||||
|
|
||||||
|
var _this = _possibleConstructorReturn(this, (ZabbixQueryController.__proto__ || Object.getPrototypeOf(ZabbixQueryController)).call(this, $scope, $injector));
|
||||||
|
|
||||||
|
_this.zabbix = _this.datasource.zabbix;
|
||||||
|
|
||||||
|
// Use custom format for template variables
|
||||||
|
_this.replaceTemplateVars = _this.datasource.replaceTemplateVars;
|
||||||
|
_this.templateSrv = templateSrv;
|
||||||
|
|
||||||
|
_this.editorModes = {
|
||||||
|
0: { value: 'num', text: 'Metrics', mode: 0 },
|
||||||
|
1: { value: 'itservice', text: 'IT Services', mode: 1 },
|
||||||
|
2: { value: 'text', text: 'Text', mode: 2 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map functions for bs-typeahead
|
||||||
|
_this.getGroupNames = _lodash2.default.partial(getMetricNames, _this, 'groupList');
|
||||||
|
_this.getHostNames = _lodash2.default.partial(getMetricNames, _this, 'hostList');
|
||||||
|
_this.getApplicationNames = _lodash2.default.partial(getMetricNames, _this, 'appList');
|
||||||
|
_this.getItemNames = _lodash2.default.partial(getMetricNames, _this, 'itemList');
|
||||||
|
|
||||||
|
// Update metric suggestion when template variable was changed
|
||||||
|
$rootScope.$on('template-variable-value-updated', function () {
|
||||||
|
return _this.onVariableChange();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update metrics when item selected from dropdown
|
||||||
|
$scope.$on('typeahead-updated', function () {
|
||||||
|
_this.onTargetBlur();
|
||||||
|
});
|
||||||
|
|
||||||
|
_this.init = function () {
|
||||||
|
var target = this.target;
|
||||||
|
|
||||||
|
// Migrate old targets
|
||||||
|
target = migrations.migrate(target);
|
||||||
|
|
||||||
|
var scopeDefaults = {
|
||||||
|
metric: {},
|
||||||
|
oldTarget: _lodash2.default.cloneDeep(this.target),
|
||||||
|
queryOptionsText: this.renderQueryOptionsText()
|
||||||
|
};
|
||||||
|
_lodash2.default.defaults(this, scopeDefaults);
|
||||||
|
|
||||||
|
// Load default values
|
||||||
|
var targetDefaults = {
|
||||||
|
mode: 0,
|
||||||
|
group: { filter: "" },
|
||||||
|
host: { filter: "" },
|
||||||
|
application: { filter: "" },
|
||||||
|
item: { filter: "" },
|
||||||
|
functions: [],
|
||||||
|
options: {
|
||||||
|
showDisabledItems: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_lodash2.default.defaults(target, targetDefaults);
|
||||||
|
|
||||||
|
// Create function instances from saved JSON
|
||||||
|
target.functions = _lodash2.default.map(target.functions, function (func) {
|
||||||
|
return metricFunctions.createFuncInstance(func.def, func.params);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (target.mode === 0 || target.mode === 2) {
|
||||||
|
|
||||||
|
this.downsampleFunctionList = [{ name: "avg", value: "avg" }, { name: "min", value: "min" }, { name: "max", value: "max" }];
|
||||||
|
|
||||||
|
this.initFilters();
|
||||||
|
} else if (target.mode === 1) {
|
||||||
|
this.slaPropertyList = [{ name: "Status", property: "status" }, { name: "SLA", property: "sla" }, { name: "OK time", property: "okTime" }, { name: "Problem time", property: "problemTime" }, { name: "Down time", property: "downtimeTime" }];
|
||||||
|
this.itserviceList = [{ name: "test" }];
|
||||||
|
this.updateITServiceList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_this.init();
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(ZabbixQueryController, [{
|
||||||
|
key: 'initFilters',
|
||||||
|
value: function initFilters() {
|
||||||
|
var itemtype = this.editorModes[this.target.mode].value;
|
||||||
|
return Promise.all([this.suggestGroups(), this.suggestHosts(), this.suggestApps(), this.suggestItems(itemtype)]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestGroups',
|
||||||
|
value: function suggestGroups() {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
return this.zabbix.getAllGroups().then(function (groups) {
|
||||||
|
_this2.metric.groupList = groups;
|
||||||
|
return groups;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestHosts',
|
||||||
|
value: function suggestHosts() {
|
||||||
|
var _this3 = this;
|
||||||
|
|
||||||
|
var groupFilter = this.replaceTemplateVars(this.target.group.filter);
|
||||||
|
return this.zabbix.getAllHosts(groupFilter).then(function (hosts) {
|
||||||
|
_this3.metric.hostList = hosts;
|
||||||
|
return hosts;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestApps',
|
||||||
|
value: function suggestApps() {
|
||||||
|
var _this4 = this;
|
||||||
|
|
||||||
|
var groupFilter = this.replaceTemplateVars(this.target.group.filter);
|
||||||
|
var hostFilter = this.replaceTemplateVars(this.target.host.filter);
|
||||||
|
return this.zabbix.getAllApps(groupFilter, hostFilter).then(function (apps) {
|
||||||
|
_this4.metric.appList = apps;
|
||||||
|
return apps;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestItems',
|
||||||
|
value: function suggestItems() {
|
||||||
|
var _this5 = this;
|
||||||
|
|
||||||
|
var itemtype = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'num';
|
||||||
|
|
||||||
|
var groupFilter = this.replaceTemplateVars(this.target.group.filter);
|
||||||
|
var hostFilter = this.replaceTemplateVars(this.target.host.filter);
|
||||||
|
var appFilter = this.replaceTemplateVars(this.target.application.filter);
|
||||||
|
var options = {
|
||||||
|
itemtype: itemtype,
|
||||||
|
showDisabledItems: this.target.options.showDisabledItems
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.zabbix.getAllItems(groupFilter, hostFilter, appFilter, options).then(function (items) {
|
||||||
|
_this5.metric.itemList = items;
|
||||||
|
return items;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'isRegex',
|
||||||
|
value: function isRegex(str) {
|
||||||
|
return utils.isRegex(str);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'isVariable',
|
||||||
|
value: function isVariable(str) {
|
||||||
|
return utils.isTemplateVariable(str, this.templateSrv.variables);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'onTargetBlur',
|
||||||
|
value: function onTargetBlur() {
|
||||||
|
var newTarget = _lodash2.default.cloneDeep(this.target);
|
||||||
|
if (!_lodash2.default.isEqual(this.oldTarget, this.target)) {
|
||||||
|
this.oldTarget = newTarget;
|
||||||
|
this.targetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'onVariableChange',
|
||||||
|
value: function onVariableChange() {
|
||||||
|
if (this.isContainsVariables()) {
|
||||||
|
this.targetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check query for template variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'isContainsVariables',
|
||||||
|
value: function isContainsVariables() {
|
||||||
|
var _this6 = this;
|
||||||
|
|
||||||
|
return _lodash2.default.some(['group', 'host', 'application'], function (field) {
|
||||||
|
if (_this6.target[field] && _this6.target[field].filter) {
|
||||||
|
return utils.isTemplateVariable(_this6.target[field].filter, _this6.templateSrv.variables);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'parseTarget',
|
||||||
|
value: function parseTarget() {}
|
||||||
|
// Parse target
|
||||||
|
|
||||||
|
|
||||||
|
// Validate target and set validation info
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'validateTarget',
|
||||||
|
value: function validateTarget() {
|
||||||
|
// validate
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'targetChanged',
|
||||||
|
value: function targetChanged() {
|
||||||
|
this.initFilters();
|
||||||
|
this.parseTarget();
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'addFunction',
|
||||||
|
value: function addFunction(funcDef) {
|
||||||
|
var newFunc = metricFunctions.createFuncInstance(funcDef);
|
||||||
|
newFunc.added = true;
|
||||||
|
this.target.functions.push(newFunc);
|
||||||
|
|
||||||
|
this.moveAliasFuncLast();
|
||||||
|
|
||||||
|
if (newFunc.params.length && newFunc.added || newFunc.def.params.length === 0) {
|
||||||
|
this.targetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'removeFunction',
|
||||||
|
value: function removeFunction(func) {
|
||||||
|
this.target.functions = _lodash2.default.without(this.target.functions, func);
|
||||||
|
this.targetChanged();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'moveAliasFuncLast',
|
||||||
|
value: function moveAliasFuncLast() {
|
||||||
|
var aliasFunc = _lodash2.default.find(this.target.functions, function (func) {
|
||||||
|
return func.def.name === 'alias' || func.def.name === 'aliasByNode' || func.def.name === 'aliasByMetric';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (aliasFunc) {
|
||||||
|
this.target.functions = _lodash2.default.without(this.target.functions, aliasFunc);
|
||||||
|
this.target.functions.push(aliasFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'toggleQueryOptions',
|
||||||
|
value: function toggleQueryOptions() {
|
||||||
|
this.showQueryOptions = !this.showQueryOptions;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'onQueryOptionChange',
|
||||||
|
value: function onQueryOptionChange() {
|
||||||
|
this.queryOptionsText = this.renderQueryOptionsText();
|
||||||
|
this.onTargetBlur();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'renderQueryOptionsText',
|
||||||
|
value: function renderQueryOptionsText() {
|
||||||
|
var optionsMap = {
|
||||||
|
showDisabledItems: "Show disabled items"
|
||||||
|
};
|
||||||
|
var options = [];
|
||||||
|
_lodash2.default.forOwn(this.target.options, function (value, key) {
|
||||||
|
if (value) {
|
||||||
|
if (value === true) {
|
||||||
|
// Show only option name (if enabled) for boolean options
|
||||||
|
options.push(optionsMap[key]);
|
||||||
|
} else {
|
||||||
|
// Show "option = value" for another options
|
||||||
|
options.push(optionsMap[key] + " = " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return "Options: " + options.join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch query editor to specified mode.
|
||||||
|
* Modes:
|
||||||
|
* 0 - items
|
||||||
|
* 1 - IT services
|
||||||
|
* 2 - Text metrics
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'switchEditorMode',
|
||||||
|
value: function switchEditorMode(mode) {
|
||||||
|
this.target.mode = mode;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
// IT Services //
|
||||||
|
/////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update list of IT services
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'updateITServiceList',
|
||||||
|
value: function updateITServiceList() {
|
||||||
|
var _this7 = this;
|
||||||
|
|
||||||
|
this.zabbix.getITService().then(function (iteservices) {
|
||||||
|
_this7.itserviceList = [];
|
||||||
|
_this7.itserviceList = _this7.itserviceList.concat(iteservices);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call when IT service is selected.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'selectITService',
|
||||||
|
value: function selectITService() {
|
||||||
|
if (!_lodash2.default.isEqual(this.oldTarget, this.target) && _lodash2.default.isEmpty(this.target.errors)) {
|
||||||
|
this.oldTarget = _angular2.default.copy(this.target);
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixQueryController;
|
||||||
|
}(_sdk.QueryCtrl);
|
||||||
|
|
||||||
|
// Set templateUrl as static property
|
||||||
|
|
||||||
|
|
||||||
|
ZabbixQueryController.templateUrl = 'datasource-zabbix/partials/query.editor.html';
|
||||||
|
|
||||||
|
// Get list of metric names for bs-typeahead directive
|
||||||
|
function getMetricNames(scope, metricList) {
|
||||||
|
return _lodash2.default.uniq(_lodash2.default.map(scope.metric[metricList], 'name'));
|
||||||
|
}
|
||||||
116
dist/test/datasource-zabbix/responseHandler.js
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Zabbix API history.get response to Grafana format
|
||||||
|
*
|
||||||
|
* @return {Array} Array of timeseries in Grafana format
|
||||||
|
* {
|
||||||
|
* target: "Metric name",
|
||||||
|
* datapoints: [[<value>, <unixtime>], ...]
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
function convertHistory(history, items, addHostName, convertPointCallback) {
|
||||||
|
/**
|
||||||
|
* Response should be in the format:
|
||||||
|
* data: [
|
||||||
|
* {
|
||||||
|
* target: "Metric name",
|
||||||
|
* datapoints: [[<value>, <unixtime>], ...]
|
||||||
|
* }, ...
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Group history by itemid
|
||||||
|
var grouped_history = _lodash2.default.groupBy(history, 'itemid');
|
||||||
|
var hosts = _lodash2.default.uniqBy(_lodash2.default.flatten(_lodash2.default.map(items, 'hosts')), 'hostid'); //uniqBy is needed to deduplicate
|
||||||
|
|
||||||
|
return _lodash2.default.map(grouped_history, function (hist, itemid) {
|
||||||
|
var item = _lodash2.default.find(items, { 'itemid': itemid });
|
||||||
|
var alias = item.name;
|
||||||
|
if (_lodash2.default.keys(hosts).length > 1 && addHostName) {
|
||||||
|
//only when actual multi hosts selected
|
||||||
|
var host = _lodash2.default.find(hosts, { 'hostid': item.hostid });
|
||||||
|
alias = host.name + ": " + alias;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
target: alias,
|
||||||
|
datapoints: _lodash2.default.map(hist, convertPointCallback)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleHistory(history, items) {
|
||||||
|
var addHostName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
||||||
|
|
||||||
|
return convertHistory(history, items, addHostName, convertHistoryPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleTrends(history, items, valueType) {
|
||||||
|
var addHostName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
|
||||||
|
|
||||||
|
var convertPointCallback = _lodash2.default.partial(convertTrendPoint, valueType);
|
||||||
|
return convertHistory(history, items, addHostName, convertPointCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSLAResponse(itservice, slaProperty, slaObject) {
|
||||||
|
var targetSLA = slaObject[itservice.serviceid].sla[0];
|
||||||
|
if (slaProperty.property === 'status') {
|
||||||
|
var targetStatus = parseInt(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]]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertHistoryPoint(point) {
|
||||||
|
// Value must be a number for properly work
|
||||||
|
return [Number(point.value), point.clock * 1000];
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertTrendPoint(valueType, point) {
|
||||||
|
var value;
|
||||||
|
switch (valueType) {
|
||||||
|
case "min":
|
||||||
|
value = point.value_min;
|
||||||
|
break;
|
||||||
|
case "max":
|
||||||
|
value = point.value_max;
|
||||||
|
break;
|
||||||
|
case "avg":
|
||||||
|
value = point.value_avg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value = point.value_avg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [Number(value), point.clock * 1000];
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.default = {
|
||||||
|
handleHistory: handleHistory,
|
||||||
|
convertHistory: convertHistory,
|
||||||
|
handleTrends: handleTrends,
|
||||||
|
handleSLAResponse: handleSLAResponse
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fix for backward compatibility with lodash 2.4
|
||||||
|
|
||||||
|
if (!_lodash2.default.uniqBy) {
|
||||||
|
_lodash2.default.uniqBy = _lodash2.default.uniq;
|
||||||
|
}
|
||||||
317
dist/test/datasource-zabbix/specs/datasource_specs.js
vendored
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _module = require("../module");
|
||||||
|
|
||||||
|
var _datasource = require("../datasource");
|
||||||
|
|
||||||
|
var _q = require("q");
|
||||||
|
|
||||||
|
var _q2 = _interopRequireDefault(_q);
|
||||||
|
|
||||||
|
var _sinon = require("sinon");
|
||||||
|
|
||||||
|
var _sinon2 = _interopRequireDefault(_sinon);
|
||||||
|
|
||||||
|
var _lodash = require("lodash");
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
describe('ZabbixDatasource', function () {
|
||||||
|
var ctx = {};
|
||||||
|
var defined = _sinon2.default.match.defined;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
ctx.instanceSettings = {
|
||||||
|
jsonData: {
|
||||||
|
username: 'zabbix',
|
||||||
|
password: 'zabbix',
|
||||||
|
trends: true,
|
||||||
|
trendsFrom: '7d'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ctx.templateSrv = {};
|
||||||
|
ctx.alertSrv = {};
|
||||||
|
ctx.zabbix = function () {};
|
||||||
|
|
||||||
|
ctx.ds = new _module.Datasource(ctx.instanceSettings, ctx.templateSrv, ctx.alertSrv, ctx.zabbix);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When querying data', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
ctx.ds.replaceTemplateVars = function (str) {
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.options = {
|
||||||
|
targets: [{
|
||||||
|
group: { filter: "" },
|
||||||
|
host: { filter: "" },
|
||||||
|
application: { filter: "" },
|
||||||
|
item: { filter: "" }
|
||||||
|
}],
|
||||||
|
range: { from: 'now-7d', to: 'now' }
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should return an empty array when no targets are set', function (done) {
|
||||||
|
var options = {
|
||||||
|
targets: [],
|
||||||
|
range: { from: 'now-6h', to: 'now' }
|
||||||
|
};
|
||||||
|
ctx.ds.query(options).then(function (result) {
|
||||||
|
expect(result.data).to.have.length(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use trends if it enabled and time more than trendsFrom', function (done) {
|
||||||
|
var ranges = ['now-7d', 'now-168h', 'now-1M', 'now-1y'];
|
||||||
|
|
||||||
|
_lodash2.default.forEach(ranges, function (range) {
|
||||||
|
ctx.options.range.from = range;
|
||||||
|
ctx.ds.queryNumericData = _sinon2.default.spy();
|
||||||
|
ctx.ds.query(ctx.options);
|
||||||
|
|
||||||
|
// Check that useTrends options is true
|
||||||
|
expect(ctx.ds.queryNumericData).to.have.been.calledWith(defined, defined, defined, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shouldnt use trends if it enabled and time less than trendsFrom', function (done) {
|
||||||
|
var ranges = ['now-6d', 'now-167h', 'now-1h', 'now-30m', 'now-30s'];
|
||||||
|
|
||||||
|
_lodash2.default.forEach(ranges, function (range) {
|
||||||
|
ctx.options.range.from = range;
|
||||||
|
ctx.ds.queryNumericData = _sinon2.default.spy();
|
||||||
|
ctx.ds.query(ctx.options);
|
||||||
|
|
||||||
|
// Check that useTrends options is false
|
||||||
|
expect(ctx.ds.queryNumericData).to.have.been.calledWith(defined, defined, defined, false);
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When replacing template variables', function () {
|
||||||
|
|
||||||
|
function testReplacingVariable(target, varValue, expectedResult, done) {
|
||||||
|
ctx.ds.templateSrv.replace = function () {
|
||||||
|
return (0, _datasource.zabbixTemplateFormat)(varValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = ctx.ds.replaceTemplateVars(target);
|
||||||
|
expect(result).to.equal(expectedResult);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Alphanumerics, spaces, dots, dashes and underscores
|
||||||
|
* are allowed in Zabbix host name.
|
||||||
|
* 'AaBbCc0123 .-_'
|
||||||
|
*/
|
||||||
|
it('should return properly escaped regex', function (done) {
|
||||||
|
var target = '$host';
|
||||||
|
var template_var_value = 'AaBbCc0123 .-_';
|
||||||
|
var expected_result = '/^AaBbCc0123 \\.-_$/';
|
||||||
|
|
||||||
|
testReplacingVariable(target, template_var_value, expected_result, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Single-value variable
|
||||||
|
* $host = backend01
|
||||||
|
* $host => /^backend01|backend01$/
|
||||||
|
*/
|
||||||
|
it('should return proper regex for single value', function (done) {
|
||||||
|
var target = '$host';
|
||||||
|
var template_var_value = 'backend01';
|
||||||
|
var expected_result = '/^backend01$/';
|
||||||
|
|
||||||
|
testReplacingVariable(target, template_var_value, expected_result, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Multi-value variable
|
||||||
|
* $host = [backend01, backend02]
|
||||||
|
* $host => /^(backend01|backend01)$/
|
||||||
|
*/
|
||||||
|
it('should return proper regex for multi-value', function (done) {
|
||||||
|
var target = '$host';
|
||||||
|
var template_var_value = ['backend01', 'backend02'];
|
||||||
|
var expected_result = '/^(backend01|backend02)$/';
|
||||||
|
|
||||||
|
testReplacingVariable(target, template_var_value, expected_result, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When invoking metricFindQuery()', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
ctx.ds.replaceTemplateVars = function (str) {
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
ctx.ds.zabbix = {
|
||||||
|
getGroups: function getGroups() {
|
||||||
|
return _q2.default.when([]);
|
||||||
|
},
|
||||||
|
getHosts: function getHosts() {
|
||||||
|
return _q2.default.when([]);
|
||||||
|
},
|
||||||
|
getApps: function getApps() {
|
||||||
|
return _q2.default.when([]);
|
||||||
|
},
|
||||||
|
getItems: function getItems() {
|
||||||
|
return _q2.default.when([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return groups', function (done) {
|
||||||
|
var tests = [{ query: '*', expect: '/.*/' }, { query: '', expect: '' }, { query: 'Backend', expect: 'Backend' }, { query: 'Back*', expect: 'Back*' }];
|
||||||
|
|
||||||
|
var getGroups = _sinon2.default.spy(ctx.ds.zabbix, 'getGroups');
|
||||||
|
var _iteratorNormalCompletion = true;
|
||||||
|
var _didIteratorError = false;
|
||||||
|
var _iteratorError = undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (var _iterator = tests[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||||
|
var test = _step.value;
|
||||||
|
|
||||||
|
ctx.ds.metricFindQuery(test.query);
|
||||||
|
expect(getGroups).to.have.been.calledWith(test.expect);
|
||||||
|
getGroups.reset();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
_didIteratorError = true;
|
||||||
|
_iteratorError = err;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
||||||
|
_iterator.return();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (_didIteratorError) {
|
||||||
|
throw _iteratorError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return hosts', function (done) {
|
||||||
|
var tests = [{ query: '*.*', expect: '/.*/' }, { query: '.', expect: '' }, { query: 'Backend.*', expect: 'Backend' }, { query: 'Back*.', expect: 'Back*' }];
|
||||||
|
|
||||||
|
var getHosts = _sinon2.default.spy(ctx.ds.zabbix, 'getHosts');
|
||||||
|
var _iteratorNormalCompletion2 = true;
|
||||||
|
var _didIteratorError2 = false;
|
||||||
|
var _iteratorError2 = undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (var _iterator2 = tests[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
||||||
|
var test = _step2.value;
|
||||||
|
|
||||||
|
ctx.ds.metricFindQuery(test.query);
|
||||||
|
expect(getHosts).to.have.been.calledWith(test.expect);
|
||||||
|
getHosts.reset();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
_didIteratorError2 = true;
|
||||||
|
_iteratorError2 = err;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (!_iteratorNormalCompletion2 && _iterator2.return) {
|
||||||
|
_iterator2.return();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (_didIteratorError2) {
|
||||||
|
throw _iteratorError2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return applications', function (done) {
|
||||||
|
var tests = [{ query: '*.*.*', expect: ['/.*/', '/.*/'] }, { query: '.*.', expect: ['', '/.*/'] }, { query: 'Backend.backend01.*', expect: ['Backend', 'backend01'] }, { query: 'Back*.*.', expect: ['Back*', '/.*/'] }];
|
||||||
|
|
||||||
|
var getApps = _sinon2.default.spy(ctx.ds.zabbix, 'getApps');
|
||||||
|
var _iteratorNormalCompletion3 = true;
|
||||||
|
var _didIteratorError3 = false;
|
||||||
|
var _iteratorError3 = undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (var _iterator3 = tests[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
|
||||||
|
var test = _step3.value;
|
||||||
|
|
||||||
|
ctx.ds.metricFindQuery(test.query);
|
||||||
|
expect(getApps).to.have.been.calledWith(test.expect[0], test.expect[1]);
|
||||||
|
getApps.reset();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
_didIteratorError3 = true;
|
||||||
|
_iteratorError3 = err;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (!_iteratorNormalCompletion3 && _iterator3.return) {
|
||||||
|
_iterator3.return();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (_didIteratorError3) {
|
||||||
|
throw _iteratorError3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return items', function (done) {
|
||||||
|
var tests = [{ query: '*.*.*.*', expect: ['/.*/', '/.*/', ''] }, { query: '.*.*.*', expect: ['', '/.*/', ''] }, { query: 'Backend.backend01.*.*', expect: ['Backend', 'backend01', ''] }, { query: 'Back*.*.cpu.*', expect: ['Back*', '/.*/', 'cpu'] }];
|
||||||
|
|
||||||
|
var getItems = _sinon2.default.spy(ctx.ds.zabbix, 'getItems');
|
||||||
|
var _iteratorNormalCompletion4 = true;
|
||||||
|
var _didIteratorError4 = false;
|
||||||
|
var _iteratorError4 = undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (var _iterator4 = tests[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
|
||||||
|
var test = _step4.value;
|
||||||
|
|
||||||
|
ctx.ds.metricFindQuery(test.query);
|
||||||
|
expect(getItems).to.have.been.calledWith(test.expect[0], test.expect[1], test.expect[2]);
|
||||||
|
getItems.reset();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
_didIteratorError4 = true;
|
||||||
|
_iteratorError4 = err;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (!_iteratorNormalCompletion4 && _iterator4.return) {
|
||||||
|
_iterator4.return();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (_didIteratorError4) {
|
||||||
|
throw _iteratorError4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should invoke method with proper arguments', function (done) {
|
||||||
|
var query = '*.*';
|
||||||
|
|
||||||
|
var getHosts = _sinon2.default.spy(ctx.ds.zabbix, 'getHosts');
|
||||||
|
ctx.ds.metricFindQuery(query);
|
||||||
|
expect(getHosts).to.have.been.calledWith('/.*/');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
135
dist/test/datasource-zabbix/specs/modules/datemath.js
vendored
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.parse = parse;
|
||||||
|
exports.isValid = isValid;
|
||||||
|
exports.parseDateMath = parseDateMath;
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _moment = require('moment');
|
||||||
|
|
||||||
|
var _moment2 = _interopRequireDefault(_moment);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
var units = ['y', 'M', 'w', 'd', 'h', 'm', 's'];
|
||||||
|
|
||||||
|
function parse(text, roundUp) {
|
||||||
|
if (!text) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (_moment2.default.isMoment(text)) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
if (_lodash2.default.isDate(text)) {
|
||||||
|
return (0, _moment2.default)(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
var time;
|
||||||
|
var mathString = '';
|
||||||
|
var index;
|
||||||
|
var parseString;
|
||||||
|
|
||||||
|
if (text.substring(0, 3) === 'now') {
|
||||||
|
time = (0, _moment2.default)();
|
||||||
|
mathString = text.substring('now'.length);
|
||||||
|
} else {
|
||||||
|
index = text.indexOf('||');
|
||||||
|
if (index === -1) {
|
||||||
|
parseString = text;
|
||||||
|
mathString = ''; // nothing else
|
||||||
|
} else {
|
||||||
|
parseString = text.substring(0, index);
|
||||||
|
mathString = text.substring(index + 2);
|
||||||
|
}
|
||||||
|
// We're going to just require ISO8601 timestamps, k?
|
||||||
|
time = (0, _moment2.default)(parseString, _moment2.default.ISO_8601);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mathString.length) {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseDateMath(mathString, time, roundUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValid(text) {
|
||||||
|
var date = parse(text);
|
||||||
|
if (!date) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_moment2.default.isMoment(date)) {
|
||||||
|
return date.isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseDateMath(mathString, time, roundUp) {
|
||||||
|
var dateTime = time;
|
||||||
|
var i = 0;
|
||||||
|
var len = mathString.length;
|
||||||
|
|
||||||
|
while (i < len) {
|
||||||
|
var c = mathString.charAt(i++);
|
||||||
|
var type;
|
||||||
|
var num;
|
||||||
|
var unit;
|
||||||
|
|
||||||
|
if (c === '/') {
|
||||||
|
type = 0;
|
||||||
|
} else if (c === '+') {
|
||||||
|
type = 1;
|
||||||
|
} else if (c === '-') {
|
||||||
|
type = 2;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(mathString.charAt(i))) {
|
||||||
|
num = 1;
|
||||||
|
} else if (mathString.length === 2) {
|
||||||
|
num = mathString.charAt(i);
|
||||||
|
} else {
|
||||||
|
var numFrom = i;
|
||||||
|
while (!isNaN(mathString.charAt(i))) {
|
||||||
|
i++;
|
||||||
|
if (i > 10) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num = parseInt(mathString.substring(numFrom, i), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 0) {
|
||||||
|
// rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M)
|
||||||
|
if (num !== 1) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unit = mathString.charAt(i++);
|
||||||
|
|
||||||
|
if (!_lodash2.default.includes(units, unit)) {
|
||||||
|
return undefined;
|
||||||
|
} else {
|
||||||
|
if (type === 0) {
|
||||||
|
if (roundUp) {
|
||||||
|
dateTime.endOf(unit);
|
||||||
|
} else {
|
||||||
|
dateTime.startOf(unit);
|
||||||
|
}
|
||||||
|
} else if (type === 1) {
|
||||||
|
dateTime.add(num, unit);
|
||||||
|
} else if (type === 2) {
|
||||||
|
dateTime.subtract(num, unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dateTime;
|
||||||
|
}
|
||||||
66
dist/test/datasource-zabbix/specs/test-main.js
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _prunk = require('prunk');
|
||||||
|
|
||||||
|
var _prunk2 = _interopRequireDefault(_prunk);
|
||||||
|
|
||||||
|
var _jsdom = require('jsdom');
|
||||||
|
|
||||||
|
var _chai = require('chai');
|
||||||
|
|
||||||
|
var _chai2 = _interopRequireDefault(_chai);
|
||||||
|
|
||||||
|
var _sinonChai = require('sinon-chai');
|
||||||
|
|
||||||
|
var _sinonChai2 = _interopRequireDefault(_sinonChai);
|
||||||
|
|
||||||
|
var _datemath = require('./modules/datemath');
|
||||||
|
|
||||||
|
var dateMath = _interopRequireWildcard(_datemath);
|
||||||
|
|
||||||
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
// Mock angular module
|
||||||
|
|
||||||
|
// import sinon from 'sinon';
|
||||||
|
var angularMocks = {
|
||||||
|
module: function module() {
|
||||||
|
return {
|
||||||
|
directive: function directive() {},
|
||||||
|
service: function service() {},
|
||||||
|
factory: function factory() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}; // JSHint options
|
||||||
|
/* globals global: false */
|
||||||
|
|
||||||
|
var datemathMock = {
|
||||||
|
parse: dateMath.parse,
|
||||||
|
parseDateMath: dateMath.parseDateMath,
|
||||||
|
isValid: dateMath.isValid
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock Grafana modules that are not available outside of the core project
|
||||||
|
// Required for loading module.js
|
||||||
|
_prunk2.default.mock('./css/query-editor.css!', 'no css, dude.');
|
||||||
|
_prunk2.default.mock('app/plugins/sdk', {
|
||||||
|
QueryCtrl: null
|
||||||
|
});
|
||||||
|
_prunk2.default.mock('app/core/utils/datemath', datemathMock);
|
||||||
|
_prunk2.default.mock('angular', angularMocks);
|
||||||
|
_prunk2.default.mock('jquery', 'module not found');
|
||||||
|
|
||||||
|
// Setup jsdom
|
||||||
|
// Required for loading angularjs
|
||||||
|
global.document = (0, _jsdom.jsdom)('<html><head><script></script></head><body></body></html>');
|
||||||
|
global.window = global.document.parentWindow;
|
||||||
|
global.navigator = window.navigator = {};
|
||||||
|
global.Node = window.Node;
|
||||||
|
|
||||||
|
// Setup Chai
|
||||||
|
_chai2.default.should();
|
||||||
|
_chai2.default.use(_sinonChai2.default);
|
||||||
|
global.assert = _chai2.default.assert;
|
||||||
|
global.expect = _chai2.default.expect;
|
||||||
151
dist/test/datasource-zabbix/utils.js
vendored
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.regexPattern = undefined;
|
||||||
|
exports.expandItemName = expandItemName;
|
||||||
|
exports.isRegex = isRegex;
|
||||||
|
exports.isTemplateVariable = isTemplateVariable;
|
||||||
|
exports.buildRegex = buildRegex;
|
||||||
|
exports.escapeRegex = escapeRegex;
|
||||||
|
exports.parseInterval = parseInterval;
|
||||||
|
exports.parseTimeShiftInterval = parseTimeShiftInterval;
|
||||||
|
exports.formatAcknowledges = formatAcknowledges;
|
||||||
|
exports.convertToZabbixAPIUrl = convertToZabbixAPIUrl;
|
||||||
|
exports.callOnce = callOnce;
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _moment = require('moment');
|
||||||
|
|
||||||
|
var _moment2 = _interopRequireDefault(_moment);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand Zabbix item name
|
||||||
|
*
|
||||||
|
* @param {string} name item name, ie "CPU $2 time"
|
||||||
|
* @param {string} key item key, ie system.cpu.util[,system,avg1]
|
||||||
|
* @return {string} expanded name, ie "CPU system time"
|
||||||
|
*/
|
||||||
|
function expandItemName(name, key) {
|
||||||
|
|
||||||
|
// extract params from key:
|
||||||
|
// "system.cpu.util[,system,avg1]" --> ["", "system", "avg1"]
|
||||||
|
var key_params = key.substring(key.indexOf('[') + 1, key.lastIndexOf(']')).split(',');
|
||||||
|
|
||||||
|
// replace item parameters
|
||||||
|
for (var i = key_params.length; i >= 1; i--) {
|
||||||
|
name = name.replace('$' + i, key_params[i - 1]);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pattern for testing regex
|
||||||
|
var regexPattern = exports.regexPattern = /^\/(.*)\/([gmi]*)$/m;
|
||||||
|
|
||||||
|
function isRegex(str) {
|
||||||
|
return regexPattern.test(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTemplateVariable(str, templateVariables) {
|
||||||
|
var variablePattern = /^\$\w+/;
|
||||||
|
if (variablePattern.test(str)) {
|
||||||
|
var variables = _lodash2.default.map(templateVariables, function (variable) {
|
||||||
|
return '$' + variable.name;
|
||||||
|
});
|
||||||
|
return _lodash2.default.includes(variables, str);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRegex(str) {
|
||||||
|
var matches = str.match(regexPattern);
|
||||||
|
var pattern = matches[1];
|
||||||
|
var flags = matches[2] !== "" ? matches[2] : undefined;
|
||||||
|
return new RegExp(pattern, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need for template variables replace
|
||||||
|
// From Grafana's templateSrv.js
|
||||||
|
function escapeRegex(value) {
|
||||||
|
return value.replace(/[\\^$*+?.()|[\]{}\/]/g, '\\$&');
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseInterval(interval) {
|
||||||
|
var intervalPattern = /(^[\d]+)(y|M|w|d|h|m|s)/g;
|
||||||
|
var momentInterval = intervalPattern.exec(interval);
|
||||||
|
return _moment2.default.duration(Number(momentInterval[1]), momentInterval[2]).valueOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseTimeShiftInterval(interval) {
|
||||||
|
var intervalPattern = /^([\+\-]*)([\d]+)(y|M|w|d|h|m|s)/g;
|
||||||
|
var momentInterval = intervalPattern.exec(interval);
|
||||||
|
var duration = 0;
|
||||||
|
|
||||||
|
if (momentInterval[1] === '+') {
|
||||||
|
duration = 0 - _moment2.default.duration(Number(momentInterval[2]), momentInterval[3]).valueOf();
|
||||||
|
} else {
|
||||||
|
duration = _moment2.default.duration(Number(momentInterval[2]), momentInterval[3]).valueOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format acknowledges.
|
||||||
|
*
|
||||||
|
* @param {array} acknowledges array of Zabbix acknowledge objects
|
||||||
|
* @return {string} HTML-formatted table
|
||||||
|
*/
|
||||||
|
function formatAcknowledges(acknowledges) {
|
||||||
|
if (acknowledges.length) {
|
||||||
|
var formatted_acknowledges = '<br><br>Acknowledges:<br><table><tr><td><b>Time</b></td>' + '<td><b>User</b></td><td><b>Comments</b></td></tr>';
|
||||||
|
_lodash2.default.each(_lodash2.default.map(acknowledges, function (ack) {
|
||||||
|
var timestamp = _moment2.default.unix(ack.clock);
|
||||||
|
return '<tr><td><i>' + timestamp.format("DD MMM YYYY HH:mm:ss") + '</i></td><td>' + ack.alias + ' (' + ack.name + ' ' + ack.surname + ')' + '</td><td>' + ack.message + '</td></tr>';
|
||||||
|
}), function (ack) {
|
||||||
|
formatted_acknowledges = formatted_acknowledges.concat(ack);
|
||||||
|
});
|
||||||
|
formatted_acknowledges = formatted_acknowledges.concat('</table>');
|
||||||
|
return formatted_acknowledges;
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertToZabbixAPIUrl(url) {
|
||||||
|
var zabbixAPIUrlPattern = /.*api_jsonrpc.php$/;
|
||||||
|
var trimSlashPattern = /(.*?)[\/]*$/;
|
||||||
|
if (url.match(zabbixAPIUrlPattern)) {
|
||||||
|
return url;
|
||||||
|
} else {
|
||||||
|
return url.replace(trimSlashPattern, "$1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap function to prevent multiple calls
|
||||||
|
* when waiting for result.
|
||||||
|
*/
|
||||||
|
function callOnce(func, promiseKeeper) {
|
||||||
|
return function () {
|
||||||
|
if (!promiseKeeper) {
|
||||||
|
promiseKeeper = Promise.resolve(func.apply(this, arguments).then(function (result) {
|
||||||
|
promiseKeeper = null;
|
||||||
|
return result;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return promiseKeeper;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix for backward compatibility with lodash 2.4
|
||||||
|
if (!_lodash2.default.includes) {
|
||||||
|
_lodash2.default.includes = _lodash2.default.contains;
|
||||||
|
}
|
||||||
266
dist/test/datasource-zabbix/zabbix.js
vendored
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||||
|
|
||||||
|
var _angular = require('angular');
|
||||||
|
|
||||||
|
var _angular2 = _interopRequireDefault(_angular);
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _utils = require('./utils');
|
||||||
|
|
||||||
|
var utils = _interopRequireWildcard(_utils);
|
||||||
|
|
||||||
|
require('./zabbixAPI.service.js');
|
||||||
|
|
||||||
|
require('./zabbixCachingProxy.service.js');
|
||||||
|
|
||||||
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
// Use factory() instead service() for multiple data sources support.
|
||||||
|
// Each Zabbix data source instance should initialize its own API instance.
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy) {
|
||||||
|
var Zabbix = function () {
|
||||||
|
function Zabbix(url, username, password, basicAuth, withCredentials, cacheTTL) {
|
||||||
|
_classCallCheck(this, Zabbix);
|
||||||
|
|
||||||
|
// Initialize Zabbix API
|
||||||
|
var ZabbixAPI = zabbixAPIService;
|
||||||
|
this.zabbixAPI = new ZabbixAPI(url, username, password, basicAuth, withCredentials);
|
||||||
|
|
||||||
|
// Initialize caching proxy for requests
|
||||||
|
var cacheOptions = {
|
||||||
|
enabled: true,
|
||||||
|
ttl: cacheTTL
|
||||||
|
};
|
||||||
|
this.cachingProxy = new ZabbixCachingProxy(this.zabbixAPI, cacheOptions);
|
||||||
|
|
||||||
|
// Proxy methods
|
||||||
|
this.getHistory = this.cachingProxy.getHistory.bind(this.cachingProxy);
|
||||||
|
|
||||||
|
this.getTrend = this.zabbixAPI.getTrend.bind(this.zabbixAPI);
|
||||||
|
this.getEvents = this.zabbixAPI.getEvents.bind(this.zabbixAPI);
|
||||||
|
this.getAcknowledges = this.zabbixAPI.getAcknowledges.bind(this.zabbixAPI);
|
||||||
|
this.getITService = this.zabbixAPI.getITService.bind(this.zabbixAPI);
|
||||||
|
this.getSLA = this.zabbixAPI.getSLA.bind(this.zabbixAPI);
|
||||||
|
this.getVersion = this.zabbixAPI.getVersion.bind(this.zabbixAPI);
|
||||||
|
this.login = this.zabbixAPI.login.bind(this.zabbixAPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(Zabbix, [{
|
||||||
|
key: 'getItemsFromTarget',
|
||||||
|
value: function getItemsFromTarget(target, options) {
|
||||||
|
var parts = ['group', 'host', 'application', 'item'];
|
||||||
|
var filters = _lodash2.default.map(parts, function (p) {
|
||||||
|
return target[p].filter;
|
||||||
|
});
|
||||||
|
return this.getItems.apply(this, _toConsumableArray(filters).concat([options]));
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getAllGroups',
|
||||||
|
value: function getAllGroups() {
|
||||||
|
return this.cachingProxy.getGroups();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getGroups',
|
||||||
|
value: function getGroups(groupFilter) {
|
||||||
|
return this.getAllGroups().then(function (groups) {
|
||||||
|
return findByFilter(groups, groupFilter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get list of host belonging to given groups.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'getAllHosts',
|
||||||
|
value: function getAllHosts(groupFilter) {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
return this.getGroups(groupFilter).then(function (groups) {
|
||||||
|
var groupids = _lodash2.default.map(groups, 'groupid');
|
||||||
|
return _this.cachingProxy.getHosts(groupids);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getHosts',
|
||||||
|
value: function getHosts(groupFilter, hostFilter) {
|
||||||
|
return this.getAllHosts(groupFilter).then(function (hosts) {
|
||||||
|
return findByFilter(hosts, hostFilter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get list of applications belonging to given groups and hosts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'getAllApps',
|
||||||
|
value: function getAllApps(groupFilter, hostFilter) {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
return this.getHosts(groupFilter, hostFilter).then(function (hosts) {
|
||||||
|
var hostids = _lodash2.default.map(hosts, 'hostid');
|
||||||
|
return _this2.cachingProxy.getApps(hostids);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getApps',
|
||||||
|
value: function getApps(groupFilter, hostFilter, appFilter) {
|
||||||
|
var _this3 = this;
|
||||||
|
|
||||||
|
return this.getHosts(groupFilter, hostFilter).then(function (hosts) {
|
||||||
|
var hostids = _lodash2.default.map(hosts, 'hostid');
|
||||||
|
if (appFilter) {
|
||||||
|
return _this3.cachingProxy.getApps(hostids).then(function (apps) {
|
||||||
|
return filterByQuery(apps, appFilter);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
appFilterEmpty: true,
|
||||||
|
hostids: hostids
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getAllItems',
|
||||||
|
value: function getAllItems(groupFilter, hostFilter, appFilter) {
|
||||||
|
var _this4 = this;
|
||||||
|
|
||||||
|
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
||||||
|
|
||||||
|
return this.getApps(groupFilter, hostFilter, appFilter).then(function (apps) {
|
||||||
|
if (apps.appFilterEmpty) {
|
||||||
|
return _this4.cachingProxy.getItems(apps.hostids, undefined, options.itemtype);
|
||||||
|
} else {
|
||||||
|
var appids = _lodash2.default.map(apps, 'applicationid');
|
||||||
|
return _this4.cachingProxy.getItems(undefined, appids, options.itemtype);
|
||||||
|
}
|
||||||
|
}).then(function (items) {
|
||||||
|
if (!options.showDisabledItems) {
|
||||||
|
items = _lodash2.default.filter(items, { 'status': '0' });
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getItems',
|
||||||
|
value: function getItems(groupFilter, hostFilter, appFilter, itemFilter) {
|
||||||
|
var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
|
||||||
|
|
||||||
|
return this.getAllItems(groupFilter, hostFilter, appFilter, options).then(function (items) {
|
||||||
|
return filterByQuery(items, itemFilter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build query - convert target filters to array of Zabbix items
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'getTriggers',
|
||||||
|
value: function getTriggers(groupFilter, hostFilter, appFilter, showTriggers) {
|
||||||
|
var _this5 = this;
|
||||||
|
|
||||||
|
var promises = [this.getGroups(groupFilter), this.getHosts(groupFilter, hostFilter), this.getApps(groupFilter, hostFilter, appFilter)];
|
||||||
|
|
||||||
|
return Promise.all(promises).then(function (results) {
|
||||||
|
var filteredGroups = results[0];
|
||||||
|
var filteredHosts = results[1];
|
||||||
|
var filteredApps = results[2];
|
||||||
|
var query = {};
|
||||||
|
|
||||||
|
if (appFilter) {
|
||||||
|
query.applicationids = _lodash2.default.flatten(_lodash2.default.map(filteredApps, 'applicationid'));
|
||||||
|
}
|
||||||
|
if (hostFilter) {
|
||||||
|
query.hostids = _lodash2.default.map(filteredHosts, 'hostid');
|
||||||
|
}
|
||||||
|
if (groupFilter) {
|
||||||
|
query.groupids = _lodash2.default.map(filteredGroups, 'groupid');
|
||||||
|
}
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}).then(function (query) {
|
||||||
|
return _this5.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return Zabbix;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return Zabbix;
|
||||||
|
}
|
||||||
|
|
||||||
|
_angular2.default.module('grafana.services').factory('Zabbix', ZabbixFactory);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find group, host, app or item by given name.
|
||||||
|
* @param list list of groups, apps or other
|
||||||
|
* @param name visible name
|
||||||
|
* @return array with finded element or undefined
|
||||||
|
*/
|
||||||
|
function findByName(list, name) {
|
||||||
|
var finded = _lodash2.default.find(list, { 'name': name });
|
||||||
|
if (finded) {
|
||||||
|
return [finded];
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = _lodash2.default.filter(list, { 'name': name });
|
||||||
|
if (finded) {
|
||||||
|
return finded;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterByRegex(list, regex) {
|
||||||
|
var filterPattern = utils.buildRegex(regex);
|
||||||
|
return _lodash2.default.filter(list, function (zbx_obj) {
|
||||||
|
return filterPattern.test(zbx_obj.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function findByFilter(list, filter) {
|
||||||
|
if (utils.isRegex(filter)) {
|
||||||
|
return filterByRegex(list, filter);
|
||||||
|
} else {
|
||||||
|
return findByName(list, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterByQuery(list, filter) {
|
||||||
|
if (utils.isRegex(filter)) {
|
||||||
|
return filterByRegex(list, filter);
|
||||||
|
} else {
|
||||||
|
return filterByName(list, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
436
dist/test/datasource-zabbix/zabbixAPI.service.js
vendored
Normal file
@@ -0,0 +1,436 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||||
|
|
||||||
|
var _angular = require('angular');
|
||||||
|
|
||||||
|
var _angular2 = _interopRequireDefault(_angular);
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _utils = require('./utils');
|
||||||
|
|
||||||
|
var utils = _interopRequireWildcard(_utils);
|
||||||
|
|
||||||
|
require('./zabbixAPICore.service');
|
||||||
|
|
||||||
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function ZabbixAPIServiceFactory(alertSrv, zabbixAPICoreService) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zabbix API Wrapper.
|
||||||
|
* Creates Zabbix API instance with given parameters (url, credentials and other).
|
||||||
|
* Wraps API calls and provides high-level methods.
|
||||||
|
*/
|
||||||
|
var ZabbixAPI = function () {
|
||||||
|
function ZabbixAPI(api_url, username, password, basicAuth, withCredentials) {
|
||||||
|
_classCallCheck(this, ZabbixAPI);
|
||||||
|
|
||||||
|
this.url = api_url;
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
this.auth = "";
|
||||||
|
|
||||||
|
this.requestOptions = {
|
||||||
|
basicAuth: basicAuth,
|
||||||
|
withCredentials: withCredentials
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loginPromise = null;
|
||||||
|
this.loginErrorCount = 0;
|
||||||
|
this.maxLoginAttempts = 3;
|
||||||
|
|
||||||
|
this.alertSrv = alertSrv;
|
||||||
|
this.zabbixAPICore = zabbixAPICoreService;
|
||||||
|
|
||||||
|
this.getTrend = this.getTrend_ZBXNEXT1193;
|
||||||
|
//getTrend = getTrend_30;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// Core method wrappers //
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
_createClass(ZabbixAPI, [{
|
||||||
|
key: 'request',
|
||||||
|
value: function request(method, params) {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
return this.zabbixAPICore.request(this.url, method, params, this.requestOptions, this.auth).catch(function (error) {
|
||||||
|
if (isNotAuthorized(error.data)) {
|
||||||
|
// Handle auth errors
|
||||||
|
_this.loginErrorCount++;
|
||||||
|
if (_this.loginErrorCount > _this.maxLoginAttempts) {
|
||||||
|
_this.loginErrorCount = 0;
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return _this.loginOnce().then(function () {
|
||||||
|
return _this.request(method, params);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle API errors
|
||||||
|
var message = error.data ? error.data : error.statusText;
|
||||||
|
_this.alertAPIError(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'alertAPIError',
|
||||||
|
value: function alertAPIError(message) {
|
||||||
|
var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5000;
|
||||||
|
|
||||||
|
this.alertSrv.set("Zabbix API Error", message, 'error', timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When API unauthenticated or auth token expired each request produce login()
|
||||||
|
* call. But auth token is common to all requests. This function wraps login() method
|
||||||
|
* and call it once. If login() already called just wait for it (return its promise).
|
||||||
|
* @return login promise
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'loginOnce',
|
||||||
|
value: function loginOnce() {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
if (!this.loginPromise) {
|
||||||
|
this.loginPromise = Promise.resolve(this.login().then(function (auth) {
|
||||||
|
_this2.auth = auth;
|
||||||
|
_this2.loginPromise = null;
|
||||||
|
return auth;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return this.loginPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get authentication token.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'login',
|
||||||
|
value: function login() {
|
||||||
|
return this.zabbixAPICore.login(this.url, this.username, this.password, this.requestOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Zabbix API version
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'getVersion',
|
||||||
|
value: function getVersion() {
|
||||||
|
return this.zabbixAPICore.getVersion(this.url, this.requestOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Zabbix API method wrappers //
|
||||||
|
////////////////////////////////
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'acknowledgeEvent',
|
||||||
|
value: function acknowledgeEvent(eventid, message) {
|
||||||
|
var params = {
|
||||||
|
eventids: eventid,
|
||||||
|
message: message
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.request('event.acknowledge', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getGroups',
|
||||||
|
value: function getGroups() {
|
||||||
|
var params = {
|
||||||
|
output: ['name'],
|
||||||
|
sortfield: 'name',
|
||||||
|
real_hosts: true
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.request('hostgroup.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getHosts',
|
||||||
|
value: function getHosts(groupids) {
|
||||||
|
var params = {
|
||||||
|
output: ['name', 'host'],
|
||||||
|
sortfield: 'name'
|
||||||
|
};
|
||||||
|
if (groupids) {
|
||||||
|
params.groupids = groupids;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.request('host.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getApps',
|
||||||
|
value: function getApps(hostids) {
|
||||||
|
var params = {
|
||||||
|
output: ['applicationid', 'name'],
|
||||||
|
hostids: hostids
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.request('application.get', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Zabbix items
|
||||||
|
* @param {[type]} hostids host ids
|
||||||
|
* @param {[type]} appids application ids
|
||||||
|
* @param {String} itemtype 'num' or 'text'
|
||||||
|
* @return {[type]} array of items
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'getItems',
|
||||||
|
value: function getItems(hostids, appids, itemtype) {
|
||||||
|
var params = {
|
||||||
|
output: ['name', 'key_', 'value_type', 'hostid', 'status', 'state'],
|
||||||
|
sortfield: 'name',
|
||||||
|
webitems: true,
|
||||||
|
filter: {},
|
||||||
|
selectHosts: ['hostid', 'name']
|
||||||
|
};
|
||||||
|
if (hostids) {
|
||||||
|
params.hostids = hostids;
|
||||||
|
}
|
||||||
|
if (appids) {
|
||||||
|
params.applicationids = appids;
|
||||||
|
}
|
||||||
|
if (itemtype === 'num') {
|
||||||
|
// Return only numeric metrics
|
||||||
|
params.filter.value_type = [0, 3];
|
||||||
|
}
|
||||||
|
if (itemtype === 'text') {
|
||||||
|
// Return only text metrics
|
||||||
|
params.filter.value_type = [1, 2, 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.request('item.get', params).then(expandItems);
|
||||||
|
|
||||||
|
function expandItems(items) {
|
||||||
|
items.forEach(function (item) {
|
||||||
|
item.item = item.name;
|
||||||
|
item.name = utils.expandItemName(item.item, item.key_);
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getLastValue',
|
||||||
|
value: function getLastValue(itemid) {
|
||||||
|
var params = {
|
||||||
|
output: ['lastvalue'],
|
||||||
|
itemids: itemid
|
||||||
|
};
|
||||||
|
return this.request('item.get', params).then(function (items) {
|
||||||
|
return items.length ? items[0].lastvalue : null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform history query from Zabbix API
|
||||||
|
*
|
||||||
|
* @param {Array} items Array of Zabbix item objects
|
||||||
|
* @param {Number} timeFrom Time in seconds
|
||||||
|
* @param {Number} timeTill Time in seconds
|
||||||
|
* @return {Array} Array of Zabbix history objects
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'getHistory',
|
||||||
|
value: function getHistory(items, timeFrom, timeTill) {
|
||||||
|
var _this3 = this;
|
||||||
|
|
||||||
|
// Group items by value type and perform request for each value type
|
||||||
|
var grouped_items = _lodash2.default.groupBy(items, 'value_type');
|
||||||
|
var promises = _lodash2.default.map(grouped_items, function (items, value_type) {
|
||||||
|
var itemids = _lodash2.default.map(items, 'itemid');
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
history: value_type,
|
||||||
|
itemids: itemids,
|
||||||
|
sortfield: 'clock',
|
||||||
|
sortorder: 'ASC',
|
||||||
|
time_from: timeFrom
|
||||||
|
};
|
||||||
|
|
||||||
|
// Relative queries (e.g. last hour) don't include an end time
|
||||||
|
if (timeTill) {
|
||||||
|
params.time_till = timeTill;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _this3.request('history.get', params);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises).then(_lodash2.default.flatten);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform trends query from Zabbix API
|
||||||
|
* Use trends api extension from ZBXNEXT-1193 patch.
|
||||||
|
*
|
||||||
|
* @param {Array} items Array of Zabbix item objects
|
||||||
|
* @param {Number} time_from Time in seconds
|
||||||
|
* @param {Number} time_till Time in seconds
|
||||||
|
* @return {Array} Array of Zabbix trend objects
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'getTrend_ZBXNEXT1193',
|
||||||
|
value: function getTrend_ZBXNEXT1193(items, timeFrom, timeTill) {
|
||||||
|
var _this4 = this;
|
||||||
|
|
||||||
|
// Group items by value type and perform request for each value type
|
||||||
|
var grouped_items = _lodash2.default.groupBy(items, 'value_type');
|
||||||
|
var promises = _lodash2.default.map(grouped_items, function (items, value_type) {
|
||||||
|
var itemids = _lodash2.default.map(items, 'itemid');
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
trend: value_type,
|
||||||
|
itemids: itemids,
|
||||||
|
sortfield: 'clock',
|
||||||
|
sortorder: 'ASC',
|
||||||
|
time_from: timeFrom
|
||||||
|
};
|
||||||
|
|
||||||
|
// Relative queries (e.g. last hour) don't include an end time
|
||||||
|
if (timeTill) {
|
||||||
|
params.time_till = timeTill;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _this4.request('trend.get', params);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises).then(_lodash2.default.flatten);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getTrend_30',
|
||||||
|
value: function getTrend_30(items, time_from, time_till, value_type) {
|
||||||
|
var self = this;
|
||||||
|
var itemids = _lodash2.default.map(items, 'itemid');
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
output: ["itemid", "clock", value_type],
|
||||||
|
itemids: itemids,
|
||||||
|
time_from: time_from
|
||||||
|
};
|
||||||
|
|
||||||
|
// Relative queries (e.g. last hour) don't include an end time
|
||||||
|
if (time_till) {
|
||||||
|
params.time_till = time_till;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.request('trend.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getITService',
|
||||||
|
value: function getITService(serviceids) {
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
serviceids: serviceids
|
||||||
|
};
|
||||||
|
return this.request('service.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getSLA',
|
||||||
|
value: function getSLA(serviceids, timeFrom, timeTo) {
|
||||||
|
var params = {
|
||||||
|
serviceids: serviceids,
|
||||||
|
intervals: [{
|
||||||
|
from: timeFrom,
|
||||||
|
to: timeTo
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
return this.request('service.getsla', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getTriggers',
|
||||||
|
value: function getTriggers(groupids, hostids, applicationids, showTriggers, timeFrom, timeTo) {
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
groupids: groupids,
|
||||||
|
hostids: hostids,
|
||||||
|
applicationids: applicationids,
|
||||||
|
expandDescription: true,
|
||||||
|
expandData: true,
|
||||||
|
expandComment: true,
|
||||||
|
monitored: true,
|
||||||
|
skipDependent: true,
|
||||||
|
//only_true: true,
|
||||||
|
filter: {
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
selectGroups: ['name'],
|
||||||
|
selectHosts: ['name', 'host'],
|
||||||
|
selectItems: ['name', 'key_', 'lastvalue'],
|
||||||
|
selectLastEvent: 'extend'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (showTriggers) {
|
||||||
|
params.filter.value = showTriggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeFrom || timeTo) {
|
||||||
|
params.lastChangeSince = timeFrom;
|
||||||
|
params.lastChangeTill = timeTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.request('trigger.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getEvents',
|
||||||
|
value: function getEvents(objectids, timeFrom, timeTo, showEvents) {
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
time_from: timeFrom,
|
||||||
|
time_till: timeTo,
|
||||||
|
objectids: objectids,
|
||||||
|
select_acknowledges: 'extend',
|
||||||
|
selectHosts: 'extend',
|
||||||
|
value: showEvents
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.request('event.get', params);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getAcknowledges',
|
||||||
|
value: function getAcknowledges(eventids) {
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
eventids: eventids,
|
||||||
|
preservekeys: true,
|
||||||
|
select_acknowledges: 'extend',
|
||||||
|
sortfield: 'clock',
|
||||||
|
sortorder: 'DESC'
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.request('event.get', params).then(function (events) {
|
||||||
|
return _lodash2.default.filter(events, function (event) {
|
||||||
|
return event.acknowledges.length;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixAPI;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return ZabbixAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNotAuthorized(message) {
|
||||||
|
return message === "Session terminated, re-login, please." || message === "Not authorised." || message === "Not authorized.";
|
||||||
|
}
|
||||||
|
|
||||||
|
_angular2.default.module('grafana.services').factory('zabbixAPIService', ZabbixAPIServiceFactory);
|
||||||
142
dist/test/datasource-zabbix/zabbixAPICore.service.js
vendored
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.ZabbixAPIError = undefined;
|
||||||
|
|
||||||
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
|
||||||
|
* General Zabbix API methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
var _angular = require('angular');
|
||||||
|
|
||||||
|
var _angular2 = _interopRequireDefault(_angular);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
var ZabbixAPICoreService = function () {
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function ZabbixAPICoreService(backendSrv) {
|
||||||
|
_classCallCheck(this, ZabbixAPICoreService);
|
||||||
|
|
||||||
|
this.backendSrv = backendSrv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request data from Zabbix API
|
||||||
|
* @return {object} response.result
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
_createClass(ZabbixAPICoreService, [{
|
||||||
|
key: 'request',
|
||||||
|
value: function request(api_url, method, params, options, auth) {
|
||||||
|
var requestData = {
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method: method,
|
||||||
|
params: params,
|
||||||
|
id: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auth === "") {
|
||||||
|
// Reject immediately if not authenticated
|
||||||
|
return Promise.reject(new ZabbixAPIError({ data: "Not authorised." }));
|
||||||
|
} else if (auth) {
|
||||||
|
// Set auth parameter only if it needed
|
||||||
|
requestData.auth = auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
url: api_url,
|
||||||
|
data: requestData,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set request options for basic auth
|
||||||
|
if (options.basicAuth || options.withCredentials) {
|
||||||
|
requestOptions.withCredentials = true;
|
||||||
|
}
|
||||||
|
if (options.basicAuth) {
|
||||||
|
requestOptions.headers.Authorization = options.basicAuth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.datasourceRequest(requestOptions);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'datasourceRequest',
|
||||||
|
value: function datasourceRequest(requestOptions) {
|
||||||
|
return this.backendSrv.datasourceRequest(requestOptions).then(function (response) {
|
||||||
|
if (!response.data) {
|
||||||
|
return Promise.reject(new ZabbixAPIError({ data: "General Error, no data" }));
|
||||||
|
} else if (response.data.error) {
|
||||||
|
|
||||||
|
// Handle Zabbix API errors
|
||||||
|
return Promise.reject(new ZabbixAPIError(response.data.error));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
return response.data.result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get authentication token.
|
||||||
|
* @return {string} auth token
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'login',
|
||||||
|
value: function login(api_url, username, password, options) {
|
||||||
|
var params = {
|
||||||
|
user: username,
|
||||||
|
password: password
|
||||||
|
};
|
||||||
|
return this.request(api_url, 'user.login', params, options, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Zabbix API version
|
||||||
|
* Matches the version of Zabbix starting from Zabbix 2.0.4
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'getVersion',
|
||||||
|
value: function getVersion(api_url, options) {
|
||||||
|
return this.request(api_url, 'apiinfo.version', [], options);
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixAPICoreService;
|
||||||
|
}();
|
||||||
|
|
||||||
|
// Define zabbix API exception type
|
||||||
|
|
||||||
|
|
||||||
|
var ZabbixAPIError = exports.ZabbixAPIError = function () {
|
||||||
|
function ZabbixAPIError(error) {
|
||||||
|
_classCallCheck(this, ZabbixAPIError);
|
||||||
|
|
||||||
|
this.code = error.code;
|
||||||
|
this.name = error.data;
|
||||||
|
this.message = error.data;
|
||||||
|
this.data = error.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(ZabbixAPIError, [{
|
||||||
|
key: 'toString',
|
||||||
|
value: function toString() {
|
||||||
|
return this.name + ": " + this.message;
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixAPIError;
|
||||||
|
}();
|
||||||
|
|
||||||
|
_angular2.default.module('grafana.services').service('zabbixAPICoreService', ZabbixAPICoreService);
|
||||||
215
dist/test/datasource-zabbix/zabbixCachingProxy.service.js
vendored
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||||
|
|
||||||
|
var _angular = require('angular');
|
||||||
|
|
||||||
|
var _angular2 = _interopRequireDefault(_angular);
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
// Use factory() instead service() for multiple datasources support.
|
||||||
|
// Each datasource instance must initialize its own cache.
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function ZabbixCachingProxyFactory() {
|
||||||
|
var ZabbixCachingProxy = function () {
|
||||||
|
function ZabbixCachingProxy(zabbixAPI, cacheOptions) {
|
||||||
|
_classCallCheck(this, ZabbixCachingProxy);
|
||||||
|
|
||||||
|
this.zabbixAPI = zabbixAPI;
|
||||||
|
this.cacheEnabled = cacheOptions.enabled;
|
||||||
|
this.ttl = cacheOptions.ttl || 600000; // 10 minutes by default
|
||||||
|
|
||||||
|
// Internal objects for data storing
|
||||||
|
this.cache = {
|
||||||
|
groups: {},
|
||||||
|
hosts: {},
|
||||||
|
applications: {},
|
||||||
|
items: {},
|
||||||
|
history: {},
|
||||||
|
trends: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.historyPromises = {};
|
||||||
|
|
||||||
|
// Don't run duplicated history requests
|
||||||
|
this.getHistory = callAPIRequestOnce(_lodash2.default.bind(this.zabbixAPI.getHistory, this.zabbixAPI), this.historyPromises, getHistoryRequestHash);
|
||||||
|
|
||||||
|
// Don't run duplicated requests
|
||||||
|
this.groupPromises = {};
|
||||||
|
this.getGroupsOnce = callAPIRequestOnce(_lodash2.default.bind(this.zabbixAPI.getGroups, this.zabbixAPI), this.groupPromises, getRequestHash);
|
||||||
|
|
||||||
|
this.hostPromises = {};
|
||||||
|
this.getHostsOnce = callAPIRequestOnce(_lodash2.default.bind(this.zabbixAPI.getHosts, this.zabbixAPI), this.hostPromises, getRequestHash);
|
||||||
|
|
||||||
|
this.appPromises = {};
|
||||||
|
this.getAppsOnce = callAPIRequestOnce(_lodash2.default.bind(this.zabbixAPI.getApps, this.zabbixAPI), this.appPromises, getRequestHash);
|
||||||
|
|
||||||
|
this.itemPromises = {};
|
||||||
|
this.getItemsOnce = callAPIRequestOnce(_lodash2.default.bind(this.zabbixAPI.getItems, this.zabbixAPI), this.itemPromises, getRequestHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(ZabbixCachingProxy, [{
|
||||||
|
key: 'isExpired',
|
||||||
|
value: function isExpired(cacheObject) {
|
||||||
|
if (cacheObject) {
|
||||||
|
var object_age = Date.now() - cacheObject.timestamp;
|
||||||
|
return !(cacheObject.timestamp && object_age < this.ttl);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that result is present in cache and up to date
|
||||||
|
* or send request to API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'proxyRequest',
|
||||||
|
value: function proxyRequest(request, params, cacheObject) {
|
||||||
|
var hash = getRequestHash(params);
|
||||||
|
if (this.cacheEnabled && !this.isExpired(cacheObject[hash])) {
|
||||||
|
return Promise.resolve(cacheObject[hash].value);
|
||||||
|
} else {
|
||||||
|
return request.apply(undefined, _toConsumableArray(params)).then(function (result) {
|
||||||
|
cacheObject[hash] = {
|
||||||
|
value: result,
|
||||||
|
timestamp: Date.now()
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getGroups',
|
||||||
|
value: function getGroups() {
|
||||||
|
return this.proxyRequest(this.getGroupsOnce, [], this.cache.groups);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getHosts',
|
||||||
|
value: function getHosts(groupids) {
|
||||||
|
return this.proxyRequest(this.getHostsOnce, [groupids], this.cache.hosts);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getApps',
|
||||||
|
value: function getApps(hostids) {
|
||||||
|
return this.proxyRequest(this.getAppsOnce, [hostids], this.cache.applications);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getItems',
|
||||||
|
value: function getItems(hostids, appids, itemtype) {
|
||||||
|
var params = [hostids, appids, itemtype];
|
||||||
|
return this.proxyRequest(this.getItemsOnce, params, this.cache.items);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getHistoryFromCache',
|
||||||
|
value: function getHistoryFromCache(items, time_from, time_till) {
|
||||||
|
var historyStorage = this.cache.history;
|
||||||
|
var full_history;
|
||||||
|
var expired = _lodash2.default.filter(_lodash2.default.keyBy(items, 'itemid'), function (item, itemid) {
|
||||||
|
return !historyStorage[itemid];
|
||||||
|
});
|
||||||
|
if (expired.length) {
|
||||||
|
return this.zabbixAPI.getHistory(expired, time_from, time_till).then(function (history) {
|
||||||
|
var grouped_history = _lodash2.default.groupBy(history, 'itemid');
|
||||||
|
_lodash2.default.forEach(expired, function (item) {
|
||||||
|
var itemid = item.itemid;
|
||||||
|
historyStorage[itemid] = item;
|
||||||
|
historyStorage[itemid].time_from = time_from;
|
||||||
|
historyStorage[itemid].time_till = time_till;
|
||||||
|
historyStorage[itemid].history = grouped_history[itemid];
|
||||||
|
});
|
||||||
|
full_history = _lodash2.default.map(items, function (item) {
|
||||||
|
return historyStorage[item.itemid].history;
|
||||||
|
});
|
||||||
|
return _lodash2.default.flatten(full_history, true);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
full_history = _lodash2.default.map(items, function (item) {
|
||||||
|
return historyStorage[item.itemid].history;
|
||||||
|
});
|
||||||
|
return Promise.resolve(_lodash2.default.flatten(full_history, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getHistoryFromAPI',
|
||||||
|
value: function getHistoryFromAPI(items, time_from, time_till) {
|
||||||
|
return this.zabbixAPI.getHistory(items, time_from, time_till);
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ZabbixCachingProxy;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return ZabbixCachingProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
_angular2.default.module('grafana.services').factory('ZabbixCachingProxy', ZabbixCachingProxyFactory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap zabbix API request to prevent multiple calls
|
||||||
|
* with same params when waiting for result.
|
||||||
|
*/
|
||||||
|
function callAPIRequestOnce(func, promiseKeeper, argsHashFunc) {
|
||||||
|
return function () {
|
||||||
|
var hash = argsHashFunc(arguments);
|
||||||
|
if (!promiseKeeper[hash]) {
|
||||||
|
promiseKeeper[hash] = Promise.resolve(func.apply(this, arguments).then(function (result) {
|
||||||
|
promiseKeeper[hash] = null;
|
||||||
|
return result;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return promiseKeeper[hash];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRequestHash(args) {
|
||||||
|
var requestStamp = _lodash2.default.map(args, function (arg) {
|
||||||
|
if (arg === undefined) {
|
||||||
|
return 'undefined';
|
||||||
|
} else {
|
||||||
|
if (_lodash2.default.isArray(arg)) {
|
||||||
|
return arg.sort().toString();
|
||||||
|
} else {
|
||||||
|
return arg.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).join();
|
||||||
|
return requestStamp.getHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHistoryRequestHash(args) {
|
||||||
|
var itemids = _lodash2.default.map(args[0], 'itemid');
|
||||||
|
var stamp = itemids.join() + args[1] + args[2];
|
||||||
|
return stamp.getHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
String.prototype.getHash = function () {
|
||||||
|
var hash = 0,
|
||||||
|
i,
|
||||||
|
chr,
|
||||||
|
len;
|
||||||
|
if (this.length !== 0) {
|
||||||
|
for (i = 0, len = this.length; i < len; i++) {
|
||||||
|
chr = this.charCodeAt(i);
|
||||||
|
hash = (hash << 5) - hash + chr;
|
||||||
|
hash |= 0; // Convert to 32bit integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fix for backward compatibility with lodash 2.4
|
||||||
|
if (!_lodash2.default.keyBy) {
|
||||||
|
_lodash2.default.keyBy = _lodash2.default.indexBy;
|
||||||
|
}
|
||||||
10
dist/test/module.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.ConfigCtrl = undefined;
|
||||||
|
|
||||||
|
var _config = require('./components/config');
|
||||||
|
|
||||||
|
exports.ConfigCtrl = _config.ZabbixAppConfigCtrl;
|
||||||
122
dist/test/panel-triggers/ack-tooltip.directive.js
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _angular = require('angular');
|
||||||
|
|
||||||
|
var _angular2 = _interopRequireDefault(_angular);
|
||||||
|
|
||||||
|
var _jquery = require('jquery');
|
||||||
|
|
||||||
|
var _jquery2 = _interopRequireDefault(_jquery);
|
||||||
|
|
||||||
|
var _tetherDrop = require('tether-drop');
|
||||||
|
|
||||||
|
var _tetherDrop2 = _interopRequireDefault(_tetherDrop);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
_angular2.default.module('grafana.directives').directive('ackTooltip', function ($sanitize, $compile) {
|
||||||
|
var buttonTemplate = '<a bs-tooltip="\'Acknowledges ({{trigger.acknowledges.length}})\'"' + '<i ng-class="' + "{'fa fa-comments': trigger.acknowledges.length, " + "'fa fa-comments-o': !trigger.acknowledges.length, " + '}"></i></a>';
|
||||||
|
|
||||||
|
return {
|
||||||
|
scope: {
|
||||||
|
ack: "=",
|
||||||
|
trigger: "=",
|
||||||
|
onAck: "=",
|
||||||
|
context: "="
|
||||||
|
},
|
||||||
|
link: function link(scope, element) {
|
||||||
|
var acknowledges = scope.ack;
|
||||||
|
var $button = (0, _jquery2.default)(buttonTemplate);
|
||||||
|
$button.appendTo(element);
|
||||||
|
|
||||||
|
$button.click(function () {
|
||||||
|
var tooltip = '<div>';
|
||||||
|
|
||||||
|
if (acknowledges && acknowledges.length) {
|
||||||
|
tooltip += '<table class="table"><thead><tr>' + '<th class="ack-time">Time</th>' + '<th class="ack-user">User</th>' + '<th class="ack-comments">Comments</th>' + '</tr></thead><tbody>';
|
||||||
|
var _iteratorNormalCompletion = true;
|
||||||
|
var _didIteratorError = false;
|
||||||
|
var _iteratorError = undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (var _iterator = acknowledges[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||||
|
var ack = _step.value;
|
||||||
|
|
||||||
|
tooltip += '<tr><td>' + ack.time + '</td>' + '<td>' + ack.user + '</td>' + '<td>' + ack.message + '</td></tr>';
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
_didIteratorError = true;
|
||||||
|
_iteratorError = err;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
||||||
|
_iterator.return();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (_didIteratorError) {
|
||||||
|
throw _iteratorError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltip += '</tbody></table>';
|
||||||
|
} else {
|
||||||
|
tooltip += 'Add acknowledge';
|
||||||
|
}
|
||||||
|
|
||||||
|
var addAckButtonTemplate = '<div class="ack-add-button">' + '<button id="add-acknowledge-btn"' + 'class="btn btn-mini btn-inverse gf-form-button">' + '<i class="fa fa-plus"></i>' + '</button></div>';
|
||||||
|
tooltip += addAckButtonTemplate;
|
||||||
|
tooltip += '</div>';
|
||||||
|
|
||||||
|
var drop = new _tetherDrop2.default({
|
||||||
|
target: element[0],
|
||||||
|
content: tooltip,
|
||||||
|
position: "bottom left",
|
||||||
|
classes: 'drop-popover ack-tooltip',
|
||||||
|
openOn: 'hover',
|
||||||
|
hoverCloseDelay: 500,
|
||||||
|
tetherOptions: {
|
||||||
|
constraints: [{ to: 'window', pin: true, attachment: "both" }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
drop.open();
|
||||||
|
drop.on('close', closeDrop);
|
||||||
|
|
||||||
|
(0, _jquery2.default)('#add-acknowledge-btn').on('click', onAddAckButtonClick);
|
||||||
|
|
||||||
|
function onAddAckButtonClick() {
|
||||||
|
var inputTemplate = '<div class="ack-input-group">' + '<input type="text" id="ack-message">' + '<button id="send-ack-button"' + 'class="btn btn-mini btn-inverse gf-form-button">' + 'Acknowledge </button>' + '<button id="cancel-ack-button"' + 'class="btn btn-mini btn-inverse gf-form-button">' + 'Cancel' + '</button></input></div>';
|
||||||
|
|
||||||
|
var $input = (0, _jquery2.default)(inputTemplate);
|
||||||
|
var $addAckButton = (0, _jquery2.default)('.ack-tooltip .ack-add-button');
|
||||||
|
$addAckButton.replaceWith($input);
|
||||||
|
(0, _jquery2.default)('.ack-tooltip #cancel-ack-button').on('click', onAckCancelButtonClick);
|
||||||
|
(0, _jquery2.default)('.ack-tooltip #send-ack-button').on('click', onAckSendlButtonClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAckCancelButtonClick() {
|
||||||
|
(0, _jquery2.default)('.ack-tooltip .ack-input-group').replaceWith(addAckButtonTemplate);
|
||||||
|
(0, _jquery2.default)('#add-acknowledge-btn').on('click', onAddAckButtonClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAckSendlButtonClick() {
|
||||||
|
var message = (0, _jquery2.default)('.ack-tooltip #ack-message')[0].value;
|
||||||
|
var onAck = scope.onAck.bind(scope.context);
|
||||||
|
onAck(scope.trigger, message).then(function () {
|
||||||
|
closeDrop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDrop() {
|
||||||
|
setTimeout(function () {
|
||||||
|
drop.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$compile(element.contents())(scope);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
225
dist/test/panel-triggers/editor.js
vendored
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
|
||||||
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
|
||||||
|
* Grafana-Zabbix
|
||||||
|
* Zabbix plugin for Grafana.
|
||||||
|
* http://github.com/alexanderzobnin/grafana-zabbix
|
||||||
|
*
|
||||||
|
* Trigger panel.
|
||||||
|
* This feature sponsored by CORE IT
|
||||||
|
* http://www.coreit.fr
|
||||||
|
*
|
||||||
|
* Copyright 2015 Alexander Zobnin alexanderzobnin@gmail.com
|
||||||
|
* Licensed under the Apache License, Version 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.triggerPanelEditor = triggerPanelEditor;
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _utils = require('../datasource-zabbix/utils');
|
||||||
|
|
||||||
|
var utils = _interopRequireWildcard(_utils);
|
||||||
|
|
||||||
|
require('../datasource-zabbix/css/query-editor.css!');
|
||||||
|
|
||||||
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
var TriggerPanelEditorCtrl = function () {
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function TriggerPanelEditorCtrl($scope, $rootScope, uiSegmentSrv, datasourceSrv, templateSrv, popoverSrv) {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
_classCallCheck(this, TriggerPanelEditorCtrl);
|
||||||
|
|
||||||
|
$scope.editor = this;
|
||||||
|
this.panelCtrl = $scope.ctrl;
|
||||||
|
this.panel = this.panelCtrl.panel;
|
||||||
|
|
||||||
|
this.datasourceSrv = datasourceSrv;
|
||||||
|
this.templateSrv = templateSrv;
|
||||||
|
this.popoverSrv = popoverSrv;
|
||||||
|
|
||||||
|
// Map functions for bs-typeahead
|
||||||
|
this.getGroupNames = _lodash2.default.partial(getMetricNames, this, 'groupList');
|
||||||
|
this.getHostNames = _lodash2.default.partial(getMetricNames, this, 'hostList');
|
||||||
|
this.getApplicationNames = _lodash2.default.partial(getMetricNames, this, 'appList');
|
||||||
|
|
||||||
|
// Update metric suggestion when template variable was changed
|
||||||
|
$rootScope.$on('template-variable-value-updated', function () {
|
||||||
|
return _this.onVariableChange();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ackFilters = ['all triggers', 'unacknowledged', 'acknowledged'];
|
||||||
|
|
||||||
|
this.sortByFields = [{ text: 'last change', value: 'lastchange' }, { text: 'severity', value: 'priority' }];
|
||||||
|
|
||||||
|
this.showEventsFields = [{ text: 'All', value: [0, 1] }, { text: 'OK', value: [0] }, { text: 'Problems', value: 1 }];
|
||||||
|
|
||||||
|
// Load scope defaults
|
||||||
|
var scopeDefaults = {
|
||||||
|
metric: {},
|
||||||
|
inputStyles: {},
|
||||||
|
oldTarget: _lodash2.default.cloneDeep(this.panel.triggers)
|
||||||
|
};
|
||||||
|
_lodash2.default.defaults(this, scopeDefaults);
|
||||||
|
|
||||||
|
// Set default datasource
|
||||||
|
this.datasources = _lodash2.default.map(this.getZabbixDataSources(), 'name');
|
||||||
|
if (!this.panel.datasource) {
|
||||||
|
this.panel.datasource = this.datasources[0];
|
||||||
|
}
|
||||||
|
// Load datasource
|
||||||
|
this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
|
||||||
|
_this.datasource = datasource;
|
||||||
|
_this.zabbix = datasource.zabbix;
|
||||||
|
_this.queryBuilder = datasource.queryBuilder;
|
||||||
|
_this.initFilters();
|
||||||
|
_this.panelCtrl.refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(TriggerPanelEditorCtrl, [{
|
||||||
|
key: 'initFilters',
|
||||||
|
value: function initFilters() {
|
||||||
|
return Promise.all([this.suggestGroups(), this.suggestHosts(), this.suggestApps()]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestGroups',
|
||||||
|
value: function suggestGroups() {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
return this.zabbix.getAllGroups().then(function (groups) {
|
||||||
|
_this2.metric.groupList = groups;
|
||||||
|
return groups;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestHosts',
|
||||||
|
value: function suggestHosts() {
|
||||||
|
var _this3 = this;
|
||||||
|
|
||||||
|
var groupFilter = this.datasource.replaceTemplateVars(this.panel.triggers.group.filter);
|
||||||
|
return this.zabbix.getAllHosts(groupFilter).then(function (hosts) {
|
||||||
|
_this3.metric.hostList = hosts;
|
||||||
|
return hosts;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'suggestApps',
|
||||||
|
value: function suggestApps() {
|
||||||
|
var _this4 = this;
|
||||||
|
|
||||||
|
var groupFilter = this.datasource.replaceTemplateVars(this.panel.triggers.group.filter);
|
||||||
|
var hostFilter = this.datasource.replaceTemplateVars(this.panel.triggers.host.filter);
|
||||||
|
return this.zabbix.getAllApps(groupFilter, hostFilter).then(function (apps) {
|
||||||
|
_this4.metric.appList = apps;
|
||||||
|
return apps;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'onVariableChange',
|
||||||
|
value: function onVariableChange() {
|
||||||
|
if (this.isContainsVariables()) {
|
||||||
|
this.targetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check query for template variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'isContainsVariables',
|
||||||
|
value: function isContainsVariables() {
|
||||||
|
var _this5 = this;
|
||||||
|
|
||||||
|
return _lodash2.default.some(['group', 'host', 'application'], function (field) {
|
||||||
|
return utils.isTemplateVariable(_this5.panel.triggers[field].filter, _this5.templateSrv.variables);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'targetChanged',
|
||||||
|
value: function targetChanged() {
|
||||||
|
this.initFilters();
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'parseTarget',
|
||||||
|
value: function parseTarget() {
|
||||||
|
this.initFilters();
|
||||||
|
var newTarget = _lodash2.default.cloneDeep(this.panel.triggers);
|
||||||
|
if (!_lodash2.default.isEqual(this.oldTarget, this.panel.triggers)) {
|
||||||
|
this.oldTarget = newTarget;
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'refreshTriggerSeverity',
|
||||||
|
value: function refreshTriggerSeverity() {
|
||||||
|
_lodash2.default.each(this.triggerList, function (trigger) {
|
||||||
|
trigger.color = this.panel.triggerSeverity[trigger.priority].color;
|
||||||
|
trigger.severity = this.panel.triggerSeverity[trigger.priority].severity;
|
||||||
|
});
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'datasourceChanged',
|
||||||
|
value: function datasourceChanged() {
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'changeTriggerSeverityColor',
|
||||||
|
value: function changeTriggerSeverityColor(trigger, color) {
|
||||||
|
this.panel.triggerSeverity[trigger.priority].color = color;
|
||||||
|
this.refreshTriggerSeverity();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'isRegex',
|
||||||
|
value: function isRegex(str) {
|
||||||
|
return utils.isRegex(str);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'isVariable',
|
||||||
|
value: function isVariable(str) {
|
||||||
|
return utils.isTemplateVariable(str, this.templateSrv.variables);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'getZabbixDataSources',
|
||||||
|
value: function getZabbixDataSources() {
|
||||||
|
var ZABBIX_DS_ID = 'alexanderzobnin-zabbix-datasource';
|
||||||
|
return _lodash2.default.filter(this.datasourceSrv.getMetricSources(), function (datasource) {
|
||||||
|
return datasource.meta.id === ZABBIX_DS_ID && datasource.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return TriggerPanelEditorCtrl;
|
||||||
|
}();
|
||||||
|
|
||||||
|
// Get list of metric names for bs-typeahead directive
|
||||||
|
|
||||||
|
|
||||||
|
function getMetricNames(scope, metricList) {
|
||||||
|
return _lodash2.default.uniq(_lodash2.default.map(scope.metric[metricList], 'name'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function triggerPanelEditor() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: true,
|
||||||
|
templateUrl: 'public/plugins/alexanderzobnin-zabbix-app/panel-triggers/editor.html',
|
||||||
|
controller: TriggerPanelEditorCtrl
|
||||||
|
};
|
||||||
|
}
|
||||||
302
dist/test/panel-triggers/module.js
vendored
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.PanelCtrl = exports.TriggerPanelCtrl = undefined;
|
||||||
|
|
||||||
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||||
|
|
||||||
|
var _lodash = require('lodash');
|
||||||
|
|
||||||
|
var _lodash2 = _interopRequireDefault(_lodash);
|
||||||
|
|
||||||
|
var _moment = require('moment');
|
||||||
|
|
||||||
|
var _moment2 = _interopRequireDefault(_moment);
|
||||||
|
|
||||||
|
var _utils = require('../datasource-zabbix/utils');
|
||||||
|
|
||||||
|
var utils = _interopRequireWildcard(_utils);
|
||||||
|
|
||||||
|
var _sdk = require('app/plugins/sdk');
|
||||||
|
|
||||||
|
var _editor = require('./editor');
|
||||||
|
|
||||||
|
require('./ack-tooltip.directive');
|
||||||
|
|
||||||
|
require('./css/panel_triggers.css!');
|
||||||
|
|
||||||
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||||||
|
|
||||||
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
|
||||||
|
* Grafana-Zabbix
|
||||||
|
* Zabbix plugin for Grafana.
|
||||||
|
* http://github.com/alexanderzobnin/grafana-zabbix
|
||||||
|
*
|
||||||
|
* Trigger panel.
|
||||||
|
* This feature sponsored by CORE IT
|
||||||
|
* http://www.coreit.fr
|
||||||
|
*
|
||||||
|
* Copyright 2015 Alexander Zobnin alexanderzobnin@gmail.com
|
||||||
|
* Licensed under the Apache License, Version 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
var defaultSeverity = [{ priority: 0, severity: 'Not classified', color: '#B7DBAB', show: true }, { priority: 1, severity: 'Information', color: '#82B5D8', show: true }, { priority: 2, severity: 'Warning', color: '#E5AC0E', show: true }, { priority: 3, severity: 'Average', color: '#C15C17', show: true }, { priority: 4, severity: 'High', color: '#BF1B00', show: true }, { priority: 5, severity: 'Disaster', color: '#890F02', show: true }];
|
||||||
|
|
||||||
|
var panelDefaults = {
|
||||||
|
datasource: null,
|
||||||
|
triggers: {
|
||||||
|
group: { filter: "" },
|
||||||
|
host: { filter: "" },
|
||||||
|
application: { filter: "" },
|
||||||
|
trigger: { filter: "" }
|
||||||
|
},
|
||||||
|
hostField: true,
|
||||||
|
statusField: false,
|
||||||
|
severityField: false,
|
||||||
|
lastChangeField: true,
|
||||||
|
ageField: true,
|
||||||
|
infoField: true,
|
||||||
|
limit: 10,
|
||||||
|
showTriggers: 'all triggers',
|
||||||
|
sortTriggersBy: { text: 'last change', value: 'lastchange' },
|
||||||
|
showEvents: { text: 'Problems', value: '1' },
|
||||||
|
triggerSeverity: defaultSeverity,
|
||||||
|
okEventColor: 'rgba(0, 245, 153, 0.45)',
|
||||||
|
ackEventColor: 'rgba(0, 0, 0, 0)'
|
||||||
|
};
|
||||||
|
|
||||||
|
var triggerStatusMap = {
|
||||||
|
'0': 'OK',
|
||||||
|
'1': 'Problem'
|
||||||
|
};
|
||||||
|
|
||||||
|
var defaultTimeFormat = "DD MMM YYYY HH:mm:ss";
|
||||||
|
|
||||||
|
var TriggerPanelCtrl = function (_MetricsPanelCtrl) {
|
||||||
|
_inherits(TriggerPanelCtrl, _MetricsPanelCtrl);
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function TriggerPanelCtrl($scope, $injector, $element, datasourceSrv, templateSrv, contextSrv) {
|
||||||
|
_classCallCheck(this, TriggerPanelCtrl);
|
||||||
|
|
||||||
|
var _this = _possibleConstructorReturn(this, (TriggerPanelCtrl.__proto__ || Object.getPrototypeOf(TriggerPanelCtrl)).call(this, $scope, $injector));
|
||||||
|
|
||||||
|
_this.datasourceSrv = datasourceSrv;
|
||||||
|
_this.templateSrv = templateSrv;
|
||||||
|
_this.contextSrv = contextSrv;
|
||||||
|
_this.triggerStatusMap = triggerStatusMap;
|
||||||
|
_this.defaultTimeFormat = defaultTimeFormat;
|
||||||
|
|
||||||
|
// Load panel defaults
|
||||||
|
// _.cloneDeep() need for prevent changing shared defaultSeverity.
|
||||||
|
// Load object "by value" istead "by reference".
|
||||||
|
_lodash2.default.defaults(_this.panel, _lodash2.default.cloneDeep(panelDefaults));
|
||||||
|
|
||||||
|
_this.triggerList = [];
|
||||||
|
_this.refreshData();
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override onInitMetricsPanelEditMode() method from MetricsPanelCtrl.
|
||||||
|
* We don't need metric editor from Metrics Panel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
_createClass(TriggerPanelCtrl, [{
|
||||||
|
key: 'onInitMetricsPanelEditMode',
|
||||||
|
value: function onInitMetricsPanelEditMode() {
|
||||||
|
this.addEditorTab('Options', _editor.triggerPanelEditor, 2);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'refresh',
|
||||||
|
value: function refresh() {
|
||||||
|
this.onMetricsPanelRefresh();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'onMetricsPanelRefresh',
|
||||||
|
value: function onMetricsPanelRefresh() {
|
||||||
|
// ignore fetching data if another panel is in fullscreen
|
||||||
|
if (this.otherPanelInFullscreenMode()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refreshData();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'refreshData',
|
||||||
|
value: function refreshData() {
|
||||||
|
// clear loading/error state
|
||||||
|
delete this.error;
|
||||||
|
this.loading = true;
|
||||||
|
this.setTimeQueryStart();
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Load datasource
|
||||||
|
return this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
|
||||||
|
var zabbix = datasource.zabbix;
|
||||||
|
var showEvents = self.panel.showEvents.value;
|
||||||
|
var triggerFilter = self.panel.triggers;
|
||||||
|
|
||||||
|
// Replace template variables
|
||||||
|
var groupFilter = datasource.replaceTemplateVars(triggerFilter.group.filter);
|
||||||
|
var hostFilter = datasource.replaceTemplateVars(triggerFilter.host.filter);
|
||||||
|
var appFilter = datasource.replaceTemplateVars(triggerFilter.application.filter);
|
||||||
|
|
||||||
|
var getTriggers = zabbix.getTriggers(groupFilter, hostFilter, appFilter, showEvents);
|
||||||
|
return getTriggers.then(function (triggers) {
|
||||||
|
return _lodash2.default.map(triggers, function (trigger) {
|
||||||
|
var triggerObj = trigger;
|
||||||
|
|
||||||
|
// Format last change and age
|
||||||
|
trigger.lastchangeUnix = Number(trigger.lastchange);
|
||||||
|
var timestamp = _moment2.default.unix(trigger.lastchangeUnix);
|
||||||
|
if (self.panel.customLastChangeFormat) {
|
||||||
|
// User defined format
|
||||||
|
triggerObj.lastchange = timestamp.format(self.panel.lastChangeFormat);
|
||||||
|
} else {
|
||||||
|
triggerObj.lastchange = timestamp.format(self.defaultTimeFormat);
|
||||||
|
}
|
||||||
|
triggerObj.age = timestamp.fromNow(true);
|
||||||
|
|
||||||
|
// Set host that the trigger belongs
|
||||||
|
if (trigger.hosts.length) {
|
||||||
|
triggerObj.host = trigger.hosts[0].name;
|
||||||
|
triggerObj.hostTechName = trigger.hosts[0].host;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set color
|
||||||
|
if (trigger.value === '1') {
|
||||||
|
// Problem state
|
||||||
|
triggerObj.color = self.panel.triggerSeverity[trigger.priority].color;
|
||||||
|
} else {
|
||||||
|
// OK state
|
||||||
|
triggerObj.color = self.panel.okEventColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerObj.severity = self.panel.triggerSeverity[trigger.priority].severity;
|
||||||
|
return triggerObj;
|
||||||
|
});
|
||||||
|
}).then(function (triggerList) {
|
||||||
|
|
||||||
|
// Request acknowledges for trigger
|
||||||
|
var eventids = _lodash2.default.map(triggerList, function (trigger) {
|
||||||
|
return trigger.lastEvent.eventid;
|
||||||
|
});
|
||||||
|
|
||||||
|
return zabbix.getAcknowledges(eventids).then(function (events) {
|
||||||
|
|
||||||
|
// Map events to triggers
|
||||||
|
_lodash2.default.each(triggerList, function (trigger) {
|
||||||
|
var event = _lodash2.default.find(events, function (event) {
|
||||||
|
return event.eventid === trigger.lastEvent.eventid;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
trigger.acknowledges = _lodash2.default.map(event.acknowledges, function (ack) {
|
||||||
|
var timestamp = _moment2.default.unix(ack.clock);
|
||||||
|
if (self.panel.customLastChangeFormat) {
|
||||||
|
ack.time = timestamp.format(self.panel.lastChangeFormat);
|
||||||
|
} else {
|
||||||
|
ack.time = timestamp.format(self.defaultTimeFormat);
|
||||||
|
}
|
||||||
|
ack.user = ack.alias + ' (' + ack.name + ' ' + ack.surname + ')';
|
||||||
|
return ack;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mark acknowledged triggers with different color
|
||||||
|
if (self.panel.markAckEvents && trigger.acknowledges.length) {
|
||||||
|
trigger.color = self.panel.ackEventColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter triggers by description
|
||||||
|
var triggerFilter = self.panel.triggers.trigger.filter;
|
||||||
|
if (triggerFilter) {
|
||||||
|
triggerList = filterTriggers(triggerList, triggerFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter acknowledged triggers
|
||||||
|
if (self.panel.showTriggers === 'unacknowledged') {
|
||||||
|
triggerList = _lodash2.default.filter(triggerList, function (trigger) {
|
||||||
|
return !trigger.acknowledges;
|
||||||
|
});
|
||||||
|
} else if (self.panel.showTriggers === 'acknowledged') {
|
||||||
|
triggerList = _lodash2.default.filter(triggerList, 'acknowledges');
|
||||||
|
} else {
|
||||||
|
triggerList = triggerList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter triggers by severity
|
||||||
|
triggerList = _lodash2.default.filter(triggerList, function (trigger) {
|
||||||
|
return self.panel.triggerSeverity[trigger.priority].show;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort triggers
|
||||||
|
if (self.panel.sortTriggersBy.value === 'priority') {
|
||||||
|
triggerList = _lodash2.default.sortBy(triggerList, 'priority').reverse();
|
||||||
|
} else {
|
||||||
|
triggerList = _lodash2.default.sortBy(triggerList, 'lastchangeUnix').reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit triggers number
|
||||||
|
self.triggerList = triggerList.slice(0, self.panel.limit);
|
||||||
|
|
||||||
|
// Notify panel that request is finished
|
||||||
|
self.setTimeQueryEnd();
|
||||||
|
self.loading = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'switchComment',
|
||||||
|
value: function switchComment(trigger) {
|
||||||
|
trigger.showComment = !trigger.showComment;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'acknowledgeTrigger',
|
||||||
|
value: function acknowledgeTrigger(trigger, message) {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
|
var eventid = trigger.lastEvent.eventid;
|
||||||
|
var grafana_user = this.contextSrv.user.name;
|
||||||
|
var ack_message = grafana_user + ' (Grafana): ' + message;
|
||||||
|
return this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
|
||||||
|
var zabbixAPI = datasource.zabbix.zabbixAPI;
|
||||||
|
return zabbixAPI.acknowledgeEvent(eventid, ack_message).then(function () {
|
||||||
|
_this2.refresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return TriggerPanelCtrl;
|
||||||
|
}(_sdk.MetricsPanelCtrl);
|
||||||
|
|
||||||
|
TriggerPanelCtrl.templateUrl = 'panel-triggers/module.html';
|
||||||
|
|
||||||
|
function filterTriggers(triggers, triggerFilter) {
|
||||||
|
if (utils.isRegex(triggerFilter)) {
|
||||||
|
return _lodash2.default.filter(triggers, function (trigger) {
|
||||||
|
return utils.buildRegex(triggerFilter).test(trigger.description);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return _lodash2.default.filter(triggers, function (trigger) {
|
||||||
|
return trigger.description === triggerFilter;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.TriggerPanelCtrl = TriggerPanelCtrl;
|
||||||
|
exports.PanelCtrl = TriggerPanelCtrl;
|
||||||