Merge remote-tracking branch 'upstream/master' into threshold_regex

# Conflicts:
#	dist/datasource-zabbix/datasource.js
#	dist/datasource-zabbix/datasource.js.map
#	dist/datasource-zabbix/specs/test-main.js
#	dist/test/datasource-zabbix/datasource.js
#	dist/test/datasource-zabbix/specs/test-main.js
This commit is contained in:
akotynski
2017-10-23 14:26:46 +02:00
48 changed files with 1835 additions and 649 deletions

View File

@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## [Unreleased]
### Added ### Added
- PostgreSQL support for Direct DB Connection. - PostgreSQL support for Direct DB Connection.
- _Triggers_ query mode which allows to count active alerts by group, host and application, [#141](https://github.com/alexanderzobnin/grafana-zabbix/issues/141)
- `sortSeries()` function that allows to sort multiple timeseries by name, [#447](https://github.com/alexanderzobnin/grafana-zabbix/issues/447) - `sortSeries()` function that allows to sort multiple timeseries by name, [#447](https://github.com/alexanderzobnin/grafana-zabbix/issues/447)
- `percentil()` function - `percentil()` function

View File

@@ -1,20 +1,25 @@
{ {
"id": null, "__inputs": [
"title": "Template Linux Server", {
"originalTitle": "Template Linux Server", "name": "DS_NAME",
"tags": [ "type": "datasource",
"zabbix", "pluginId": "alexanderzobnin-zabbix-datasource"
"example" }
], ],
"style": "dark", "title": "Zabbix Template Linux Server",
"timezone": "browser", "revision": 1,
"annotations": {
"list": []
},
"editable": true, "editable": true,
"gnetId": null,
"graphTooltip": 0,
"hideControls": false, "hideControls": false,
"sharedCrosshair": false, "id": null,
"links": [],
"rows": [ "rows": [
{ {
"collapse": false, "collapse": false,
"editable": true,
"height": "250px", "height": "250px",
"panels": [ "panels": [
{ {
@@ -24,16 +29,13 @@
"CPU user time": "#EAB839" "CPU user time": "#EAB839"
}, },
"bars": false, "bars": false,
"datasource": "$datasource", "dashLength": 10,
"dashes": false,
"datasource": "${DS_NAME}",
"editable": true, "editable": true,
"error": false, "error": false,
"fill": 3, "fill": 3,
"grid": { "grid": {},
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 1, "id": 1,
"legend": { "legend": {
"avg": false, "avg": false,
@@ -53,6 +55,7 @@
"points": false, "points": false,
"renderer": "flot", "renderer": "flot",
"seriesOverrides": [], "seriesOverrides": [],
"spaceLength": 10,
"span": 6, "span": 6,
"stack": true, "stack": true,
"steppedLine": false, "steppedLine": false,
@@ -61,6 +64,7 @@
"application": { "application": {
"filter": "CPU" "filter": "CPU"
}, },
"countTriggers": true,
"functions": [], "functions": [],
"group": { "group": {
"filter": "$group" "filter": "$group"
@@ -71,21 +75,31 @@
"item": { "item": {
"filter": "/CPU/" "filter": "/CPU/"
}, },
"minSeverity": 3,
"mode": 0, "mode": 0,
"options": {
"showDisabledItems": false
},
"refId": "A" "refId": "A"
} }
], ],
"thresholds": [],
"timeFrom": null, "timeFrom": null,
"timeShift": null, "timeShift": null,
"title": "CPU", "title": "CPU",
"tooltip": { "tooltip": {
"msResolution": false, "msResolution": false,
"shared": true, "shared": true,
"sort": 0,
"value_type": "individual" "value_type": "individual"
}, },
"type": "graph", "type": "graph",
"xaxis": { "xaxis": {
"show": true "buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
}, },
"yaxes": [ "yaxes": [
{ {
@@ -109,16 +123,13 @@
"Processor load (1 min average per core)": "#1F78C1" "Processor load (1 min average per core)": "#1F78C1"
}, },
"bars": false, "bars": false,
"datasource": "$datasource", "dashLength": 10,
"dashes": false,
"datasource": "${DS_NAME}",
"editable": true, "editable": true,
"error": false, "error": false,
"fill": 1, "fill": 1,
"grid": { "grid": {},
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 2, "id": 2,
"legend": { "legend": {
"avg": false, "avg": false,
@@ -138,6 +149,7 @@
"points": false, "points": false,
"renderer": "flot", "renderer": "flot",
"seriesOverrides": [], "seriesOverrides": [],
"spaceLength": 10,
"span": 6, "span": 6,
"stack": false, "stack": false,
"steppedLine": false, "steppedLine": false,
@@ -146,6 +158,7 @@
"application": { "application": {
"filter": "CPU" "filter": "CPU"
}, },
"countTriggers": true,
"functions": [], "functions": [],
"group": { "group": {
"filter": "$group" "filter": "$group"
@@ -156,21 +169,31 @@
"item": { "item": {
"filter": "Processor load (15 min average per core)" "filter": "Processor load (15 min average per core)"
}, },
"minSeverity": 3,
"mode": 0, "mode": 0,
"options": {
"showDisabledItems": false
},
"refId": "A" "refId": "A"
} }
], ],
"thresholds": [],
"timeFrom": null, "timeFrom": null,
"timeShift": null, "timeShift": null,
"title": "System load", "title": "System load",
"tooltip": { "tooltip": {
"msResolution": false, "msResolution": false,
"shared": true, "shared": true,
"sort": 0,
"value_type": "cumulative" "value_type": "cumulative"
}, },
"type": "graph", "type": "graph",
"xaxis": { "xaxis": {
"show": true "buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
}, },
"yaxes": [ "yaxes": [
{ {
@@ -190,27 +213,27 @@
] ]
} }
], ],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": true, "showTitle": true,
"title": "CPU" "title": "CPU",
"titleSize": "h6"
}, },
{ {
"collapse": false, "collapse": false,
"editable": true,
"height": "250px", "height": "250px",
"panels": [ "panels": [
{ {
"aliasColors": {}, "aliasColors": {},
"bars": false, "bars": false,
"datasource": "$datasource", "dashLength": 10,
"dashes": false,
"datasource": "${DS_NAME}",
"editable": true, "editable": true,
"error": false, "error": false,
"fill": 3, "fill": 3,
"grid": { "grid": {},
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 3, "id": 3,
"legend": { "legend": {
"alignAsTable": false, "alignAsTable": false,
@@ -233,20 +256,14 @@
"points": false, "points": false,
"renderer": "flot", "renderer": "flot",
"repeat": "netif", "repeat": "netif",
"scopedVars": {
"netif": {
"text": "eth0",
"value": "eth0",
"selected": false
}
},
"seriesOverrides": [ "seriesOverrides": [
{ {
"alias": "/Incoming/", "alias": "/Incoming/",
"transform": "negative-Y" "transform": "negative-Y"
} }
], ],
"span": 6, "spaceLength": 10,
"span": 12,
"stack": false, "stack": false,
"steppedLine": false, "steppedLine": false,
"targets": [ "targets": [
@@ -254,6 +271,7 @@
"application": { "application": {
"filter": "" "filter": ""
}, },
"countTriggers": true,
"functions": [], "functions": [],
"group": { "group": {
"filter": "$group" "filter": "$group"
@@ -264,21 +282,31 @@
"item": { "item": {
"filter": "/$netif/" "filter": "/$netif/"
}, },
"minSeverity": 3,
"mode": 0, "mode": 0,
"options": {
"showDisabledItems": false
},
"refId": "A" "refId": "A"
} }
], ],
"thresholds": [],
"timeFrom": null, "timeFrom": null,
"timeShift": null, "timeShift": null,
"title": "Network traffic on $netif", "title": "Network traffic on $netif",
"tooltip": { "tooltip": {
"msResolution": false, "msResolution": false,
"shared": true, "shared": true,
"sort": 0,
"value_type": "cumulative" "value_type": "cumulative"
}, },
"type": "graph", "type": "graph",
"xaxis": { "xaxis": {
"show": true "buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
}, },
"yaxes": [ "yaxes": [
{ {
@@ -296,113 +324,96 @@
"show": true "show": true
} }
] ]
},
{
"aliasColors": {},
"bars": false,
"datasource": "$datasource",
"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
} }
], ],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": true, "showTitle": true,
"title": "Network" "title": "Network",
"titleSize": "h6"
} }
], ],
"schemaVersion": 14,
"style": "dark",
"tags": [
"zabbix",
"example"
],
"templating": {
"list": [
{
"allFormat": "regex values",
"allValue": null,
"current": {},
"datasource": "${DS_NAME}",
"hide": 0,
"includeAll": false,
"label": "Group",
"multi": false,
"multiFormat": "glob",
"name": "group",
"options": [],
"query": "*",
"refresh": 1,
"refresh_on_load": false,
"regex": "",
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allFormat": "glob",
"allValue": null,
"current": {},
"datasource": "${DS_NAME}",
"hide": 0,
"includeAll": false,
"label": "Host",
"multi": false,
"multiFormat": "glob",
"name": "host",
"options": [],
"query": "$group.*",
"refresh": 1,
"refresh_on_load": false,
"regex": "",
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allFormat": "regex values",
"allValue": null,
"current": {},
"datasource": "${DS_NAME}",
"hide": 0,
"hideLabel": false,
"includeAll": true,
"label": "Network interface",
"multi": true,
"multiFormat": "regex values",
"name": "netif",
"options": [],
"query": "*.$host.Network interfaces.*",
"refresh": 1,
"refresh_on_load": false,
"regex": "/(?:Incoming|Outgoing) network traffic on (.*)/",
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": { "time": {
"from": "now-3h", "from": "now-3h",
"to": "now" "to": "now"
@@ -432,77 +443,5 @@
"30d" "30d"
] ]
}, },
"templating": { "timezone": "browser"
"list": [
{
"current": {},
"hide": 0,
"label": "Zabbix Data Source",
"name": "datasource",
"options": [],
"query": "alexanderzobnin-zabbix-datasource",
"refresh": 1,
"regex": "",
"type": "datasource"
},
{
"allFormat": "regex values",
"current": {},
"datasource": "$datasource",
"hide": 0,
"includeAll": false,
"label": "Group",
"multi": false,
"multiFormat": "glob",
"name": "group",
"options": [],
"query": "*",
"refresh": 1,
"refresh_on_load": false,
"regex": "",
"type": "query"
},
{
"allFormat": "glob",
"current": {},
"datasource": "$datasource",
"hide": 0,
"includeAll": false,
"label": "Host",
"multi": false,
"multiFormat": "glob",
"name": "host",
"options": [],
"query": "$group.*",
"refresh": 1,
"refresh_on_load": false,
"regex": "",
"type": "query"
},
{
"allFormat": "regex values",
"current": {},
"datasource": "$datasource",
"hide": 0,
"hideLabel": false,
"includeAll": true,
"label": "Network interface",
"multi": true,
"multiFormat": "regex values",
"name": "netif",
"options": [],
"query": "*.$host.Network interfaces.*",
"refresh": 1,
"refresh_on_load": false,
"regex": "/(?:Incoming|Outgoing) network traffic on (.*)/",
"type": "query"
}
]
},
"annotations": {
"list": []
},
"schemaVersion": 12,
"version": 9,
"links": []
} }

View File

@@ -0,0 +1,371 @@
{
"__inputs": [
{
"name": "DS_NAME",
"type": "datasource",
"pluginId": "alexanderzobnin-zabbix-datasource"
}
],
"title": "Zabbix System Status",
"revision": "1.0",
"annotations": {
"list": []
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"hideControls": false,
"id": null,
"links": [],
"rows": [
{
"collapse": false,
"height": 250,
"panels": [
{
"columns": [],
"datasource": "${DS_NAME}",
"fontSize": "100%",
"id": 9,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"span": 12,
"styles": [
{
"alias": "Time",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "Time",
"type": "date"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"rgba(45, 172, 121, 0.97)",
"rgba(45, 172, 121, 0.97)",
"#58140c"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "Disaster",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "none"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"#99440a",
"rgba(45, 172, 121, 0.97)",
"#99440a"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "High",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "short"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)",
"#c15c17"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "Average",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "short"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)",
"#cca300"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "Warning",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "short"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)",
"#64b0c8"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "Information",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "short"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)",
"rgb(176, 176, 176)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "Not classified",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "short"
},
{
"alias": "",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 0,
"pattern": "/.*/",
"thresholds": [],
"type": "number",
"unit": "none"
}
],
"targets": [
{
"application": {
"filter": ""
},
"countTriggers": false,
"functions": [],
"group": {
"filter": "/.*/"
},
"host": {
"filter": "/.*/"
},
"item": {
"filter": ""
},
"minSeverity": 0,
"mode": 4,
"options": {
"countTriggers": false,
"showDisabledItems": false
},
"refId": "A",
"target": ""
}
],
"title": "System status",
"transform": "table",
"type": "table"
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": false,
"title": "Dashboard Row",
"titleSize": "h6"
},
{
"collapse": false,
"height": "150px",
"panels": [
{
"cacheTimeout": null,
"colorBackground": true,
"colorValue": false,
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(16, 154, 113, 0.97)",
"#890f02"
],
"datasource": "${DS_NAME}",
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"id": 1,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"minSpan": 2,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"repeat": "group",
"span": 2,
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"application": {
"filter": ""
},
"countTriggers": true,
"functions": [],
"group": {
"filter": "$group"
},
"host": {
"filter": "/.*/"
},
"item": {
"filter": ""
},
"minSeverity": 3,
"mode": 4,
"options": {
"showDisabledItems": false
},
"refId": "A",
"target": ""
}
],
"thresholds": "0,1",
"title": "$group",
"type": "singlestat",
"valueFontSize": "120%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": false,
"title": "Dashboard Row",
"titleSize": "h6"
}
],
"schemaVersion": 14,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"allValue": null,
"current": {},
"datasource": "${DS_NAME}",
"hide": 0,
"includeAll": true,
"label": null,
"multi": true,
"name": "group",
"options": [],
"query": "*",
"refresh": 1,
"regex": "",
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"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"
]
},
"timezone": ""
}

View File

@@ -1,71 +1,79 @@
"use strict"; 'use strict';
System.register([], function (_export, _context) { System.register([], function (_export, _context) {
"use strict"; "use strict";
var MODE_METRICS, MODE_ITSERVICE, MODE_TEXT, MODE_ITEMID, SEV_NOT_CLASSIFIED, SEV_INFORMATION, SEV_WARNING, SEV_AVERAGE, SEV_HIGH, SEV_DISASTER, SHOW_ALL_TRIGGERS, SHOW_ALL_EVENTS, SHOW_OK_EVENTS, DATAPOINT_VALUE, DATAPOINT_TS; var MODE_METRICS, MODE_ITSERVICE, MODE_TEXT, MODE_ITEMID, MODE_TRIGGERS, SEV_NOT_CLASSIFIED, SEV_INFORMATION, SEV_WARNING, SEV_AVERAGE, SEV_HIGH, SEV_DISASTER, SHOW_ALL_TRIGGERS, SHOW_ALL_EVENTS, SHOW_OK_EVENTS, DATAPOINT_VALUE, DATAPOINT_TS, TRIGGER_SEVERITY;
return { return {
setters: [], setters: [],
execute: function () { execute: function () {
_export("MODE_METRICS", MODE_METRICS = 0); _export('MODE_METRICS', MODE_METRICS = 0);
_export("MODE_METRICS", MODE_METRICS); _export('MODE_METRICS', MODE_METRICS);
_export("MODE_ITSERVICE", MODE_ITSERVICE = 1); _export('MODE_ITSERVICE', MODE_ITSERVICE = 1);
_export("MODE_ITSERVICE", MODE_ITSERVICE); _export('MODE_ITSERVICE', MODE_ITSERVICE);
_export("MODE_TEXT", MODE_TEXT = 2); _export('MODE_TEXT', MODE_TEXT = 2);
_export("MODE_TEXT", MODE_TEXT); _export('MODE_TEXT', MODE_TEXT);
_export("MODE_ITEMID", MODE_ITEMID = 3); _export('MODE_ITEMID', MODE_ITEMID = 3);
_export("MODE_ITEMID", MODE_ITEMID); _export('MODE_ITEMID', MODE_ITEMID);
_export("SEV_NOT_CLASSIFIED", SEV_NOT_CLASSIFIED = 0); _export('MODE_TRIGGERS', MODE_TRIGGERS = 4);
_export("SEV_NOT_CLASSIFIED", SEV_NOT_CLASSIFIED); _export('MODE_TRIGGERS', MODE_TRIGGERS);
_export("SEV_INFORMATION", SEV_INFORMATION = 1); _export('SEV_NOT_CLASSIFIED', SEV_NOT_CLASSIFIED = 0);
_export("SEV_INFORMATION", SEV_INFORMATION); _export('SEV_NOT_CLASSIFIED', SEV_NOT_CLASSIFIED);
_export("SEV_WARNING", SEV_WARNING = 2); _export('SEV_INFORMATION', SEV_INFORMATION = 1);
_export("SEV_WARNING", SEV_WARNING); _export('SEV_INFORMATION', SEV_INFORMATION);
_export("SEV_AVERAGE", SEV_AVERAGE = 3); _export('SEV_WARNING', SEV_WARNING = 2);
_export("SEV_AVERAGE", SEV_AVERAGE); _export('SEV_WARNING', SEV_WARNING);
_export("SEV_HIGH", SEV_HIGH = 4); _export('SEV_AVERAGE', SEV_AVERAGE = 3);
_export("SEV_HIGH", SEV_HIGH); _export('SEV_AVERAGE', SEV_AVERAGE);
_export("SEV_DISASTER", SEV_DISASTER = 5); _export('SEV_HIGH', SEV_HIGH = 4);
_export("SEV_DISASTER", SEV_DISASTER); _export('SEV_HIGH', SEV_HIGH);
_export("SHOW_ALL_TRIGGERS", SHOW_ALL_TRIGGERS = [0, 1]); _export('SEV_DISASTER', SEV_DISASTER = 5);
_export("SHOW_ALL_TRIGGERS", SHOW_ALL_TRIGGERS); _export('SEV_DISASTER', SEV_DISASTER);
_export("SHOW_ALL_EVENTS", SHOW_ALL_EVENTS = [0, 1]); _export('SHOW_ALL_TRIGGERS', SHOW_ALL_TRIGGERS = [0, 1]);
_export("SHOW_ALL_EVENTS", SHOW_ALL_EVENTS); _export('SHOW_ALL_TRIGGERS', SHOW_ALL_TRIGGERS);
_export("SHOW_OK_EVENTS", SHOW_OK_EVENTS = 1); _export('SHOW_ALL_EVENTS', SHOW_ALL_EVENTS = [0, 1]);
_export("SHOW_OK_EVENTS", SHOW_OK_EVENTS); _export('SHOW_ALL_EVENTS', SHOW_ALL_EVENTS);
_export("DATAPOINT_VALUE", DATAPOINT_VALUE = 0); _export('SHOW_OK_EVENTS', SHOW_OK_EVENTS = 1);
_export("DATAPOINT_VALUE", DATAPOINT_VALUE); _export('SHOW_OK_EVENTS', SHOW_OK_EVENTS);
_export("DATAPOINT_TS", DATAPOINT_TS = 1); _export('DATAPOINT_VALUE', DATAPOINT_VALUE = 0);
_export("DATAPOINT_TS", DATAPOINT_TS); _export('DATAPOINT_VALUE', DATAPOINT_VALUE);
_export('DATAPOINT_TS', DATAPOINT_TS = 1);
_export('DATAPOINT_TS', DATAPOINT_TS);
_export('TRIGGER_SEVERITY', TRIGGER_SEVERITY = [{ val: 0, text: 'Not classified' }, { val: 1, text: 'Information' }, { val: 2, text: 'Warning' }, { val: 3, text: 'Average' }, { val: 4, text: 'High' }, { val: 5, text: 'Disaster' }]);
_export('TRIGGER_SEVERITY', TRIGGER_SEVERITY);
} }
}; };
}); });

View File

@@ -1 +1 @@
{"version":3,"sources":["../../src/datasource-zabbix/constants.js"],"names":["MODE_METRICS","MODE_ITSERVICE","MODE_TEXT","MODE_ITEMID","SEV_NOT_CLASSIFIED","SEV_INFORMATION","SEV_WARNING","SEV_AVERAGE","SEV_HIGH","SEV_DISASTER","SHOW_ALL_TRIGGERS","SHOW_ALL_EVENTS","SHOW_OK_EVENTS","DATAPOINT_VALUE","DATAPOINT_TS"],"mappings":";;;;;;;;;8BACaA,Y,GAAe,C;;;;gCACfC,c,GAAiB,C;;;;2BACjBC,S,GAAY,C;;;;6BACZC,W,GAAc,C;;;;oCAGdC,kB,GAAqB,C;;;;iCACrBC,e,GAAkB,C;;;;6BAClBC,W,GAAc,C;;;;6BACdC,W,GAAc,C;;;;0BACdC,Q,GAAW,C;;;;8BACXC,Y,GAAe,C;;;;mCAEfC,iB,GAAoB,CAAC,CAAD,EAAI,CAAJ,C;;;;iCACpBC,e,GAAkB,CAAC,CAAD,EAAI,CAAJ,C;;;;gCAClBC,c,GAAiB,C;;;;iCAGjBC,e,GAAkB,C;;;;8BAClBC,Y,GAAe,C","file":"constants.js","sourcesContent":["// Editor modes\nexport const MODE_METRICS = 0;\nexport const MODE_ITSERVICE = 1;\nexport const MODE_TEXT = 2;\nexport const MODE_ITEMID = 3;\n\n// Triggers severity\nexport const SEV_NOT_CLASSIFIED = 0;\nexport const SEV_INFORMATION = 1;\nexport const SEV_WARNING = 2;\nexport const SEV_AVERAGE = 3;\nexport const SEV_HIGH = 4;\nexport const SEV_DISASTER = 5;\n\nexport const SHOW_ALL_TRIGGERS = [0, 1];\nexport const SHOW_ALL_EVENTS = [0, 1];\nexport const SHOW_OK_EVENTS = 1;\n\n// Data point\nexport const DATAPOINT_VALUE = 0;\nexport const DATAPOINT_TS = 1;\n"]} {"version":3,"sources":["../../src/datasource-zabbix/constants.js"],"names":["MODE_METRICS","MODE_ITSERVICE","MODE_TEXT","MODE_ITEMID","MODE_TRIGGERS","SEV_NOT_CLASSIFIED","SEV_INFORMATION","SEV_WARNING","SEV_AVERAGE","SEV_HIGH","SEV_DISASTER","SHOW_ALL_TRIGGERS","SHOW_ALL_EVENTS","SHOW_OK_EVENTS","DATAPOINT_VALUE","DATAPOINT_TS","TRIGGER_SEVERITY","val","text"],"mappings":";;;;;;;;;8BACaA,Y,GAAe,C;;;;gCACfC,c,GAAiB,C;;;;2BACjBC,S,GAAY,C;;;;6BACZC,W,GAAc,C;;;;+BACdC,a,GAAgB,C;;;;oCAGhBC,kB,GAAqB,C;;;;iCACrBC,e,GAAkB,C;;;;6BAClBC,W,GAAc,C;;;;6BACdC,W,GAAc,C;;;;0BACdC,Q,GAAW,C;;;;8BACXC,Y,GAAe,C;;;;mCAEfC,iB,GAAoB,CAAC,CAAD,EAAI,CAAJ,C;;;;iCACpBC,e,GAAkB,CAAC,CAAD,EAAI,CAAJ,C;;;;gCAClBC,c,GAAiB,C;;;;iCAGjBC,e,GAAkB,C;;;;8BAClBC,Y,GAAe,C;;;;kCAEfC,gB,GAAmB,CAC9B,EAACC,KAAK,CAAN,EAASC,MAAM,gBAAf,EAD8B,EAE9B,EAACD,KAAK,CAAN,EAASC,MAAM,aAAf,EAF8B,EAG9B,EAACD,KAAK,CAAN,EAASC,MAAM,SAAf,EAH8B,EAI9B,EAACD,KAAK,CAAN,EAASC,MAAM,SAAf,EAJ8B,EAK9B,EAACD,KAAK,CAAN,EAASC,MAAM,MAAf,EAL8B,EAM9B,EAACD,KAAK,CAAN,EAASC,MAAM,UAAf,EAN8B,C","file":"constants.js","sourcesContent":["// Editor modes\nexport const MODE_METRICS = 0;\nexport const MODE_ITSERVICE = 1;\nexport const MODE_TEXT = 2;\nexport const MODE_ITEMID = 3;\nexport const MODE_TRIGGERS = 4;\n\n// Triggers severity\nexport const SEV_NOT_CLASSIFIED = 0;\nexport const SEV_INFORMATION = 1;\nexport const SEV_WARNING = 2;\nexport const SEV_AVERAGE = 3;\nexport const SEV_HIGH = 4;\nexport const SEV_DISASTER = 5;\n\nexport const SHOW_ALL_TRIGGERS = [0, 1];\nexport const SHOW_ALL_EVENTS = [0, 1];\nexport const SHOW_OK_EVENTS = 1;\n\n// Data point\nexport const DATAPOINT_VALUE = 0;\nexport const DATAPOINT_TS = 1;\n\nexport const TRIGGER_SEVERITY = [\n {val: 0, text: 'Not classified'},\n {val: 1, text: 'Information'},\n {val: 2, text: 'Warning'},\n {val: 3, text: 'Average'},\n {val: 4, text: 'High'},\n {val: 5, text: 'Disaster'}\n];\n"]}

View File

@@ -112,7 +112,7 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
} }
function getTriggerThreshold(expression) { function getTriggerThreshold(expression) {
var thresholdPattern = /.*[<>=]{1,2}([\d\.]+)/; var thresholdPattern = /.*[<>]([\d\.]+)/;
var finded_thresholds = expression.match(thresholdPattern); var finded_thresholds = expression.match(thresholdPattern);
if (finded_thresholds && finded_thresholds.length >= 2) { if (finded_thresholds && finded_thresholds.length >= 2) {
var threshold = finded_thresholds[1]; var threshold = finded_thresholds[1];
@@ -220,26 +220,28 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
this.basicAuth = instanceSettings.basicAuth; this.basicAuth = instanceSettings.basicAuth;
this.withCredentials = instanceSettings.withCredentials; this.withCredentials = instanceSettings.withCredentials;
var jsonData = instanceSettings.jsonData;
// Zabbix API credentials // Zabbix API credentials
this.username = instanceSettings.jsonData.username; this.username = jsonData.username;
this.password = instanceSettings.jsonData.password; this.password = jsonData.password;
// Use trends instead history since specified time // Use trends instead history since specified time
this.trends = instanceSettings.jsonData.trends; this.trends = jsonData.trends;
this.trendsFrom = instanceSettings.jsonData.trendsFrom || '7d'; this.trendsFrom = jsonData.trendsFrom || '7d';
this.trendsRange = instanceSettings.jsonData.trendsRange || '4d'; this.trendsRange = jsonData.trendsRange || '4d';
// Set cache update interval // Set cache update interval
var ttl = instanceSettings.jsonData.cacheTTL || '1h'; var ttl = jsonData.cacheTTL || '1h';
this.cacheTTL = utils.parseInterval(ttl); this.cacheTTL = utils.parseInterval(ttl);
// Alerting options // Alerting options
this.alertingEnabled = instanceSettings.jsonData.alerting; this.alertingEnabled = jsonData.alerting;
this.addThresholds = instanceSettings.jsonData.addThresholds; this.addThresholds = jsonData.addThresholds;
this.alertingMinSeverity = instanceSettings.jsonData.alertingMinSeverity || c.SEV_WARNING; this.alertingMinSeverity = jsonData.alertingMinSeverity || c.SEV_WARNING;
// Direct DB Connection options // Direct DB Connection options
var dbConnectionOptions = instanceSettings.jsonData.dbConnection || {}; var dbConnectionOptions = jsonData.dbConnection || {};
this.enableDirectDBConnection = dbConnectionOptions.enable; this.enableDirectDBConnection = dbConnectionOptions.enable;
this.sqlDatasourceId = dbConnectionOptions.datasourceId; this.sqlDatasourceId = dbConnectionOptions.datasourceId;
@@ -335,6 +337,10 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
} else if (target.mode === c.MODE_ITSERVICE) { } else if (target.mode === c.MODE_ITSERVICE) {
// IT services mode // IT services mode
return _this.queryITServiceData(target, timeRange, options); return _this.queryITServiceData(target, timeRange, options);
} else if (target.mode === c.MODE_TRIGGERS) {
return _this.queryTriggersData(target, timeRange);
} else {
return [];
} }
}); });
@@ -556,18 +562,43 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
}); });
}); });
} }
}, {
key: 'queryTriggersData',
value: function queryTriggersData(target, timeRange) {
var _this7 = this;
var _timeRange3 = _slicedToArray(timeRange, 2),
timeFrom = _timeRange3[0],
timeTo = _timeRange3[1];
return this.zabbix.getHostsFromTarget(target).then(function (results) {
var _results = _slicedToArray(results, 2),
hosts = _results[0],
apps = _results[1];
if (hosts.length) {
var hostids = _.map(hosts, 'hostid');
var appids = _.map(apps, 'applicationid');
return _this7.zabbix.getHostAlerts(hostids, appids, target.minSeverity, target.countTriggers, timeFrom, timeTo).then(function (triggers) {
return responseHandler.handleTriggersResponse(triggers, timeRange);
});
} else {
return Promise.resolve([]);
}
});
}
}, { }, {
key: 'testDatasource', key: 'testDatasource',
value: function testDatasource() { value: function testDatasource() {
var _this7 = this; var _this8 = this;
var zabbixVersion = void 0; var zabbixVersion = void 0;
return this.zabbix.getVersion().then(function (version) { return this.zabbix.getVersion().then(function (version) {
zabbixVersion = version; zabbixVersion = version;
return _this7.zabbix.login(); return _this8.zabbix.login();
}).then(function () { }).then(function () {
if (_this7.enableDirectDBConnection) { if (_this8.enableDirectDBConnection) {
return _this7.zabbix.dbConnector.testSQLDataSource(); return _this8.zabbix.dbConnector.testSQLDataSource();
} else { } else {
return Promise.resolve(); return Promise.resolve();
} }
@@ -582,13 +613,13 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
return { return {
status: "error", status: "error",
title: error.message, title: error.message,
message: error.data message: error.message
}; };
} else if (error.data && error.data.message) { } else if (error.data && error.data.message) {
return { return {
status: "error", status: "error",
title: "Connection failed", title: "Connection failed",
message: error.data.message message: "Connection failed: " + error.data.message
}; };
} else { } else {
return { return {
@@ -602,14 +633,14 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
}, { }, {
key: 'metricFindQuery', key: 'metricFindQuery',
value: function metricFindQuery(query) { value: function metricFindQuery(query) {
var _this8 = this; var _this9 = this;
var result = void 0; var result = void 0;
var parts = []; var parts = [];
// Split query. Query structure: group.host.app.item // Split query. Query structure: group.host.app.item
_.each(utils.splitTemplateQuery(query), function (part) { _.each(utils.splitTemplateQuery(query), function (part) {
part = _this8.replaceTemplateVars(part, {}); part = _this9.replaceTemplateVars(part, {});
// Replace wildcard to regex // Replace wildcard to regex
if (part === '*') { if (part === '*') {
@@ -646,7 +677,7 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
}, { }, {
key: 'annotationQuery', key: 'annotationQuery',
value: function annotationQuery(options) { value: function annotationQuery(options) {
var _this9 = this; var _this10 = this;
var timeFrom = Math.ceil(dateMath.parse(options.rangeRaw.from) / 1000); var timeFrom = Math.ceil(dateMath.parse(options.rangeRaw.from) / 1000);
var timeTo = Math.ceil(dateMath.parse(options.rangeRaw.to) / 1000); var timeTo = Math.ceil(dateMath.parse(options.rangeRaw.to) / 1000);
@@ -664,7 +695,7 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
return getTriggers.then(function (triggers) { return getTriggers.then(function (triggers) {
// Filter triggers by description // Filter triggers by description
var triggerName = _this9.replaceTemplateVars(annotation.trigger, {}); var triggerName = _this10.replaceTemplateVars(annotation.trigger, {});
if (utils.isRegex(triggerName)) { if (utils.isRegex(triggerName)) {
triggers = _.filter(triggers, function (trigger) { triggers = _.filter(triggers, function (trigger) {
return utils.buildRegex(triggerName).test(trigger.description); return utils.buildRegex(triggerName).test(trigger.description);
@@ -681,7 +712,7 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
}); });
var objectids = _.map(triggers, 'triggerid'); var objectids = _.map(triggers, 'triggerid');
return _this9.zabbix.getEvents(objectids, timeFrom, timeTo, showOkEvents).then(function (events) { return _this10.zabbix.getEvents(objectids, timeFrom, timeTo, showOkEvents).then(function (events) {
var indexedTriggers = _.keyBy(triggers, 'triggerid'); var indexedTriggers = _.keyBy(triggers, 'triggerid');
// Hide acknowledged events if option enabled // Hide acknowledged events if option enabled
@@ -715,23 +746,23 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
}, { }, {
key: 'alertQuery', key: 'alertQuery',
value: function alertQuery(options) { value: function alertQuery(options) {
var _this10 = this; var _this11 = this;
var enabled_targets = filterEnabledTargets(options.targets); var enabled_targets = filterEnabledTargets(options.targets);
var getPanelItems = _.map(enabled_targets, function (t) { var getPanelItems = _.map(enabled_targets, function (t) {
var target = _.cloneDeep(t); var target = _.cloneDeep(t);
_this10.replaceTargetVariables(target, options); _this11.replaceTargetVariables(target, options);
return _this10.zabbix.getItemsFromTarget(target, { itemtype: 'num' }); return _this11.zabbix.getItemsFromTarget(target, { itemtype: 'num' });
}); });
return Promise.all(getPanelItems).then(function (results) { return Promise.all(getPanelItems).then(function (results) {
var items = _.flatten(results); var items = _.flatten(results);
var itemids = _.map(items, 'itemid'); var itemids = _.map(items, 'itemid');
return _this10.zabbix.getAlerts(itemids); return _this11.zabbix.getAlerts(itemids);
}).then(function (triggers) { }).then(function (triggers) {
triggers = _.filter(triggers, function (trigger) { triggers = _.filter(triggers, function (trigger) {
return trigger.priority >= _this10.alertingMinSeverity; return trigger.priority >= _this11.alertingMinSeverity;
}); });
if (!triggers || triggers.length === 0) { if (!triggers || triggers.length === 0) {
@@ -759,12 +790,12 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
}, { }, {
key: 'replaceTargetVariables', key: 'replaceTargetVariables',
value: function replaceTargetVariables(target, options) { value: function replaceTargetVariables(target, options) {
var _this11 = this; var _this12 = this;
var parts = ['group', 'host', 'application', 'item']; var parts = ['group', 'host', 'application', 'item'];
_.forEach(parts, function (p) { _.forEach(parts, function (p) {
if (target[p] && target[p].filter) { if (target[p] && target[p].filter) {
target[p].filter = _this11.replaceTemplateVars(target[p].filter, options.scopedVars); target[p].filter = _this12.replaceTemplateVars(target[p].filter, options.scopedVars);
} }
}); });
target.textFilter = this.replaceTemplateVars(target.textFilter, options.scopedVars); target.textFilter = this.replaceTemplateVars(target.textFilter, options.scopedVars);
@@ -772,9 +803,9 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
_.forEach(target.functions, function (func) { _.forEach(target.functions, function (func) {
func.params = _.map(func.params, function (param) { func.params = _.map(func.params, function (param) {
if (typeof param === 'number') { if (typeof param === 'number') {
return +_this11.templateSrv.replace(param.toString(), options.scopedVars); return +_this12.templateSrv.replace(param.toString(), options.scopedVars);
} else { } else {
return _this11.templateSrv.replace(param, options.scopedVars); return _this12.templateSrv.replace(param, options.scopedVars);
} }
}); });
}); });
@@ -782,9 +813,9 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
}, { }, {
key: 'isUseTrends', key: 'isUseTrends',
value: function isUseTrends(timeRange) { value: function isUseTrends(timeRange) {
var _timeRange3 = _slicedToArray(timeRange, 2), var _timeRange4 = _slicedToArray(timeRange, 2),
timeFrom = _timeRange3[0], timeFrom = _timeRange4[0],
timeTo = _timeRange3[1]; timeTo = _timeRange4[1];
var useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000); var useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000);
var useTrendsRange = Math.ceil(utils.parseInterval(this.trendsRange) / 1000); var useTrendsRange = Math.ceil(utils.parseInterval(this.trendsRange) / 1000);

File diff suppressed because one or more lines are too long

View File

@@ -48,7 +48,7 @@
</div> </div>
</div> </div>
<div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT"> <div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT || ctrl.target.mode == editorMode.TRIGGERS">
<!-- Select Group --> <!-- Select Group -->
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-7">Group</label> <label class="gf-form-label query-keyword width-7">Group</label>
@@ -66,7 +66,7 @@
</div> </div>
<!-- Select Host --> <!-- Select Host -->
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label query-keyword width-7">Host</label> <label class="gf-form-label query-keyword width-8">Host</label>
<input type="text" <input type="text"
ng-model="ctrl.target.host.filter" ng-model="ctrl.target.host.filter"
bs-typeahead="ctrl.getHostNames" bs-typeahead="ctrl.getHostNames"
@@ -85,7 +85,7 @@
</div> </div>
</div> </div>
<div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT"> <div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT || ctrl.target.mode == editorMode.TRIGGERS">
<!-- Select Application --> <!-- Select Application -->
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-7">Application</label> <label class="gf-form-label query-keyword width-7">Application</label>
@@ -103,8 +103,8 @@
</div> </div>
<!-- Select Item --> <!-- Select Item -->
<div class="gf-form"> <div class="gf-form" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT">
<label class="gf-form-label query-keyword width-7">Item</label> <label class="gf-form-label query-keyword width-8">Item</label>
<input type="text" <input type="text"
ng-model="ctrl.target.item.filter" ng-model="ctrl.target.item.filter"
bs-typeahead="ctrl.getItemNames" bs-typeahead="ctrl.getItemNames"
@@ -117,9 +117,25 @@
'zbx-regex': ctrl.isRegex(ctrl.target.item.filter) 'zbx-regex': ctrl.isRegex(ctrl.target.item.filter)
}"> }">
</div> </div>
<div class="gf-form max-width-23" ng-show="ctrl.target.mode == editorMode.TRIGGERS">
<label class="gf-form-label query-keyword width-8">Min Severity</label>
<div class="gf-form-select-wrapper width-16">
<select class="gf-form-input"
ng-change="ctrl.onTargetBlur()"
ng-model="ctrl.target.minSeverity"
ng-options="s.val as s.text for s in ctrl.triggerSeverity">
</select>
</div>
</div>
<gf-form-switch class="gf-form" label="Count" ng-show="ctrl.target.mode == editorMode.TRIGGERS"
checked="ctrl.target.countTriggers" on-change="ctrl.onTargetBlur()">
</gf-form-switch>
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<label class="gf-form-label gf-form-label--grow"> <label class="gf-form-label gf-form-label--grow">
<a ng-click="ctrl.toggleQueryOptions()"> <a ng-click="ctrl.toggleQueryOptions()" ng-hide="ctrl.target.mode == editorMode.TRIGGERS">
<i class="fa fa-caret-down" ng-show="ctrl.showQueryOptions"></i> <i class="fa fa-caret-down" ng-show="ctrl.showQueryOptions"></i>
<i class="fa fa-caret-right" ng-hide="ctrl.showQueryOptions"></i> <i class="fa fa-caret-right" ng-hide="ctrl.showQueryOptions"></i>
{{ctrl.queryOptionsText}} {{ctrl.queryOptionsText}}
@@ -130,7 +146,7 @@
<!-- Query options --> <!-- Query options -->
<div class="gf-form-group" ng-if="ctrl.showQueryOptions"> <div class="gf-form-group" ng-if="ctrl.showQueryOptions">
<div class="gf-form offset-width-7"> <div class="gf-form offset-width-7" ng-hide="ctrl.target.mode == editorMode.TRIGGERS">
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label="Show disabled items" label="Show disabled items"
checked="ctrl.target.options.showDisabledItems" checked="ctrl.target.options.showDisabledItems"

View File

@@ -3,6 +3,19 @@
"name": "Zabbix", "name": "Zabbix",
"id": "alexanderzobnin-zabbix-datasource", "id": "alexanderzobnin-zabbix-datasource",
"includes": [
{
"type": "dashboard",
"name": "Zabbix System Status",
"path": "../dashboards/zabbix_system_status.json"
},
{
"type": "dashboard",
"name": "Zabbix Template Linux Server",
"path": "../dashboards/template_linux_server.json"
}
],
"metrics": true, "metrics": true,
"annotations": true, "annotations": true,

View File

@@ -83,17 +83,20 @@ System.register(['app/plugins/sdk', 'lodash', './constants', './utils', './metri
_this.replaceTemplateVars = _this.datasource.replaceTemplateVars; _this.replaceTemplateVars = _this.datasource.replaceTemplateVars;
_this.templateSrv = templateSrv; _this.templateSrv = templateSrv;
_this.editorModes = [{ value: 'num', text: 'Metrics', mode: c.MODE_METRICS }, { value: 'text', text: 'Text', mode: c.MODE_TEXT }, { value: 'itservice', text: 'IT Services', mode: c.MODE_ITSERVICE }, { value: 'itemid', text: 'Item ID', mode: c.MODE_ITEMID }]; _this.editorModes = [{ value: 'num', text: 'Metrics', mode: c.MODE_METRICS }, { value: 'text', text: 'Text', mode: c.MODE_TEXT }, { value: 'itservice', text: 'IT Services', mode: c.MODE_ITSERVICE }, { value: 'itemid', text: 'Item ID', mode: c.MODE_ITEMID }, { value: 'triggers', text: 'Triggers', mode: c.MODE_TRIGGERS }];
_this.$scope.editorMode = { _this.$scope.editorMode = {
METRICS: c.MODE_METRICS, METRICS: c.MODE_METRICS,
TEXT: c.MODE_TEXT, TEXT: c.MODE_TEXT,
ITSERVICE: c.MODE_ITSERVICE, ITSERVICE: c.MODE_ITSERVICE,
ITEMID: c.MODE_ITEMID ITEMID: c.MODE_ITEMID,
TRIGGERS: c.MODE_TRIGGERS
}; };
_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.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.triggerSeverity = c.TRIGGER_SEVERITY;
// Map functions for bs-typeahead // Map functions for bs-typeahead
_this.getGroupNames = _.bind(_this.getMetricNames, _this, 'groupList'); _this.getGroupNames = _.bind(_this.getMetricNames, _this, 'groupList');
_this.getHostNames = _.bind(_this.getMetricNames, _this, 'hostList', true); _this.getHostNames = _.bind(_this.getMetricNames, _this, 'hostList', true);
@@ -133,6 +136,8 @@ System.register(['app/plugins/sdk', 'lodash', './constants', './utils', './metri
'application': { 'filter': "" }, 'application': { 'filter': "" },
'item': { 'filter': "" }, 'item': { 'filter': "" },
'functions': [], 'functions': [],
'minSeverity': 3,
'countTriggers': true,
'options': { 'options': {
'showDisabledItems': false 'showDisabledItems': false
} }
@@ -144,8 +149,7 @@ System.register(['app/plugins/sdk', 'lodash', './constants', './utils', './metri
return metricFunctions.createFuncInstance(func.def, func.params); return metricFunctions.createFuncInstance(func.def, func.params);
}); });
if (target.mode === c.MODE_METRICS || target.mode === c.MODE_TEXT) { if (target.mode === c.MODE_METRICS || target.mode === c.MODE_TEXT || target.mode === c.MODE_TRIGGERS) {
this.initFilters(); this.initFilters();
} else if (target.mode === c.MODE_ITSERVICE) { } else if (target.mode === c.MODE_ITSERVICE) {
_.defaults(target, { slaProperty: { name: "SLA", property: "sla" } }); _.defaults(target, { slaProperty: { name: "SLA", property: "sla" } });
@@ -154,6 +158,7 @@ System.register(['app/plugins/sdk', 'lodash', './constants', './utils', './metri
}; };
_this.init(); _this.init();
_this.queryOptionsText = _this.renderQueryOptionsText();
return _this; return _this;
} }

File diff suppressed because one or more lines are too long

View File

@@ -26,3 +26,6 @@ This mode is suitable for rendering charts in grafana by passing itemids as url
1. Save dashboard. 1. Save dashboard.
1. Click to graph title and select _Share_ -> _Direct link rendered image_. 1. Click to graph title and select _Share_ -> _Direct link rendered image_.
1. Use this URL for graph png image and set `var-itemids` param to desired IDs. Note, for multiple IDs you should pass multiple params, like `&var-itemids=28276&var-itemids=28277`. 1. Use this URL for graph png image and set `var-itemids` param to desired IDs. Note, for multiple IDs you should pass multiple params, like `&var-itemids=28276&var-itemids=28277`.
##### Triggers
Active triggers count for selected hosts or table data like Zabbix _System status_ panel on the main dashboard.

View File

@@ -1,9 +1,21 @@
'use strict'; 'use strict';
System.register(['lodash'], function (_export, _context) { System.register(['lodash', 'app/core/table_model', './constants'], function (_export, _context) {
"use strict"; "use strict";
var _; var _, TableModel, c;
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);
}
}
/** /**
* Convert Zabbix API history.get response to Grafana format * Convert Zabbix API history.get response to Grafana format
@@ -98,6 +110,47 @@ System.register(['lodash'], function (_export, _context) {
} }
} }
function handleTriggersResponse(triggers, timeRange) {
if (_.isNumber(triggers)) {
return {
target: "triggers count",
datapoints: [[triggers, timeRange[1] * 1000]]
};
} else {
var stats = getTriggerStats(triggers);
var table = new TableModel();
table.addColumn({ text: 'Host group' });
_.each(_.orderBy(c.TRIGGER_SEVERITY, ['val'], ['desc']), function (severity) {
table.addColumn({ text: severity.text });
});
_.each(stats, function (severity_stats, group) {
var row = _.map(_.orderBy(_.toPairs(severity_stats), function (s) {
return s[0];
}, ['desc']), function (s) {
return s[1];
});
row = _.concat.apply(_, [[group]].concat(_toConsumableArray(row)));
table.rows.push(row);
});
return table;
}
}function getTriggerStats(triggers) {
var groups = _.uniq(_.flattenDeep(_.map(triggers, function (trigger) {
return _.map(trigger.groups, 'name');
})));
// let severity = _.map(c.TRIGGER_SEVERITY, 'text');
var stats = {};
_.each(groups, function (group) {
stats[group] = { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 }; // severity:count
});
_.each(triggers, function (trigger) {
_.each(trigger.groups, function (group) {
stats[group.name][trigger.priority]++;
});
});
return stats;
}
function convertHistoryPoint(point) { function convertHistoryPoint(point) {
// Value must be a number for properly work // Value must be a number for properly work
return [Number(point.value), point.clock * 1000 + Math.round(point.ns / 1000000)]; return [Number(point.value), point.clock * 1000 + Math.round(point.ns / 1000000)];
@@ -129,6 +182,10 @@ System.register(['lodash'], function (_export, _context) {
return { return {
setters: [function (_lodash) { setters: [function (_lodash) {
_ = _lodash.default; _ = _lodash.default;
}, function (_appCoreTable_model) {
TableModel = _appCoreTable_model.default;
}, function (_constants) {
c = _constants;
}], }],
execute: function () { execute: function () {
_export('default', { _export('default', {
@@ -136,7 +193,8 @@ System.register(['lodash'], function (_export, _context) {
convertHistory: convertHistory, convertHistory: convertHistory,
handleTrends: handleTrends, handleTrends: handleTrends,
handleText: handleText, handleText: handleText,
handleSLAResponse: handleSLAResponse handleSLAResponse: handleSLAResponse,
handleTriggersResponse: handleTriggersResponse
}); });
// Fix for backward compatibility with lodash 2.4 // Fix for backward compatibility with lodash 2.4

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@
/* globals global: false */ /* globals global: false */
import prunk from 'prunk'; import prunk from 'prunk';
import {JSDOM} from 'jsdom'; import {jsdom} from 'jsdom';
import chai from 'chai'; import chai from 'chai';
// import sinon from 'sinon'; // import sinon from 'sinon';
import sinonChai from 'sinon-chai'; import sinonChai from 'sinon-chai';
@@ -32,14 +32,15 @@ prunk.mock('app/plugins/sdk', {
QueryCtrl: null QueryCtrl: null
}); });
prunk.mock('app/core/utils/datemath', datemathMock); prunk.mock('app/core/utils/datemath', datemathMock);
prunk.mock('app/core/table_model', {});
prunk.mock('angular', angularMocks); prunk.mock('angular', angularMocks);
prunk.mock('jquery', 'module not found'); prunk.mock('jquery', 'module not found');
// Required for loading angularjs
let dom = new JSDOM('<html><head><script></script></head><body></body></html>');
// Setup jsdom // Setup jsdom
global.window = dom.window; // Required for loading angularjs
global.document = global.window.document; global.document = jsdom('<html><head><script></script></head><body></body></html>');
global.window = global.document.parentWindow;
global.navigator = window.navigator = {};
global.Node = window.Node; global.Node = window.Node;
// Setup Chai // Setup Chai

View File

@@ -3,7 +3,7 @@
System.register(['angular', 'lodash', './utils', './zabbixAPI.service.js', './zabbixCachingProxy.service.js', './zabbixDBConnector'], function (_export, _context) { System.register(['angular', 'lodash', './utils', './zabbixAPI.service.js', './zabbixCachingProxy.service.js', './zabbixDBConnector'], function (_export, _context) {
"use strict"; "use strict";
var angular, _, utils, _createClass; var angular, _, utils, _slicedToArray, _createClass;
function _toConsumableArray(arr) { function _toConsumableArray(arr) {
if (Array.isArray(arr)) { if (Array.isArray(arr)) {
@@ -69,6 +69,7 @@ System.register(['angular', 'lodash', './utils', './zabbixAPI.service.js', './za
this.getTrend = this.zabbixAPI.getTrend.bind(this.zabbixAPI); this.getTrend = this.zabbixAPI.getTrend.bind(this.zabbixAPI);
this.getEvents = this.zabbixAPI.getEvents.bind(this.zabbixAPI); this.getEvents = this.zabbixAPI.getEvents.bind(this.zabbixAPI);
this.getAlerts = this.zabbixAPI.getAlerts.bind(this.zabbixAPI); this.getAlerts = this.zabbixAPI.getAlerts.bind(this.zabbixAPI);
this.getHostAlerts = this.zabbixAPI.getHostAlerts.bind(this.zabbixAPI);
this.getAcknowledges = this.zabbixAPI.getAcknowledges.bind(this.zabbixAPI); this.getAcknowledges = this.zabbixAPI.getAcknowledges.bind(this.zabbixAPI);
this.getITService = this.zabbixAPI.getITService.bind(this.zabbixAPI); this.getITService = this.zabbixAPI.getITService.bind(this.zabbixAPI);
this.getSLA = this.zabbixAPI.getSLA.bind(this.zabbixAPI); this.getSLA = this.zabbixAPI.getSLA.bind(this.zabbixAPI);
@@ -85,6 +86,24 @@ System.register(['angular', 'lodash', './utils', './zabbixAPI.service.js', './za
}); });
return this.getItems.apply(this, _toConsumableArray(filters).concat([options])); return this.getItems.apply(this, _toConsumableArray(filters).concat([options]));
} }
}, {
key: 'getHostsFromTarget',
value: function getHostsFromTarget(target) {
var parts = ['group', 'host', 'application'];
var filters = _.map(parts, function (p) {
return target[p].filter;
});
return Promise.all([this.getHosts.apply(this, _toConsumableArray(filters)), this.getApps.apply(this, _toConsumableArray(filters))]).then(function (results) {
var _results = _slicedToArray(results, 2),
hosts = _results[0],
apps = _results[1];
if (apps.appFilterEmpty) {
apps = [];
}
return [hosts, apps];
});
}
}, { }, {
key: 'getAllGroups', key: 'getAllGroups',
value: function getAllGroups() { value: function getAllGroups() {
@@ -302,6 +321,44 @@ System.register(['angular', 'lodash', './utils', './zabbixAPI.service.js', './za
utils = _utils; utils = _utils;
}, function (_zabbixAPIServiceJs) {}, function (_zabbixCachingProxyServiceJs) {}, function (_zabbixDBConnector) {}], }, function (_zabbixAPIServiceJs) {}, function (_zabbixCachingProxyServiceJs) {}, function (_zabbixDBConnector) {}],
execute: function () { 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 () { _createClass = function () {
function defineProperties(target, props) { function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) { for (var i = 0; i < props.length; i++) {

File diff suppressed because one or more lines are too long

View File

@@ -411,6 +411,39 @@ System.register(['angular', 'lodash', './utils', './zabbixAPICore.service'], fun
params.lastChangeTill = timeTo; params.lastChangeTill = timeTo;
} }
return this.request('trigger.get', params);
}
}, {
key: 'getHostAlerts',
value: function getHostAlerts(hostids, applicationids, minSeverity, count, timeFrom, timeTo) {
var params = {
output: 'extend',
hostids: hostids,
min_severity: minSeverity,
filter: { value: 1 },
expandDescription: true,
expandData: true,
expandComment: true,
monitored: true,
skipDependent: true,
selectLastEvent: 'extend',
selectGroups: 'extend',
selectHosts: ['host', 'name']
};
if (count) {
params.countOutput = true;
}
if (applicationids && applicationids.length) {
params.applicationids = applicationids;
}
if (timeFrom || timeTo) {
params.lastChangeSince = timeFrom;
params.lastChangeTill = timeTo;
}
return this.request('trigger.get', params); return this.request('trigger.get', params);
} }
}]); }]);

File diff suppressed because one or more lines are too long

View File

@@ -100,8 +100,6 @@ System.register(['angular'], function (_export, _context) {
// Success // Success
return response.data.result; return response.data.result;
}).catch(function () {
return Promise.reject(new ZabbixAPIError({ data: "Connection Error" }));
}); });
} }
}, { }, {
@@ -127,16 +125,16 @@ System.register(['angular'], function (_export, _context) {
function ZabbixAPIError(error) { function ZabbixAPIError(error) {
_classCallCheck(this, ZabbixAPIError); _classCallCheck(this, ZabbixAPIError);
this.code = error.code; this.code = error.code || null;
this.name = error.data; this.name = error.message || "";
this.message = error.data; this.data = error.data || "";
this.data = error.data; this.message = "Zabbix API Error: " + this.name + " " + this.data;
} }
_createClass(ZabbixAPIError, [{ _createClass(ZabbixAPIError, [{
key: 'toString', key: 'toString',
value: function toString() { value: function toString() {
return this.name + ": " + this.message; return this.name + " " + this.data;
} }
}]); }]);

File diff suppressed because one or more lines are too long

10
dist/plugin.json vendored
View File

@@ -26,8 +26,8 @@
{"name": "Metric Editor", "path": "img/screenshot-metric_editor.png"}, {"name": "Metric Editor", "path": "img/screenshot-metric_editor.png"},
{"name": "Triggers", "path": "img/screenshot-triggers.png"} {"name": "Triggers", "path": "img/screenshot-triggers.png"}
], ],
"version": "3.6.1", "version": "3.7.0",
"updated": "2017-07-26" "updated": "2017-10-22"
}, },
"includes": [ "includes": [
@@ -45,12 +45,6 @@
"path": "dashboards/zabbix_server_dashboard.json", "path": "dashboards/zabbix_server_dashboard.json",
"addToNav": true, "addToNav": true,
"defaultNav": true "defaultNav": true
},
{
"type": "dashboard",
"name": "Template Linux Server",
"path": "dashboards/template_linux_server.json",
"addToNav": true
} }
], ],

View File

@@ -1,4 +1,4 @@
"use strict"; 'use strict';
Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "__esModule", {
value: true value: true
@@ -8,6 +8,7 @@ var MODE_METRICS = exports.MODE_METRICS = 0;
var MODE_ITSERVICE = exports.MODE_ITSERVICE = 1; var MODE_ITSERVICE = exports.MODE_ITSERVICE = 1;
var MODE_TEXT = exports.MODE_TEXT = 2; var MODE_TEXT = exports.MODE_TEXT = 2;
var MODE_ITEMID = exports.MODE_ITEMID = 3; var MODE_ITEMID = exports.MODE_ITEMID = 3;
var MODE_TRIGGERS = exports.MODE_TRIGGERS = 4;
// Triggers severity // Triggers severity
var SEV_NOT_CLASSIFIED = exports.SEV_NOT_CLASSIFIED = 0; var SEV_NOT_CLASSIFIED = exports.SEV_NOT_CLASSIFIED = 0;
@@ -24,3 +25,5 @@ var SHOW_OK_EVENTS = exports.SHOW_OK_EVENTS = 1;
// Data point // Data point
var DATAPOINT_VALUE = exports.DATAPOINT_VALUE = 0; var DATAPOINT_VALUE = exports.DATAPOINT_VALUE = 0;
var DATAPOINT_TS = exports.DATAPOINT_TS = 1; var DATAPOINT_TS = exports.DATAPOINT_TS = 1;
var TRIGGER_SEVERITY = exports.TRIGGER_SEVERITY = [{ val: 0, text: 'Not classified' }, { val: 1, text: 'Information' }, { val: 2, text: 'Warning' }, { val: 3, text: 'Average' }, { val: 4, text: 'High' }, { val: 5, text: 'Disaster' }];

View File

@@ -73,26 +73,28 @@ var ZabbixAPIDatasource = function () {
this.basicAuth = instanceSettings.basicAuth; this.basicAuth = instanceSettings.basicAuth;
this.withCredentials = instanceSettings.withCredentials; this.withCredentials = instanceSettings.withCredentials;
var jsonData = instanceSettings.jsonData;
// Zabbix API credentials // Zabbix API credentials
this.username = instanceSettings.jsonData.username; this.username = jsonData.username;
this.password = instanceSettings.jsonData.password; this.password = jsonData.password;
// Use trends instead history since specified time // Use trends instead history since specified time
this.trends = instanceSettings.jsonData.trends; this.trends = jsonData.trends;
this.trendsFrom = instanceSettings.jsonData.trendsFrom || '7d'; this.trendsFrom = jsonData.trendsFrom || '7d';
this.trendsRange = instanceSettings.jsonData.trendsRange || '4d'; this.trendsRange = jsonData.trendsRange || '4d';
// Set cache update interval // Set cache update interval
var ttl = instanceSettings.jsonData.cacheTTL || '1h'; var ttl = jsonData.cacheTTL || '1h';
this.cacheTTL = utils.parseInterval(ttl); this.cacheTTL = utils.parseInterval(ttl);
// Alerting options // Alerting options
this.alertingEnabled = instanceSettings.jsonData.alerting; this.alertingEnabled = jsonData.alerting;
this.addThresholds = instanceSettings.jsonData.addThresholds; this.addThresholds = jsonData.addThresholds;
this.alertingMinSeverity = instanceSettings.jsonData.alertingMinSeverity || c.SEV_WARNING; this.alertingMinSeverity = jsonData.alertingMinSeverity || c.SEV_WARNING;
// Direct DB Connection options // Direct DB Connection options
var dbConnectionOptions = instanceSettings.jsonData.dbConnection || {}; var dbConnectionOptions = jsonData.dbConnection || {};
this.enableDirectDBConnection = dbConnectionOptions.enable; this.enableDirectDBConnection = dbConnectionOptions.enable;
this.sqlDatasourceId = dbConnectionOptions.datasourceId; this.sqlDatasourceId = dbConnectionOptions.datasourceId;
@@ -188,6 +190,10 @@ var ZabbixAPIDatasource = function () {
} else if (target.mode === c.MODE_ITSERVICE) { } else if (target.mode === c.MODE_ITSERVICE) {
// IT services mode // IT services mode
return _this.queryITServiceData(target, timeRange, options); return _this.queryITServiceData(target, timeRange, options);
} else if (target.mode === c.MODE_TRIGGERS) {
return _this.queryTriggersData(target, timeRange);
} else {
return [];
} }
}); });
@@ -434,6 +440,31 @@ var ZabbixAPIDatasource = function () {
}); });
}); });
} }
}, {
key: 'queryTriggersData',
value: function queryTriggersData(target, timeRange) {
var _this7 = this;
var _timeRange3 = _slicedToArray(timeRange, 2),
timeFrom = _timeRange3[0],
timeTo = _timeRange3[1];
return this.zabbix.getHostsFromTarget(target).then(function (results) {
var _results = _slicedToArray(results, 2),
hosts = _results[0],
apps = _results[1];
if (hosts.length) {
var hostids = _lodash2.default.map(hosts, 'hostid');
var appids = _lodash2.default.map(apps, 'applicationid');
return _this7.zabbix.getHostAlerts(hostids, appids, target.minSeverity, target.countTriggers, timeFrom, timeTo).then(function (triggers) {
return _responseHandler2.default.handleTriggersResponse(triggers, timeRange);
});
} else {
return Promise.resolve([]);
}
});
}
/** /**
* Test connection to Zabbix API * Test connection to Zabbix API
@@ -443,15 +474,15 @@ var ZabbixAPIDatasource = function () {
}, { }, {
key: 'testDatasource', key: 'testDatasource',
value: function testDatasource() { value: function testDatasource() {
var _this7 = this; var _this8 = this;
var zabbixVersion = void 0; var zabbixVersion = void 0;
return this.zabbix.getVersion().then(function (version) { return this.zabbix.getVersion().then(function (version) {
zabbixVersion = version; zabbixVersion = version;
return _this7.zabbix.login(); return _this8.zabbix.login();
}).then(function () { }).then(function () {
if (_this7.enableDirectDBConnection) { if (_this8.enableDirectDBConnection) {
return _this7.zabbix.dbConnector.testSQLDataSource(); return _this8.zabbix.dbConnector.testSQLDataSource();
} else { } else {
return Promise.resolve(); return Promise.resolve();
} }
@@ -466,13 +497,13 @@ var ZabbixAPIDatasource = function () {
return { return {
status: "error", status: "error",
title: error.message, title: error.message,
message: error.data message: error.message
}; };
} else if (error.data && error.data.message) { } else if (error.data && error.data.message) {
return { return {
status: "error", status: "error",
title: "Connection failed", title: "Connection failed",
message: error.data.message message: "Connection failed: " + error.data.message
}; };
} else { } else {
return { return {
@@ -499,14 +530,14 @@ var ZabbixAPIDatasource = function () {
}, { }, {
key: 'metricFindQuery', key: 'metricFindQuery',
value: function metricFindQuery(query) { value: function metricFindQuery(query) {
var _this8 = this; var _this9 = this;
var result = void 0; var result = void 0;
var parts = []; var parts = [];
// Split query. Query structure: group.host.app.item // Split query. Query structure: group.host.app.item
_lodash2.default.each(utils.splitTemplateQuery(query), function (part) { _lodash2.default.each(utils.splitTemplateQuery(query), function (part) {
part = _this8.replaceTemplateVars(part, {}); part = _this9.replaceTemplateVars(part, {});
// Replace wildcard to regex // Replace wildcard to regex
if (part === '*') { if (part === '*') {
@@ -548,7 +579,7 @@ var ZabbixAPIDatasource = function () {
}, { }, {
key: 'annotationQuery', key: 'annotationQuery',
value: function annotationQuery(options) { value: function annotationQuery(options) {
var _this9 = this; var _this10 = this;
var timeFrom = Math.ceil(dateMath.parse(options.rangeRaw.from) / 1000); var timeFrom = Math.ceil(dateMath.parse(options.rangeRaw.from) / 1000);
var timeTo = Math.ceil(dateMath.parse(options.rangeRaw.to) / 1000); var timeTo = Math.ceil(dateMath.parse(options.rangeRaw.to) / 1000);
@@ -566,7 +597,7 @@ var ZabbixAPIDatasource = function () {
return getTriggers.then(function (triggers) { return getTriggers.then(function (triggers) {
// Filter triggers by description // Filter triggers by description
var triggerName = _this9.replaceTemplateVars(annotation.trigger, {}); var triggerName = _this10.replaceTemplateVars(annotation.trigger, {});
if (utils.isRegex(triggerName)) { if (utils.isRegex(triggerName)) {
triggers = _lodash2.default.filter(triggers, function (trigger) { triggers = _lodash2.default.filter(triggers, function (trigger) {
return utils.buildRegex(triggerName).test(trigger.description); return utils.buildRegex(triggerName).test(trigger.description);
@@ -583,7 +614,7 @@ var ZabbixAPIDatasource = function () {
}); });
var objectids = _lodash2.default.map(triggers, 'triggerid'); var objectids = _lodash2.default.map(triggers, 'triggerid');
return _this9.zabbix.getEvents(objectids, timeFrom, timeTo, showOkEvents).then(function (events) { return _this10.zabbix.getEvents(objectids, timeFrom, timeTo, showOkEvents).then(function (events) {
var indexedTriggers = _lodash2.default.keyBy(triggers, 'triggerid'); var indexedTriggers = _lodash2.default.keyBy(triggers, 'triggerid');
// Hide acknowledged events if option enabled // Hide acknowledged events if option enabled
@@ -624,23 +655,23 @@ var ZabbixAPIDatasource = function () {
}, { }, {
key: 'alertQuery', key: 'alertQuery',
value: function alertQuery(options) { value: function alertQuery(options) {
var _this10 = this; var _this11 = this;
var enabled_targets = filterEnabledTargets(options.targets); var enabled_targets = filterEnabledTargets(options.targets);
var getPanelItems = _lodash2.default.map(enabled_targets, function (t) { var getPanelItems = _lodash2.default.map(enabled_targets, function (t) {
var target = _lodash2.default.cloneDeep(t); var target = _lodash2.default.cloneDeep(t);
_this10.replaceTargetVariables(target, options); _this11.replaceTargetVariables(target, options);
return _this10.zabbix.getItemsFromTarget(target, { itemtype: 'num' }); return _this11.zabbix.getItemsFromTarget(target, { itemtype: 'num' });
}); });
return Promise.all(getPanelItems).then(function (results) { return Promise.all(getPanelItems).then(function (results) {
var items = _lodash2.default.flatten(results); var items = _lodash2.default.flatten(results);
var itemids = _lodash2.default.map(items, 'itemid'); var itemids = _lodash2.default.map(items, 'itemid');
return _this10.zabbix.getAlerts(itemids); return _this11.zabbix.getAlerts(itemids);
}).then(function (triggers) { }).then(function (triggers) {
triggers = _lodash2.default.filter(triggers, function (trigger) { triggers = _lodash2.default.filter(triggers, function (trigger) {
return trigger.priority >= _this10.alertingMinSeverity; return trigger.priority >= _this11.alertingMinSeverity;
}); });
if (!triggers || triggers.length === 0) { if (!triggers || triggers.length === 0) {
@@ -671,12 +702,12 @@ var ZabbixAPIDatasource = function () {
}, { }, {
key: 'replaceTargetVariables', key: 'replaceTargetVariables',
value: function replaceTargetVariables(target, options) { value: function replaceTargetVariables(target, options) {
var _this11 = this; var _this12 = this;
var parts = ['group', 'host', 'application', 'item']; var parts = ['group', 'host', 'application', 'item'];
_lodash2.default.forEach(parts, function (p) { _lodash2.default.forEach(parts, function (p) {
if (target[p] && target[p].filter) { if (target[p] && target[p].filter) {
target[p].filter = _this11.replaceTemplateVars(target[p].filter, options.scopedVars); target[p].filter = _this12.replaceTemplateVars(target[p].filter, options.scopedVars);
} }
}); });
target.textFilter = this.replaceTemplateVars(target.textFilter, options.scopedVars); target.textFilter = this.replaceTemplateVars(target.textFilter, options.scopedVars);
@@ -684,9 +715,9 @@ var ZabbixAPIDatasource = function () {
_lodash2.default.forEach(target.functions, function (func) { _lodash2.default.forEach(target.functions, function (func) {
func.params = _lodash2.default.map(func.params, function (param) { func.params = _lodash2.default.map(func.params, function (param) {
if (typeof param === 'number') { if (typeof param === 'number') {
return +_this11.templateSrv.replace(param.toString(), options.scopedVars); return +_this12.templateSrv.replace(param.toString(), options.scopedVars);
} else { } else {
return _this11.templateSrv.replace(param, options.scopedVars); return _this12.templateSrv.replace(param, options.scopedVars);
} }
}); });
}); });
@@ -694,9 +725,9 @@ var ZabbixAPIDatasource = function () {
}, { }, {
key: 'isUseTrends', key: 'isUseTrends',
value: function isUseTrends(timeRange) { value: function isUseTrends(timeRange) {
var _timeRange3 = _slicedToArray(timeRange, 2), var _timeRange4 = _slicedToArray(timeRange, 2),
timeFrom = _timeRange3[0], timeFrom = _timeRange4[0],
timeTo = _timeRange3[1]; timeTo = _timeRange4[1];
var useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000); var useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000);
var useTrendsRange = Math.ceil(utils.parseInterval(this.trendsRange) / 1000); var useTrendsRange = Math.ceil(utils.parseInterval(this.trendsRange) / 1000);
@@ -809,7 +840,7 @@ function filterEnabledTargets(targets) {
} }
function getTriggerThreshold(expression) { function getTriggerThreshold(expression) {
var thresholdPattern = /.*[<>=]{1,2}([\d\.]+)/; var thresholdPattern = /.*[<>]([\d\.]+)/;
var finded_thresholds = expression.match(thresholdPattern); var finded_thresholds = expression.match(thresholdPattern);
if (finded_thresholds && finded_thresholds.length >= 2) { if (finded_thresholds && finded_thresholds.length >= 2) {
var threshold = finded_thresholds[1]; var threshold = finded_thresholds[1];

View File

@@ -60,17 +60,20 @@ var ZabbixQueryController = exports.ZabbixQueryController = function (_QueryCtrl
_this.replaceTemplateVars = _this.datasource.replaceTemplateVars; _this.replaceTemplateVars = _this.datasource.replaceTemplateVars;
_this.templateSrv = templateSrv; _this.templateSrv = templateSrv;
_this.editorModes = [{ value: 'num', text: 'Metrics', mode: c.MODE_METRICS }, { value: 'text', text: 'Text', mode: c.MODE_TEXT }, { value: 'itservice', text: 'IT Services', mode: c.MODE_ITSERVICE }, { value: 'itemid', text: 'Item ID', mode: c.MODE_ITEMID }]; _this.editorModes = [{ value: 'num', text: 'Metrics', mode: c.MODE_METRICS }, { value: 'text', text: 'Text', mode: c.MODE_TEXT }, { value: 'itservice', text: 'IT Services', mode: c.MODE_ITSERVICE }, { value: 'itemid', text: 'Item ID', mode: c.MODE_ITEMID }, { value: 'triggers', text: 'Triggers', mode: c.MODE_TRIGGERS }];
_this.$scope.editorMode = { _this.$scope.editorMode = {
METRICS: c.MODE_METRICS, METRICS: c.MODE_METRICS,
TEXT: c.MODE_TEXT, TEXT: c.MODE_TEXT,
ITSERVICE: c.MODE_ITSERVICE, ITSERVICE: c.MODE_ITSERVICE,
ITEMID: c.MODE_ITEMID ITEMID: c.MODE_ITEMID,
TRIGGERS: c.MODE_TRIGGERS
}; };
_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.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.triggerSeverity = c.TRIGGER_SEVERITY;
// Map functions for bs-typeahead // Map functions for bs-typeahead
_this.getGroupNames = _lodash2.default.bind(_this.getMetricNames, _this, 'groupList'); _this.getGroupNames = _lodash2.default.bind(_this.getMetricNames, _this, 'groupList');
_this.getHostNames = _lodash2.default.bind(_this.getMetricNames, _this, 'hostList', true); _this.getHostNames = _lodash2.default.bind(_this.getMetricNames, _this, 'hostList', true);
@@ -110,6 +113,8 @@ var ZabbixQueryController = exports.ZabbixQueryController = function (_QueryCtrl
'application': { 'filter': "" }, 'application': { 'filter': "" },
'item': { 'filter': "" }, 'item': { 'filter': "" },
'functions': [], 'functions': [],
'minSeverity': 3,
'countTriggers': true,
'options': { 'options': {
'showDisabledItems': false 'showDisabledItems': false
} }
@@ -121,8 +126,7 @@ var ZabbixQueryController = exports.ZabbixQueryController = function (_QueryCtrl
return metricFunctions.createFuncInstance(func.def, func.params); return metricFunctions.createFuncInstance(func.def, func.params);
}); });
if (target.mode === c.MODE_METRICS || target.mode === c.MODE_TEXT) { if (target.mode === c.MODE_METRICS || target.mode === c.MODE_TEXT || target.mode === c.MODE_TRIGGERS) {
this.initFilters(); this.initFilters();
} else if (target.mode === c.MODE_ITSERVICE) { } else if (target.mode === c.MODE_ITSERVICE) {
_lodash2.default.defaults(target, { slaProperty: { name: "SLA", property: "sla" } }); _lodash2.default.defaults(target, { slaProperty: { name: "SLA", property: "sla" } });
@@ -131,6 +135,7 @@ var ZabbixQueryController = exports.ZabbixQueryController = function (_QueryCtrl
}; };
_this.init(); _this.init();
_this.queryOptionsText = _this.renderQueryOptionsText();
return _this; return _this;
} }

View File

@@ -8,8 +8,20 @@ var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash); var _lodash2 = _interopRequireDefault(_lodash);
var _table_model = require('app/core/table_model');
var _table_model2 = _interopRequireDefault(_table_model);
var _constants = require('./constants');
var c = _interopRequireWildcard(_constants);
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 _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); } }
/** /**
* Convert Zabbix API history.get response to Grafana format * Convert Zabbix API history.get response to Grafana format
* *
@@ -109,6 +121,49 @@ function handleSLAResponse(itservice, slaProperty, slaObject) {
} }
} }
function handleTriggersResponse(triggers, timeRange) {
if (_lodash2.default.isNumber(triggers)) {
return {
target: "triggers count",
datapoints: [[triggers, timeRange[1] * 1000]]
};
} else {
var stats = getTriggerStats(triggers);
var table = new _table_model2.default();
table.addColumn({ text: 'Host group' });
_lodash2.default.each(_lodash2.default.orderBy(c.TRIGGER_SEVERITY, ['val'], ['desc']), function (severity) {
table.addColumn({ text: severity.text });
});
_lodash2.default.each(stats, function (severity_stats, group) {
var row = _lodash2.default.map(_lodash2.default.orderBy(_lodash2.default.toPairs(severity_stats), function (s) {
return s[0];
}, ['desc']), function (s) {
return s[1];
});
row = _lodash2.default.concat.apply(_lodash2.default, [[group]].concat(_toConsumableArray(row)));
table.rows.push(row);
});
return table;
}
}
function getTriggerStats(triggers) {
var groups = _lodash2.default.uniq(_lodash2.default.flattenDeep(_lodash2.default.map(triggers, function (trigger) {
return _lodash2.default.map(trigger.groups, 'name');
})));
// let severity = _.map(c.TRIGGER_SEVERITY, 'text');
var stats = {};
_lodash2.default.each(groups, function (group) {
stats[group] = { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 }; // severity:count
});
_lodash2.default.each(triggers, function (trigger) {
_lodash2.default.each(trigger.groups, function (group) {
stats[group.name][trigger.priority]++;
});
});
return stats;
}
function convertHistoryPoint(point) { function convertHistoryPoint(point) {
// Value must be a number for properly work // Value must be a number for properly work
return [Number(point.value), point.clock * 1000 + Math.round(point.ns / 1000000)]; return [Number(point.value), point.clock * 1000 + Math.round(point.ns / 1000000)];
@@ -144,7 +199,8 @@ exports.default = {
convertHistory: convertHistory, convertHistory: convertHistory,
handleTrends: handleTrends, handleTrends: handleTrends,
handleText: handleText, handleText: handleText,
handleSLAResponse: handleSLAResponse handleSLAResponse: handleSLAResponse,
handleTriggersResponse: handleTriggersResponse
}; };
// Fix for backward compatibility with lodash 2.4 // Fix for backward compatibility with lodash 2.4

View File

@@ -49,14 +49,15 @@ _prunk2.default.mock('app/plugins/sdk', {
QueryCtrl: null QueryCtrl: null
}); });
_prunk2.default.mock('app/core/utils/datemath', datemathMock); _prunk2.default.mock('app/core/utils/datemath', datemathMock);
_prunk2.default.mock('app/core/table_model', {});
_prunk2.default.mock('angular', angularMocks); _prunk2.default.mock('angular', angularMocks);
_prunk2.default.mock('jquery', 'module not found'); _prunk2.default.mock('jquery', 'module not found');
// Required for loading angularjs
var dom = new _jsdom.JSDOM('<html><head><script></script></head><body></body></html>');
// Setup jsdom // Setup jsdom
global.window = dom.window; // Required for loading angularjs
global.document = global.window.document; 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; global.Node = window.Node;
// Setup Chai // Setup Chai

View File

@@ -1,5 +1,7 @@
'use strict'; 'use strict';
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; }; }(); 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 _angular = require('angular');
@@ -74,6 +76,7 @@ function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy, ZabbixDBConnector)
this.getTrend = this.zabbixAPI.getTrend.bind(this.zabbixAPI); this.getTrend = this.zabbixAPI.getTrend.bind(this.zabbixAPI);
this.getEvents = this.zabbixAPI.getEvents.bind(this.zabbixAPI); this.getEvents = this.zabbixAPI.getEvents.bind(this.zabbixAPI);
this.getAlerts = this.zabbixAPI.getAlerts.bind(this.zabbixAPI); this.getAlerts = this.zabbixAPI.getAlerts.bind(this.zabbixAPI);
this.getHostAlerts = this.zabbixAPI.getHostAlerts.bind(this.zabbixAPI);
this.getAcknowledges = this.zabbixAPI.getAcknowledges.bind(this.zabbixAPI); this.getAcknowledges = this.zabbixAPI.getAcknowledges.bind(this.zabbixAPI);
this.getITService = this.zabbixAPI.getITService.bind(this.zabbixAPI); this.getITService = this.zabbixAPI.getITService.bind(this.zabbixAPI);
this.getSLA = this.zabbixAPI.getSLA.bind(this.zabbixAPI); this.getSLA = this.zabbixAPI.getSLA.bind(this.zabbixAPI);
@@ -90,6 +93,24 @@ function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy, ZabbixDBConnector)
}); });
return this.getItems.apply(this, _toConsumableArray(filters).concat([options])); return this.getItems.apply(this, _toConsumableArray(filters).concat([options]));
} }
}, {
key: 'getHostsFromTarget',
value: function getHostsFromTarget(target) {
var parts = ['group', 'host', 'application'];
var filters = _lodash2.default.map(parts, function (p) {
return target[p].filter;
});
return Promise.all([this.getHosts.apply(this, _toConsumableArray(filters)), this.getApps.apply(this, _toConsumableArray(filters))]).then(function (results) {
var _results = _slicedToArray(results, 2),
hosts = _results[0],
apps = _results[1];
if (apps.appFilterEmpty) {
apps = [];
}
return [hosts, apps];
});
}
}, { }, {
key: 'getAllGroups', key: 'getAllGroups',
value: function getAllGroups() { value: function getAllGroups() {

View File

@@ -483,6 +483,39 @@ function ZabbixAPIServiceFactory(alertSrv, zabbixAPICoreService) {
params.lastChangeTill = timeTo; params.lastChangeTill = timeTo;
} }
return this.request('trigger.get', params);
}
}, {
key: 'getHostAlerts',
value: function getHostAlerts(hostids, applicationids, minSeverity, count, timeFrom, timeTo) {
var params = {
output: 'extend',
hostids: hostids,
min_severity: minSeverity,
filter: { value: 1 },
expandDescription: true,
expandData: true,
expandComment: true,
monitored: true,
skipDependent: true,
selectLastEvent: 'extend',
selectGroups: 'extend',
selectHosts: ['host', 'name']
};
if (count) {
params.countOutput = true;
}
if (applicationids && applicationids.length) {
params.applicationids = applicationids;
}
if (timeFrom || timeTo) {
params.lastChangeSince = timeFrom;
params.lastChangeTill = timeTo;
}
return this.request('trigger.get', params); return this.request('trigger.get', params);
} }
}]); }]);

View File

@@ -83,8 +83,6 @@ var ZabbixAPICoreService = function () {
// Success // Success
return response.data.result; return response.data.result;
}).catch(function () {
return Promise.reject(new ZabbixAPIError({ data: "Connection Error" }));
}); });
} }
@@ -125,16 +123,16 @@ var ZabbixAPIError = exports.ZabbixAPIError = function () {
function ZabbixAPIError(error) { function ZabbixAPIError(error) {
_classCallCheck(this, ZabbixAPIError); _classCallCheck(this, ZabbixAPIError);
this.code = error.code; this.code = error.code || null;
this.name = error.data; this.name = error.message || "";
this.message = error.data; this.data = error.data || "";
this.data = error.data; this.message = "Zabbix API Error: " + this.name + " " + this.data;
} }
_createClass(ZabbixAPIError, [{ _createClass(ZabbixAPIError, [{
key: 'toString', key: 'toString',
value: function toString() { value: function toString() {
return this.name + ": " + this.message; return this.name + " " + this.data;
} }
}]); }]);

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d7dae33170bf09b353f886bc1a8cbc4307d80858c514199f08f1b9e01bc01e81
size 260406

View File

@@ -1,5 +1,7 @@
# SQL Data Source Configuration # SQL Data Source Configuration
## MySQL
In order to use _Direct DB Connection_ feature you should configure SQL data source first. In order to use _Direct DB Connection_ feature you should configure SQL data source first.
![Configure MySQL data source](../img/installation-mysql_ds_config.png) ![Configure MySQL data source](../img/installation-mysql_ds_config.png)
@@ -7,7 +9,7 @@ In order to use _Direct DB Connection_ feature you should configure SQL data sou
Select _MySQL_ data source type and provide your database host address and port (3306 is default for MySQL). Fill Select _MySQL_ data source type and provide your database host address and port (3306 is default for MySQL). Fill
database name (usually, `zabbix`) and specify credentials. database name (usually, `zabbix`) and specify credentials.
## Security notes ### Security notes
As you can see in _User Permission_ note, Grafana doesn't restrict any queries to the database. So you should be careful As you can see in _User Permission_ note, Grafana doesn't restrict any queries to the database. So you should be careful
and create a special user with limited access to Zabbix database. Grafana-Zabbix plugin uses only `SELECT` queries to and create a special user with limited access to Zabbix database. Grafana-Zabbix plugin uses only `SELECT` queries to
@@ -20,3 +22,13 @@ Also, all queries are invoked by grafana-server, so you can restrict connection
```sql ```sql
GRANT SELECT ON zabbix.* TO 'grafana'@'grafana-host' identified by 'password'; GRANT SELECT ON zabbix.* TO 'grafana'@'grafana-host' identified by 'password';
``` ```
## PostgreSQL
Select _PostgreSQL_ data source type and provide your database host address and port (5432 is default). Fill
database name (usually, `zabbix`) and specify credentials.
![Configure PostgreSQL data source](../img/installation-postgres_ds_config.png)
### Security notes
Make sure you use read-only user for Zabbix database.

View File

@@ -65,7 +65,7 @@ Read [how to configure](/installation/configuration-sql) SQL data source in Graf
#### Supported databases #### Supported databases
Now only **MySQL** is supported by Grafana. **MySQL** and **PostgreSQL** are supported by Grafana.
### Alerting ### Alerting

View File

@@ -22,12 +22,26 @@ and `trend.get` API calls.
Below is an example query for getting history in the Grafana-Zabbix Plugin: Below is an example query for getting history in the Grafana-Zabbix Plugin:
**MySQL**:
```sql ```sql
SELECT itemid AS metric, clock AS time_sec, {aggFunc}(value) as value SELECT itemid AS metric, clock AS time_sec, {aggFunc}(value) as value
FROM {historyTable} FROM {historyTable}
WHERE itemid IN ({itemids}) WHERE itemid IN ({itemids})
AND clock > {timeFrom} AND clock < {timeTill} AND clock > {timeFrom} AND clock < {timeTill}
GROUP BY time_sec DIV {intervalSec}, metric GROUP BY time_sec DIV {intervalSec}, metric
ORDER BY time_sec ASC
```
**PostgreSQL**:
```sql
SELECT to_char(itemid, 'FM99999999999999999999') AS metric,
clock / {intervalSec} * {intervalSec} AS time,
{aggFunc}(value) AS value
FROM {historyTable}
WHERE itemid IN ({itemids})
AND clock > {timeFrom} AND clock < {timeTill}
GROUP BY 1, 2
ORDER BY time ASC
``` ```
where `{aggFunc}` is one of `[AVG, MIN, MAX, SUM, COUNT]` aggregation functions, `{historyTable}` is a history table, where `{aggFunc}` is one of `[AVG, MIN, MAX, SUM, COUNT]` aggregation functions, `{historyTable}` is a history table,
@@ -36,14 +50,30 @@ where `{aggFunc}` is one of `[AVG, MIN, MAX, SUM, COUNT]` aggregation functions,
When getting trends, the plugin additionally queries a particular value column (`value_avg`, `value_min` or `value_max`) which When getting trends, the plugin additionally queries a particular value column (`value_avg`, `value_min` or `value_max`) which
depends on `consolidateBy` function value: depends on `consolidateBy` function value:
**MySQL**:
```sql ```sql
SELECT itemid AS metric, clock AS time_sec, {aggFunc}({valueColumn}) as value SELECT itemid AS metric, clock AS time_sec, {aggFunc}({valueColumn}) as value
FROM {trendsTable} FROM {trendsTable}
WHERE itemid IN ({itemids}) WHERE itemid IN ({itemids})
AND clock > {timeFrom} AND clock < {timeTill} AND clock > {timeFrom} AND clock < {timeTill}
GROUP BY time_sec DIV {intervalSec}, metric GROUP BY time_sec DIV {intervalSec}, metric
ORDER BY time_sec ASC
``` ```
**PostgreSQL**:
```sql
SELECT to_char(itemid, 'FM99999999999999999999') AS metric,
clock / {intervalSec} * {intervalSec} AS time,
{aggFunc}({valueColumn}) AS value
FROM {trendsTable}
WHERE itemid IN ({itemids})
AND clock > {timeFrom} AND clock < {timeTill}
GROUP BY 1, 2
ORDER BY time ASC
```
**Note**: these queries may be changed in future, so look into sources for actual query structure.
As you can see, the Grafana-Zabbix plugin uses aggregation by a given time interval. This interval is provided by Grafana and depends on the panel width in pixels. Thus, Grafana displays the data in the proper resolution. As you can see, the Grafana-Zabbix plugin uses aggregation by a given time interval. This interval is provided by Grafana and depends on the panel width in pixels. Thus, Grafana displays the data in the proper resolution.
## Functions usage with Direct DB Connection ## Functions usage with Direct DB Connection

View File

@@ -1,20 +1,25 @@
{ {
"id": null, "__inputs": [
"title": "Template Linux Server", {
"originalTitle": "Template Linux Server", "name": "DS_NAME",
"tags": [ "type": "datasource",
"zabbix", "pluginId": "alexanderzobnin-zabbix-datasource"
"example" }
], ],
"style": "dark", "title": "Zabbix Template Linux Server",
"timezone": "browser", "revision": 1,
"annotations": {
"list": []
},
"editable": true, "editable": true,
"gnetId": null,
"graphTooltip": 0,
"hideControls": false, "hideControls": false,
"sharedCrosshair": false, "id": null,
"links": [],
"rows": [ "rows": [
{ {
"collapse": false, "collapse": false,
"editable": true,
"height": "250px", "height": "250px",
"panels": [ "panels": [
{ {
@@ -24,16 +29,13 @@
"CPU user time": "#EAB839" "CPU user time": "#EAB839"
}, },
"bars": false, "bars": false,
"datasource": "$datasource", "dashLength": 10,
"dashes": false,
"datasource": "${DS_NAME}",
"editable": true, "editable": true,
"error": false, "error": false,
"fill": 3, "fill": 3,
"grid": { "grid": {},
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 1, "id": 1,
"legend": { "legend": {
"avg": false, "avg": false,
@@ -53,6 +55,7 @@
"points": false, "points": false,
"renderer": "flot", "renderer": "flot",
"seriesOverrides": [], "seriesOverrides": [],
"spaceLength": 10,
"span": 6, "span": 6,
"stack": true, "stack": true,
"steppedLine": false, "steppedLine": false,
@@ -61,6 +64,7 @@
"application": { "application": {
"filter": "CPU" "filter": "CPU"
}, },
"countTriggers": true,
"functions": [], "functions": [],
"group": { "group": {
"filter": "$group" "filter": "$group"
@@ -71,21 +75,31 @@
"item": { "item": {
"filter": "/CPU/" "filter": "/CPU/"
}, },
"minSeverity": 3,
"mode": 0, "mode": 0,
"options": {
"showDisabledItems": false
},
"refId": "A" "refId": "A"
} }
], ],
"thresholds": [],
"timeFrom": null, "timeFrom": null,
"timeShift": null, "timeShift": null,
"title": "CPU", "title": "CPU",
"tooltip": { "tooltip": {
"msResolution": false, "msResolution": false,
"shared": true, "shared": true,
"sort": 0,
"value_type": "individual" "value_type": "individual"
}, },
"type": "graph", "type": "graph",
"xaxis": { "xaxis": {
"show": true "buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
}, },
"yaxes": [ "yaxes": [
{ {
@@ -109,16 +123,13 @@
"Processor load (1 min average per core)": "#1F78C1" "Processor load (1 min average per core)": "#1F78C1"
}, },
"bars": false, "bars": false,
"datasource": "$datasource", "dashLength": 10,
"dashes": false,
"datasource": "${DS_NAME}",
"editable": true, "editable": true,
"error": false, "error": false,
"fill": 1, "fill": 1,
"grid": { "grid": {},
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 2, "id": 2,
"legend": { "legend": {
"avg": false, "avg": false,
@@ -138,6 +149,7 @@
"points": false, "points": false,
"renderer": "flot", "renderer": "flot",
"seriesOverrides": [], "seriesOverrides": [],
"spaceLength": 10,
"span": 6, "span": 6,
"stack": false, "stack": false,
"steppedLine": false, "steppedLine": false,
@@ -146,6 +158,7 @@
"application": { "application": {
"filter": "CPU" "filter": "CPU"
}, },
"countTriggers": true,
"functions": [], "functions": [],
"group": { "group": {
"filter": "$group" "filter": "$group"
@@ -156,21 +169,31 @@
"item": { "item": {
"filter": "Processor load (15 min average per core)" "filter": "Processor load (15 min average per core)"
}, },
"minSeverity": 3,
"mode": 0, "mode": 0,
"options": {
"showDisabledItems": false
},
"refId": "A" "refId": "A"
} }
], ],
"thresholds": [],
"timeFrom": null, "timeFrom": null,
"timeShift": null, "timeShift": null,
"title": "System load", "title": "System load",
"tooltip": { "tooltip": {
"msResolution": false, "msResolution": false,
"shared": true, "shared": true,
"sort": 0,
"value_type": "cumulative" "value_type": "cumulative"
}, },
"type": "graph", "type": "graph",
"xaxis": { "xaxis": {
"show": true "buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
}, },
"yaxes": [ "yaxes": [
{ {
@@ -190,27 +213,27 @@
] ]
} }
], ],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": true, "showTitle": true,
"title": "CPU" "title": "CPU",
"titleSize": "h6"
}, },
{ {
"collapse": false, "collapse": false,
"editable": true,
"height": "250px", "height": "250px",
"panels": [ "panels": [
{ {
"aliasColors": {}, "aliasColors": {},
"bars": false, "bars": false,
"datasource": "$datasource", "dashLength": 10,
"dashes": false,
"datasource": "${DS_NAME}",
"editable": true, "editable": true,
"error": false, "error": false,
"fill": 3, "fill": 3,
"grid": { "grid": {},
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 3, "id": 3,
"legend": { "legend": {
"alignAsTable": false, "alignAsTable": false,
@@ -233,20 +256,14 @@
"points": false, "points": false,
"renderer": "flot", "renderer": "flot",
"repeat": "netif", "repeat": "netif",
"scopedVars": {
"netif": {
"text": "eth0",
"value": "eth0",
"selected": false
}
},
"seriesOverrides": [ "seriesOverrides": [
{ {
"alias": "/Incoming/", "alias": "/Incoming/",
"transform": "negative-Y" "transform": "negative-Y"
} }
], ],
"span": 6, "spaceLength": 10,
"span": 12,
"stack": false, "stack": false,
"steppedLine": false, "steppedLine": false,
"targets": [ "targets": [
@@ -254,6 +271,7 @@
"application": { "application": {
"filter": "" "filter": ""
}, },
"countTriggers": true,
"functions": [], "functions": [],
"group": { "group": {
"filter": "$group" "filter": "$group"
@@ -264,21 +282,31 @@
"item": { "item": {
"filter": "/$netif/" "filter": "/$netif/"
}, },
"minSeverity": 3,
"mode": 0, "mode": 0,
"options": {
"showDisabledItems": false
},
"refId": "A" "refId": "A"
} }
], ],
"thresholds": [],
"timeFrom": null, "timeFrom": null,
"timeShift": null, "timeShift": null,
"title": "Network traffic on $netif", "title": "Network traffic on $netif",
"tooltip": { "tooltip": {
"msResolution": false, "msResolution": false,
"shared": true, "shared": true,
"sort": 0,
"value_type": "cumulative" "value_type": "cumulative"
}, },
"type": "graph", "type": "graph",
"xaxis": { "xaxis": {
"show": true "buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
}, },
"yaxes": [ "yaxes": [
{ {
@@ -296,113 +324,96 @@
"show": true "show": true
} }
] ]
},
{
"aliasColors": {},
"bars": false,
"datasource": "$datasource",
"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
} }
], ],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": true, "showTitle": true,
"title": "Network" "title": "Network",
"titleSize": "h6"
} }
], ],
"schemaVersion": 14,
"style": "dark",
"tags": [
"zabbix",
"example"
],
"templating": {
"list": [
{
"allFormat": "regex values",
"allValue": null,
"current": {},
"datasource": "${DS_NAME}",
"hide": 0,
"includeAll": false,
"label": "Group",
"multi": false,
"multiFormat": "glob",
"name": "group",
"options": [],
"query": "*",
"refresh": 1,
"refresh_on_load": false,
"regex": "",
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allFormat": "glob",
"allValue": null,
"current": {},
"datasource": "${DS_NAME}",
"hide": 0,
"includeAll": false,
"label": "Host",
"multi": false,
"multiFormat": "glob",
"name": "host",
"options": [],
"query": "$group.*",
"refresh": 1,
"refresh_on_load": false,
"regex": "",
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allFormat": "regex values",
"allValue": null,
"current": {},
"datasource": "${DS_NAME}",
"hide": 0,
"hideLabel": false,
"includeAll": true,
"label": "Network interface",
"multi": true,
"multiFormat": "regex values",
"name": "netif",
"options": [],
"query": "*.$host.Network interfaces.*",
"refresh": 1,
"refresh_on_load": false,
"regex": "/(?:Incoming|Outgoing) network traffic on (.*)/",
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": { "time": {
"from": "now-3h", "from": "now-3h",
"to": "now" "to": "now"
@@ -432,77 +443,5 @@
"30d" "30d"
] ]
}, },
"templating": { "timezone": "browser"
"list": [
{
"current": {},
"hide": 0,
"label": "Zabbix Data Source",
"name": "datasource",
"options": [],
"query": "alexanderzobnin-zabbix-datasource",
"refresh": 1,
"regex": "",
"type": "datasource"
},
{
"allFormat": "regex values",
"current": {},
"datasource": "$datasource",
"hide": 0,
"includeAll": false,
"label": "Group",
"multi": false,
"multiFormat": "glob",
"name": "group",
"options": [],
"query": "*",
"refresh": 1,
"refresh_on_load": false,
"regex": "",
"type": "query"
},
{
"allFormat": "glob",
"current": {},
"datasource": "$datasource",
"hide": 0,
"includeAll": false,
"label": "Host",
"multi": false,
"multiFormat": "glob",
"name": "host",
"options": [],
"query": "$group.*",
"refresh": 1,
"refresh_on_load": false,
"regex": "",
"type": "query"
},
{
"allFormat": "regex values",
"current": {},
"datasource": "$datasource",
"hide": 0,
"hideLabel": false,
"includeAll": true,
"label": "Network interface",
"multi": true,
"multiFormat": "regex values",
"name": "netif",
"options": [],
"query": "*.$host.Network interfaces.*",
"refresh": 1,
"refresh_on_load": false,
"regex": "/(?:Incoming|Outgoing) network traffic on (.*)/",
"type": "query"
}
]
},
"annotations": {
"list": []
},
"schemaVersion": 12,
"version": 9,
"links": []
} }

View File

@@ -0,0 +1,371 @@
{
"__inputs": [
{
"name": "DS_NAME",
"type": "datasource",
"pluginId": "alexanderzobnin-zabbix-datasource"
}
],
"title": "Zabbix System Status",
"revision": "1.0",
"annotations": {
"list": []
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"hideControls": false,
"id": null,
"links": [],
"rows": [
{
"collapse": false,
"height": 250,
"panels": [
{
"columns": [],
"datasource": "${DS_NAME}",
"fontSize": "100%",
"id": 9,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"span": 12,
"styles": [
{
"alias": "Time",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "Time",
"type": "date"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"rgba(45, 172, 121, 0.97)",
"rgba(45, 172, 121, 0.97)",
"#58140c"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "Disaster",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "none"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"#99440a",
"rgba(45, 172, 121, 0.97)",
"#99440a"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "High",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "short"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)",
"#c15c17"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "Average",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "short"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)",
"#cca300"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "Warning",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "short"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)",
"#64b0c8"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "Information",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "short"
},
{
"alias": "",
"colorMode": "cell",
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)",
"rgb(176, 176, 176)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "Not classified",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "short"
},
{
"alias": "",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 0,
"pattern": "/.*/",
"thresholds": [],
"type": "number",
"unit": "none"
}
],
"targets": [
{
"application": {
"filter": ""
},
"countTriggers": false,
"functions": [],
"group": {
"filter": "/.*/"
},
"host": {
"filter": "/.*/"
},
"item": {
"filter": ""
},
"minSeverity": 0,
"mode": 4,
"options": {
"countTriggers": false,
"showDisabledItems": false
},
"refId": "A",
"target": ""
}
],
"title": "System status",
"transform": "table",
"type": "table"
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": false,
"title": "Dashboard Row",
"titleSize": "h6"
},
{
"collapse": false,
"height": "150px",
"panels": [
{
"cacheTimeout": null,
"colorBackground": true,
"colorValue": false,
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(16, 154, 113, 0.97)",
"#890f02"
],
"datasource": "${DS_NAME}",
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"id": 1,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"minSpan": 2,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"repeat": "group",
"span": 2,
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"application": {
"filter": ""
},
"countTriggers": true,
"functions": [],
"group": {
"filter": "$group"
},
"host": {
"filter": "/.*/"
},
"item": {
"filter": ""
},
"minSeverity": 3,
"mode": 4,
"options": {
"showDisabledItems": false
},
"refId": "A",
"target": ""
}
],
"thresholds": "0,1",
"title": "$group",
"type": "singlestat",
"valueFontSize": "120%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": false,
"title": "Dashboard Row",
"titleSize": "h6"
}
],
"schemaVersion": 14,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"allValue": null,
"current": {},
"datasource": "${DS_NAME}",
"hide": 0,
"includeAll": true,
"label": null,
"multi": true,
"name": "group",
"options": [],
"query": "*",
"refresh": 1,
"regex": "",
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"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"
]
},
"timezone": ""
}

View File

@@ -3,6 +3,7 @@ export const MODE_METRICS = 0;
export const MODE_ITSERVICE = 1; export const MODE_ITSERVICE = 1;
export const MODE_TEXT = 2; export const MODE_TEXT = 2;
export const MODE_ITEMID = 3; export const MODE_ITEMID = 3;
export const MODE_TRIGGERS = 4;
// Triggers severity // Triggers severity
export const SEV_NOT_CLASSIFIED = 0; export const SEV_NOT_CLASSIFIED = 0;
@@ -19,3 +20,12 @@ export const SHOW_OK_EVENTS = 1;
// Data point // Data point
export const DATAPOINT_VALUE = 0; export const DATAPOINT_VALUE = 0;
export const DATAPOINT_TS = 1; export const DATAPOINT_TS = 1;
export const TRIGGER_SEVERITY = [
{val: 0, text: 'Not classified'},
{val: 1, text: 'Information'},
{val: 2, text: 'Warning'},
{val: 3, text: 'Average'},
{val: 4, text: 'High'},
{val: 5, text: 'Disaster'}
];

View File

@@ -28,26 +28,28 @@ class ZabbixAPIDatasource {
this.basicAuth = instanceSettings.basicAuth; this.basicAuth = instanceSettings.basicAuth;
this.withCredentials = instanceSettings.withCredentials; this.withCredentials = instanceSettings.withCredentials;
const jsonData = instanceSettings.jsonData;
// Zabbix API credentials // Zabbix API credentials
this.username = instanceSettings.jsonData.username; this.username = jsonData.username;
this.password = instanceSettings.jsonData.password; this.password = jsonData.password;
// Use trends instead history since specified time // Use trends instead history since specified time
this.trends = instanceSettings.jsonData.trends; this.trends = jsonData.trends;
this.trendsFrom = instanceSettings.jsonData.trendsFrom || '7d'; this.trendsFrom = jsonData.trendsFrom || '7d';
this.trendsRange = instanceSettings.jsonData.trendsRange || '4d'; this.trendsRange = jsonData.trendsRange || '4d';
// Set cache update interval // Set cache update interval
var ttl = instanceSettings.jsonData.cacheTTL || '1h'; var ttl = jsonData.cacheTTL || '1h';
this.cacheTTL = utils.parseInterval(ttl); this.cacheTTL = utils.parseInterval(ttl);
// Alerting options // Alerting options
this.alertingEnabled = instanceSettings.jsonData.alerting; this.alertingEnabled = jsonData.alerting;
this.addThresholds = instanceSettings.jsonData.addThresholds; this.addThresholds = jsonData.addThresholds;
this.alertingMinSeverity = instanceSettings.jsonData.alertingMinSeverity || c.SEV_WARNING; this.alertingMinSeverity = jsonData.alertingMinSeverity || c.SEV_WARNING;
// Direct DB Connection options // Direct DB Connection options
let dbConnectionOptions = instanceSettings.jsonData.dbConnection || {}; let dbConnectionOptions = jsonData.dbConnection || {};
this.enableDirectDBConnection = dbConnectionOptions.enable; this.enableDirectDBConnection = dbConnectionOptions.enable;
this.sqlDatasourceId = dbConnectionOptions.datasourceId; this.sqlDatasourceId = dbConnectionOptions.datasourceId;
@@ -134,6 +136,10 @@ class ZabbixAPIDatasource {
} else if (target.mode === c.MODE_ITSERVICE) { } else if (target.mode === c.MODE_ITSERVICE) {
// IT services mode // IT services mode
return this.queryITServiceData(target, timeRange, options); return this.queryITServiceData(target, timeRange, options);
} else if (target.mode === c.MODE_TRIGGERS) {
return this.queryTriggersData(target, timeRange);
} else {
return [];
} }
}); });
@@ -348,6 +354,24 @@ class ZabbixAPIDatasource {
}); });
} }
queryTriggersData(target, timeRange) {
let [timeFrom, timeTo] = timeRange;
return this.zabbix.getHostsFromTarget(target)
.then((results) => {
let [hosts, apps] = results;
if (hosts.length) {
let hostids = _.map(hosts, 'hostid');
let appids = _.map(apps, 'applicationid');
return this.zabbix.getHostAlerts(hostids, appids, target.minSeverity, target.countTriggers, timeFrom, timeTo)
.then((triggers) => {
return responseHandler.handleTriggersResponse(triggers, timeRange);
});
} else {
return Promise.resolve([]);
}
});
}
/** /**
* Test connection to Zabbix API * Test connection to Zabbix API
* @return {object} Connection status and Zabbix API version * @return {object} Connection status and Zabbix API version
@@ -378,13 +402,13 @@ class ZabbixAPIDatasource {
return { return {
status: "error", status: "error",
title: error.message, title: error.message,
message: error.data message: error.message
}; };
} else if (error.data && error.data.message) { } else if (error.data && error.data.message) {
return { return {
status: "error", status: "error",
title: "Connection failed", title: "Connection failed",
message: error.data.message message: "Connection failed: " + error.data.message
}; };
} else { } else {
return { return {

View File

@@ -48,7 +48,7 @@
</div> </div>
</div> </div>
<div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT"> <div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT || ctrl.target.mode == editorMode.TRIGGERS">
<!-- Select Group --> <!-- Select Group -->
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-7">Group</label> <label class="gf-form-label query-keyword width-7">Group</label>
@@ -66,7 +66,7 @@
</div> </div>
<!-- Select Host --> <!-- Select Host -->
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label query-keyword width-7">Host</label> <label class="gf-form-label query-keyword width-8">Host</label>
<input type="text" <input type="text"
ng-model="ctrl.target.host.filter" ng-model="ctrl.target.host.filter"
bs-typeahead="ctrl.getHostNames" bs-typeahead="ctrl.getHostNames"
@@ -85,7 +85,7 @@
</div> </div>
</div> </div>
<div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT"> <div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT || ctrl.target.mode == editorMode.TRIGGERS">
<!-- Select Application --> <!-- Select Application -->
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-7">Application</label> <label class="gf-form-label query-keyword width-7">Application</label>
@@ -103,8 +103,8 @@
</div> </div>
<!-- Select Item --> <!-- Select Item -->
<div class="gf-form"> <div class="gf-form" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT">
<label class="gf-form-label query-keyword width-7">Item</label> <label class="gf-form-label query-keyword width-8">Item</label>
<input type="text" <input type="text"
ng-model="ctrl.target.item.filter" ng-model="ctrl.target.item.filter"
bs-typeahead="ctrl.getItemNames" bs-typeahead="ctrl.getItemNames"
@@ -117,9 +117,25 @@
'zbx-regex': ctrl.isRegex(ctrl.target.item.filter) 'zbx-regex': ctrl.isRegex(ctrl.target.item.filter)
}"> }">
</div> </div>
<div class="gf-form max-width-23" ng-show="ctrl.target.mode == editorMode.TRIGGERS">
<label class="gf-form-label query-keyword width-8">Min Severity</label>
<div class="gf-form-select-wrapper width-16">
<select class="gf-form-input"
ng-change="ctrl.onTargetBlur()"
ng-model="ctrl.target.minSeverity"
ng-options="s.val as s.text for s in ctrl.triggerSeverity">
</select>
</div>
</div>
<gf-form-switch class="gf-form" label="Count" ng-show="ctrl.target.mode == editorMode.TRIGGERS"
checked="ctrl.target.countTriggers" on-change="ctrl.onTargetBlur()">
</gf-form-switch>
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<label class="gf-form-label gf-form-label--grow"> <label class="gf-form-label gf-form-label--grow">
<a ng-click="ctrl.toggleQueryOptions()"> <a ng-click="ctrl.toggleQueryOptions()" ng-hide="ctrl.target.mode == editorMode.TRIGGERS">
<i class="fa fa-caret-down" ng-show="ctrl.showQueryOptions"></i> <i class="fa fa-caret-down" ng-show="ctrl.showQueryOptions"></i>
<i class="fa fa-caret-right" ng-hide="ctrl.showQueryOptions"></i> <i class="fa fa-caret-right" ng-hide="ctrl.showQueryOptions"></i>
{{ctrl.queryOptionsText}} {{ctrl.queryOptionsText}}
@@ -130,7 +146,7 @@
<!-- Query options --> <!-- Query options -->
<div class="gf-form-group" ng-if="ctrl.showQueryOptions"> <div class="gf-form-group" ng-if="ctrl.showQueryOptions">
<div class="gf-form offset-width-7"> <div class="gf-form offset-width-7" ng-hide="ctrl.target.mode == editorMode.TRIGGERS">
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label="Show disabled items" label="Show disabled items"
checked="ctrl.target.options.showDisabledItems" checked="ctrl.target.options.showDisabledItems"

View File

@@ -3,6 +3,19 @@
"name": "Zabbix", "name": "Zabbix",
"id": "alexanderzobnin-zabbix-datasource", "id": "alexanderzobnin-zabbix-datasource",
"includes": [
{
"type": "dashboard",
"name": "Zabbix System Status",
"path": "../dashboards/zabbix_system_status.json"
},
{
"type": "dashboard",
"name": "Zabbix Template Linux Server",
"path": "../dashboards/template_linux_server.json"
}
],
"metrics": true, "metrics": true,
"annotations": true, "annotations": true,

View File

@@ -25,14 +25,16 @@ export class ZabbixQueryController extends QueryCtrl {
{value: 'num', text: 'Metrics', mode: c.MODE_METRICS}, {value: 'num', text: 'Metrics', mode: c.MODE_METRICS},
{value: 'text', text: 'Text', mode: c.MODE_TEXT}, {value: 'text', text: 'Text', mode: c.MODE_TEXT},
{value: 'itservice', text: 'IT Services', mode: c.MODE_ITSERVICE}, {value: 'itservice', text: 'IT Services', mode: c.MODE_ITSERVICE},
{value: 'itemid', text: 'Item ID', mode: c.MODE_ITEMID} {value: 'itemid', text: 'Item ID', mode: c.MODE_ITEMID},
{value: 'triggers', text: 'Triggers', mode: c.MODE_TRIGGERS}
]; ];
this.$scope.editorMode = { this.$scope.editorMode = {
METRICS: c.MODE_METRICS, METRICS: c.MODE_METRICS,
TEXT: c.MODE_TEXT, TEXT: c.MODE_TEXT,
ITSERVICE: c.MODE_ITSERVICE, ITSERVICE: c.MODE_ITSERVICE,
ITEMID: c.MODE_ITEMID ITEMID: c.MODE_ITEMID,
TRIGGERS: c.MODE_TRIGGERS
}; };
this.slaPropertyList = [ this.slaPropertyList = [
@@ -43,6 +45,8 @@ export class ZabbixQueryController extends QueryCtrl {
{name: "Down time", property: "downtimeTime"} {name: "Down time", property: "downtimeTime"}
]; ];
this.triggerSeverity = c.TRIGGER_SEVERITY;
// Map functions for bs-typeahead // Map functions for bs-typeahead
this.getGroupNames = _.bind(this.getMetricNames, this, 'groupList'); this.getGroupNames = _.bind(this.getMetricNames, this, 'groupList');
this.getHostNames = _.bind(this.getMetricNames, this, 'hostList', true); this.getHostNames = _.bind(this.getMetricNames, this, 'hostList', true);
@@ -80,6 +84,8 @@ export class ZabbixQueryController extends QueryCtrl {
'application': { 'filter': "" }, 'application': { 'filter': "" },
'item': { 'filter': "" }, 'item': { 'filter': "" },
'functions': [], 'functions': [],
'minSeverity': 3,
'countTriggers': true,
'options': { 'options': {
'showDisabledItems': false 'showDisabledItems': false
} }
@@ -92,8 +98,8 @@ export class ZabbixQueryController extends QueryCtrl {
}); });
if (target.mode === c.MODE_METRICS || if (target.mode === c.MODE_METRICS ||
target.mode === c.MODE_TEXT) { target.mode === c.MODE_TEXT ||
target.mode === c.MODE_TRIGGERS) {
this.initFilters(); this.initFilters();
} }
else if (target.mode === c.MODE_ITSERVICE) { else if (target.mode === c.MODE_ITSERVICE) {
@@ -103,6 +109,7 @@ export class ZabbixQueryController extends QueryCtrl {
}; };
this.init(); this.init();
this.queryOptionsText = this.renderQueryOptionsText();
} }
initFilters() { initFilters() {

View File

@@ -26,3 +26,6 @@ This mode is suitable for rendering charts in grafana by passing itemids as url
1. Save dashboard. 1. Save dashboard.
1. Click to graph title and select _Share_ -> _Direct link rendered image_. 1. Click to graph title and select _Share_ -> _Direct link rendered image_.
1. Use this URL for graph png image and set `var-itemids` param to desired IDs. Note, for multiple IDs you should pass multiple params, like `&var-itemids=28276&var-itemids=28277`. 1. Use this URL for graph png image and set `var-itemids` param to desired IDs. Note, for multiple IDs you should pass multiple params, like `&var-itemids=28276&var-itemids=28277`.
##### Triggers
Active triggers count for selected hosts or table data like Zabbix _System status_ panel on the main dashboard.

View File

@@ -1,4 +1,6 @@
import _ from 'lodash'; import _ from 'lodash';
import TableModel from 'app/core/table_model';
import * as c from './constants';
/** /**
* Convert Zabbix API history.get response to Grafana format * Convert Zabbix API history.get response to Grafana format
@@ -100,6 +102,45 @@ function handleSLAResponse(itservice, slaProperty, slaObject) {
} }
} }
function handleTriggersResponse(triggers, timeRange) {
if (_.isNumber(triggers)) {
return {
target: "triggers count",
datapoints: [
[triggers, timeRange[1] * 1000]
]
};
} else {
let stats = getTriggerStats(triggers);
let table = new TableModel();
table.addColumn({text: 'Host group'});
_.each(_.orderBy(c.TRIGGER_SEVERITY, ['val'], ['desc']), (severity) => {
table.addColumn({text: severity.text});
});
_.each(stats, (severity_stats, group) => {
let row = _.map(_.orderBy(_.toPairs(severity_stats), (s) => s[0], ['desc']), (s) => s[1]);
row = _.concat([group], ...row);
table.rows.push(row);
});
return table;
}
}
function getTriggerStats(triggers) {
let groups = _.uniq(_.flattenDeep(_.map(triggers, (trigger) => _.map(trigger.groups, 'name'))));
// let severity = _.map(c.TRIGGER_SEVERITY, 'text');
let stats = {};
_.each(groups, (group) => {
stats[group] = {0:0, 1:0, 2:0, 3:0, 4:0, 5:0}; // severity:count
});
_.each(triggers, (trigger) => {
_.each(trigger.groups, (group) => {
stats[group.name][trigger.priority]++;
});
});
return stats;
}
function convertHistoryPoint(point) { function convertHistoryPoint(point) {
// Value must be a number for properly work // Value must be a number for properly work
return [ return [
@@ -141,7 +182,8 @@ export default {
convertHistory: convertHistory, convertHistory: convertHistory,
handleTrends: handleTrends, handleTrends: handleTrends,
handleText: handleText, handleText: handleText,
handleSLAResponse: handleSLAResponse handleSLAResponse: handleSLAResponse,
handleTriggersResponse: handleTriggersResponse
}; };
// Fix for backward compatibility with lodash 2.4 // Fix for backward compatibility with lodash 2.4

View File

@@ -32,6 +32,7 @@ prunk.mock('app/plugins/sdk', {
QueryCtrl: null QueryCtrl: null
}); });
prunk.mock('app/core/utils/datemath', datemathMock); prunk.mock('app/core/utils/datemath', datemathMock);
prunk.mock('app/core/table_model', {});
prunk.mock('angular', angularMocks); prunk.mock('angular', angularMocks);
prunk.mock('jquery', 'module not found'); prunk.mock('jquery', 'module not found');

View File

@@ -46,6 +46,7 @@ function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy, ZabbixDBConnector)
this.getTrend = this.zabbixAPI.getTrend.bind(this.zabbixAPI); this.getTrend = this.zabbixAPI.getTrend.bind(this.zabbixAPI);
this.getEvents = this.zabbixAPI.getEvents.bind(this.zabbixAPI); this.getEvents = this.zabbixAPI.getEvents.bind(this.zabbixAPI);
this.getAlerts = this.zabbixAPI.getAlerts.bind(this.zabbixAPI); this.getAlerts = this.zabbixAPI.getAlerts.bind(this.zabbixAPI);
this.getHostAlerts = this.zabbixAPI.getHostAlerts.bind(this.zabbixAPI);
this.getAcknowledges = this.zabbixAPI.getAcknowledges.bind(this.zabbixAPI); this.getAcknowledges = this.zabbixAPI.getAcknowledges.bind(this.zabbixAPI);
this.getITService = this.zabbixAPI.getITService.bind(this.zabbixAPI); this.getITService = this.zabbixAPI.getITService.bind(this.zabbixAPI);
this.getSLA = this.zabbixAPI.getSLA.bind(this.zabbixAPI); this.getSLA = this.zabbixAPI.getSLA.bind(this.zabbixAPI);
@@ -59,6 +60,21 @@ function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy, ZabbixDBConnector)
return this.getItems(...filters, options); return this.getItems(...filters, options);
} }
getHostsFromTarget(target) {
let parts = ['group', 'host', 'application'];
let filters = _.map(parts, p => target[p].filter);
return Promise.all([
this.getHosts(...filters),
this.getApps(...filters),
]).then((results) => {
let [hosts, apps] = results;
if (apps.appFilterEmpty) {
apps = [];
}
return [hosts, apps];
});
}
getAllGroups() { getAllGroups() {
return this.cachingProxy.getGroups(); return this.cachingProxy.getGroups();
} }

View File

@@ -433,6 +433,38 @@ function ZabbixAPIServiceFactory(alertSrv, zabbixAPICoreService) {
return this.request('trigger.get', params); return this.request('trigger.get', params);
} }
getHostAlerts(hostids, applicationids, minSeverity, count, timeFrom, timeTo) {
var params = {
output: 'extend',
hostids: hostids,
min_severity: minSeverity,
filter: { value: 1 },
expandDescription: true,
expandData: true,
expandComment: true,
monitored: true,
skipDependent: true,
selectLastEvent: 'extend',
selectGroups: 'extend',
selectHosts: ['host', 'name']
};
if (count) {
params.countOutput = true;
}
if (applicationids && applicationids.length) {
params.applicationids = applicationids;
}
if (timeFrom || timeTo) {
params.lastChangeSince = timeFrom;
params.lastChangeTill = timeTo;
}
return this.request('trigger.get', params);
}
} }
return ZabbixAPI; return ZabbixAPI;

View File

@@ -53,7 +53,7 @@ class ZabbixAPICoreService {
datasourceRequest(requestOptions) { datasourceRequest(requestOptions) {
return this.backendSrv.datasourceRequest(requestOptions) return this.backendSrv.datasourceRequest(requestOptions)
.then(response => { .then((response) => {
if (!response.data) { if (!response.data) {
return Promise.reject(new ZabbixAPIError({data: "General Error, no data"})); return Promise.reject(new ZabbixAPIError({data: "General Error, no data"}));
} else if (response.data.error) { } else if (response.data.error) {
@@ -64,9 +64,6 @@ class ZabbixAPICoreService {
// Success // Success
return response.data.result; return response.data.result;
})
.catch(() => {
return Promise.reject(new ZabbixAPIError({data: "Connection Error"}));
}); });
} }
@@ -94,14 +91,14 @@ class ZabbixAPICoreService {
// Define zabbix API exception type // Define zabbix API exception type
export class ZabbixAPIError { export class ZabbixAPIError {
constructor(error) { constructor(error) {
this.code = error.code; this.code = error.code || null;
this.name = error.data; this.name = error.message || "";
this.message = error.data; this.data = error.data || "";
this.data = error.data; this.message = "Zabbix API Error: " + this.name + " " + this.data;
} }
toString() { toString() {
return this.name + ": " + this.message; return this.name + " " + this.data;
} }
} }

View File

@@ -26,8 +26,8 @@
{"name": "Metric Editor", "path": "img/screenshot-metric_editor.png"}, {"name": "Metric Editor", "path": "img/screenshot-metric_editor.png"},
{"name": "Triggers", "path": "img/screenshot-triggers.png"} {"name": "Triggers", "path": "img/screenshot-triggers.png"}
], ],
"version": "3.6.1", "version": "3.7.0",
"updated": "2017-07-26" "updated": "2017-10-22"
}, },
"includes": [ "includes": [
@@ -45,12 +45,6 @@
"path": "dashboards/zabbix_server_dashboard.json", "path": "dashboards/zabbix_server_dashboard.json",
"addToNav": true, "addToNav": true,
"defaultNav": true "defaultNav": true
},
{
"type": "dashboard",
"name": "Template Linux Server",
"path": "dashboards/template_linux_server.json",
"addToNav": true
} }
], ],