diff --git a/dist/datasource-zabbix/config.controller.js b/dist/datasource-zabbix/config.controller.js index 9b753aa..328d37e 100644 --- a/dist/datasource-zabbix/config.controller.js +++ b/dist/datasource-zabbix/config.controller.js @@ -34,7 +34,7 @@ System.register(['lodash'], function (_export, _context) { }; }(); - SUPPORTED_SQL_DS = ['mysql']; + SUPPORTED_SQL_DS = ['mysql', 'postgres']; defaultConfig = { dbConnection: { enable: false diff --git a/dist/datasource-zabbix/config.controller.js.map b/dist/datasource-zabbix/config.controller.js.map index afc3a6b..6f23618 100644 --- a/dist/datasource-zabbix/config.controller.js.map +++ b/dist/datasource-zabbix/config.controller.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../src/datasource-zabbix/config.controller.js"],"names":["_","SUPPORTED_SQL_DS","defaultConfig","dbConnection","enable","ZabbixDSConfigController","$scope","$injector","datasourceSrv","defaults","current","jsonData","sqlDataSources","getSupportedSQLDataSources","datasources","getAll","filter","includes","ds","type","templateUrl"],"mappings":";;;;;;;;;;;;;;;AAAOA,O;;;;;;;;;;;;;;;;;;;;;AAEDC,sB,GAAmB,CAAC,OAAD,C;AAEnBC,mB,GAAgB;AACpBC,sBAAc;AACZC,kBAAQ;AADI;AADM,O;;0CAMTC,wB;AACX;AACA,0CAAYC,MAAZ,EAAoBC,SAApB,EAA+BC,aAA/B,EAA8C;AAAA;;AAC5C,eAAKA,aAAL,GAAqBA,aAArB;;AAEAR,YAAES,QAAF,CAAW,KAAKC,OAAL,CAAaC,QAAxB,EAAkCT,aAAlC;AACA,eAAKU,cAAL,GAAsB,KAAKC,0BAAL,EAAtB;AACD;;;;uDAE4B;AAC3B,gBAAIC,cAAc,KAAKN,aAAL,CAAmBO,MAAnB,EAAlB;AACA,mBAAOf,EAAEgB,MAAF,CAASF,WAAT,EAAsB,cAAM;AACjC,qBAAOd,EAAEiB,QAAF,CAAWhB,gBAAX,EAA6BiB,GAAGC,IAAhC,CAAP;AACD,aAFM,CAAP;AAGD;;;;;;;;AAGHd,+BAAyBe,WAAzB,GAAuC,wCAAvC","file":"config.controller.js","sourcesContent":["import _ from 'lodash';\n\nconst SUPPORTED_SQL_DS = ['mysql'];\n\nconst defaultConfig = {\n dbConnection: {\n enable: false,\n }\n};\n\nexport class ZabbixDSConfigController {\n /** @ngInject */\n constructor($scope, $injector, datasourceSrv) {\n this.datasourceSrv = datasourceSrv;\n\n _.defaults(this.current.jsonData, defaultConfig);\n this.sqlDataSources = this.getSupportedSQLDataSources();\n }\n\n getSupportedSQLDataSources() {\n let datasources = this.datasourceSrv.getAll();\n return _.filter(datasources, ds => {\n return _.includes(SUPPORTED_SQL_DS, ds.type);\n });\n }\n}\n\nZabbixDSConfigController.templateUrl = 'datasource-zabbix/partials/config.html';\n"]} \ No newline at end of file +{"version":3,"sources":["../../src/datasource-zabbix/config.controller.js"],"names":["_","SUPPORTED_SQL_DS","defaultConfig","dbConnection","enable","ZabbixDSConfigController","$scope","$injector","datasourceSrv","defaults","current","jsonData","sqlDataSources","getSupportedSQLDataSources","datasources","getAll","filter","includes","ds","type","templateUrl"],"mappings":";;;;;;;;;;;;;;;AAAOA,O;;;;;;;;;;;;;;;;;;;;;AAEDC,sB,GAAmB,CAAC,OAAD,EAAU,UAAV,C;AAEnBC,mB,GAAgB;AACpBC,sBAAc;AACZC,kBAAQ;AADI;AADM,O;;0CAMTC,wB;AACX;AACA,0CAAYC,MAAZ,EAAoBC,SAApB,EAA+BC,aAA/B,EAA8C;AAAA;;AAC5C,eAAKA,aAAL,GAAqBA,aAArB;;AAEAR,YAAES,QAAF,CAAW,KAAKC,OAAL,CAAaC,QAAxB,EAAkCT,aAAlC;AACA,eAAKU,cAAL,GAAsB,KAAKC,0BAAL,EAAtB;AACD;;;;uDAE4B;AAC3B,gBAAIC,cAAc,KAAKN,aAAL,CAAmBO,MAAnB,EAAlB;AACA,mBAAOf,EAAEgB,MAAF,CAASF,WAAT,EAAsB,cAAM;AACjC,qBAAOd,EAAEiB,QAAF,CAAWhB,gBAAX,EAA6BiB,GAAGC,IAAhC,CAAP;AACD,aAFM,CAAP;AAGD;;;;;;;;AAGHd,+BAAyBe,WAAzB,GAAuC,wCAAvC","file":"config.controller.js","sourcesContent":["import _ from 'lodash';\n\nconst SUPPORTED_SQL_DS = ['mysql', 'postgres'];\n\nconst defaultConfig = {\n dbConnection: {\n enable: false,\n }\n};\n\nexport class ZabbixDSConfigController {\n /** @ngInject */\n constructor($scope, $injector, datasourceSrv) {\n this.datasourceSrv = datasourceSrv;\n\n _.defaults(this.current.jsonData, defaultConfig);\n this.sqlDataSources = this.getSupportedSQLDataSources();\n }\n\n getSupportedSQLDataSources() {\n let datasources = this.datasourceSrv.getAll();\n return _.filter(datasources, ds => {\n return _.includes(SUPPORTED_SQL_DS, ds.type);\n });\n }\n}\n\nZabbixDSConfigController.templateUrl = 'datasource-zabbix/partials/config.html';\n"]} \ No newline at end of file diff --git a/dist/datasource-zabbix/zabbixDBConnector.js b/dist/datasource-zabbix/zabbixDBConnector.js index e8ed627..e3657d2 100644 --- a/dist/datasource-zabbix/zabbixDBConnector.js +++ b/dist/datasource-zabbix/zabbixDBConnector.js @@ -3,7 +3,7 @@ System.register(['angular', 'lodash'], function (_export, _context) { "use strict"; - var angular, _, _createClass, DEFAULT_QUERY_LIMIT, HISTORY_TO_TABLE_MAP, TREND_TO_TABLE_MAP, consolidateByFunc, consolidateByTrendColumns; + var angular, _, _createClass, DEFAULT_QUERY_LIMIT, HISTORY_TO_TABLE_MAP, TREND_TO_TABLE_MAP, consolidateByFunc, consolidateByTrendColumns, TEST_MYSQL_QUERY, TEST_POSTGRES_QUERY; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { @@ -24,6 +24,8 @@ System.register(['angular', 'lodash'], function (_export, _context) { this.sqlDataSourceId = sqlDataSourceId; this.limit = limit || DEFAULT_QUERY_LIMIT; + + this.loadSQLDataSource(sqlDataSourceId); } /** @@ -35,10 +37,13 @@ System.register(['angular', 'lodash'], function (_export, _context) { _createClass(ZabbixDBConnector, [{ key: 'loadSQLDataSource', value: function loadSQLDataSource(datasourceId) { + var _this = this; + var ds = _.find(datasourceSrv.getAll(), { 'id': datasourceId }); if (ds) { return datasourceSrv.loadDatasource(ds.name).then(function (ds) { - console.log('SQL data source loaded', ds); + _this.sqlDataSourceType = ds.meta.id; + return ds; }); } else { return Promise.reject('SQL Data Source with ID ' + datasourceId + ' not found'); @@ -47,13 +52,16 @@ System.register(['angular', 'lodash'], function (_export, _context) { }, { key: 'testSQLDataSource', value: function testSQLDataSource() { - var testQuery = 'SELECT itemid AS metric, clock AS time_sec, value_avg AS value FROM trends_uint LIMIT 1'; + var testQuery = TEST_MYSQL_QUERY; + if (this.sqlDataSourceType === 'postgres') { + testQuery = TEST_POSTGRES_QUERY; + } return this.invokeSQLQuery(testQuery); } }, { key: 'getHistory', value: function getHistory(items, timeFrom, timeTill, options) { - var _this = this; + var _this2 = this; var intervalMs = options.intervalMs, consolidateBy = options.consolidateBy; @@ -69,11 +77,11 @@ System.register(['angular', 'lodash'], function (_export, _context) { var itemids = _.map(items, 'itemid').join(', '); var table = HISTORY_TO_TABLE_MAP[value_type]; - var time_expression = 'clock DIV ' + intervalSec + ' * ' + intervalSec; - var query = '\n SELECT itemid AS metric, ' + time_expression + ' AS time_sec, ' + aggFunction + '(value) AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY ' + time_expression + ', metric\n '; + var dialect = _this2.sqlDataSourceType; + var query = buildSQLHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, dialect); query = compactSQLQuery(query); - return _this.invokeSQLQuery(query); + return _this2.invokeSQLQuery(query); }); return Promise.all(promises).then(function (results) { @@ -83,7 +91,7 @@ System.register(['angular', 'lodash'], function (_export, _context) { }, { key: 'getTrends', value: function getTrends(items, timeFrom, timeTill, options) { - var _this2 = this; + var _this3 = this; var intervalMs = options.intervalMs, consolidateBy = options.consolidateBy; @@ -101,11 +109,11 @@ System.register(['angular', 'lodash'], function (_export, _context) { var valueColumn = _.includes(['avg', 'min', 'max'], consolidateBy) ? consolidateBy : 'avg'; valueColumn = consolidateByTrendColumns[valueColumn]; - var time_expression = 'clock DIV ' + intervalSec + ' * ' + intervalSec; - var query = '\n SELECT itemid AS metric, ' + time_expression + ' AS time_sec, ' + aggFunction + '(' + valueColumn + ') AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY ' + time_expression + ', metric\n '; + var dialect = _this3.sqlDataSourceType; + var query = buildSQLTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn, dialect); query = compactSQLQuery(query); - return _this2.invokeSQLQuery(query); + return _this3.invokeSQLQuery(query); }); return Promise.all(promises).then(function (results) { @@ -181,6 +189,59 @@ System.register(['angular', 'lodash'], function (_export, _context) { function compactSQLQuery(query) { return query.replace(/\s+/g, ' '); } + + function buildSQLHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction) { + var dialect = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 'mysql'; + + if (dialect === 'postgres') { + return buildPostgresHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction); + } else { + return buildMysqlHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction); + } + } + + function buildSQLTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn) { + var dialect = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 'mysql'; + + if (dialect === 'postgres') { + return buildPostgresTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn); + } else { + return buildMysqlTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn); + } + } + + /////////// + // MySQL // + /////////// + + function buildMysqlHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction) { + var time_expression = 'clock DIV ' + intervalSec + ' * ' + intervalSec; + var query = '\n SELECT itemid AS metric, ' + time_expression + ' AS time_sec, ' + aggFunction + '(value) AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY ' + time_expression + ', metric\n ORDER BY time_sec ASC\n '; + return query; + } + + function buildMysqlTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn) { + var time_expression = 'clock DIV ' + intervalSec + ' * ' + intervalSec; + var query = '\n SELECT itemid AS metric, ' + time_expression + ' AS time_sec, ' + aggFunction + '(' + valueColumn + ') AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY ' + time_expression + ', metric\n ORDER BY time_sec ASC\n '; + return query; + } + + //////////////// + // PostgreSQL // + //////////////// + + function buildPostgresHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction) { + var time_expression = 'clock / ' + intervalSec + ' * ' + intervalSec; + var query = '\n SELECT DISTINCT to_char(itemid, \'FM9999999999999\') AS metric,\n ' + time_expression + ' AS time,\n ' + aggFunction + '(value) OVER (PARTITION BY clock / ' + intervalSec + ') AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY metric, clock, value\n ORDER BY time ASC\n '; + return query; + } + + function buildPostgresTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn) { + var time_expression = 'clock / ' + intervalSec + ' * ' + intervalSec; + var query = '\n SELECT DISTINCT to_char(itemid, \'FM9999999999999\') AS metric,\n ' + time_expression + ' AS time,\n ' + aggFunction + '(' + valueColumn + ') OVER (PARTITION BY clock / ' + intervalSec + ') AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY metric, clock, ' + valueColumn + '\n ORDER BY time ASC\n '; + return query; + } + return { setters: [function (_angular) { angular = _angular.default; @@ -230,7 +291,8 @@ System.register(['angular', 'lodash'], function (_export, _context) { 'min': 'value_min', 'max': 'value_max' }; - angular.module('grafana.services').factory('ZabbixDBConnector', ZabbixDBConnectorFactory); + angular.module('grafana.services').factory('ZabbixDBConnector', ZabbixDBConnectorFactory);TEST_MYSQL_QUERY = 'SELECT itemid AS metric, clock AS time_sec, value_avg AS value FROM trends_uint LIMIT 1'; + TEST_POSTGRES_QUERY = '\n SELECT to_char(itemid, \'FM9999999999999\') AS metric, clock AS time, value_avg AS value\n FROM trends_uint LIMIT 1\n'; } }; }); diff --git a/dist/datasource-zabbix/zabbixDBConnector.js.map b/dist/datasource-zabbix/zabbixDBConnector.js.map index 59d13cf..1033c6d 100644 --- a/dist/datasource-zabbix/zabbixDBConnector.js.map +++ b/dist/datasource-zabbix/zabbixDBConnector.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../src/datasource-zabbix/zabbixDBConnector.js"],"names":["ZabbixDBConnectorFactory","datasourceSrv","backendSrv","ZabbixDBConnector","sqlDataSourceId","options","limit","DEFAULT_QUERY_LIMIT","datasourceId","ds","_","find","getAll","loadDatasource","name","then","console","log","Promise","reject","testQuery","invokeSQLQuery","items","timeFrom","timeTill","intervalMs","consolidateBy","intervalSec","Math","ceil","aggFunction","consolidateByFunc","grouped_items","groupBy","promises","map","value_type","itemids","join","table","HISTORY_TO_TABLE_MAP","time_expression","query","compactSQLQuery","all","flatten","results","TREND_TO_TABLE_MAP","valueColumn","includes","consolidateByTrendColumns","history","addHostName","convertGrafanaTSResponse","queryDef","refId","format","rawSql","maxDataPoints","datasourceRequest","url","method","data","queries","response","series","time_series","hosts","uniqBy","grafanaSeries","itemid","item","alias","keys","length","host","hostid","datapoints","cloneDeep","points","target","sortBy","replace","angular","module","factory"],"mappings":";;;;;;;;;;;;;AA+BA;AACA,WAASA,wBAAT,CAAkCC,aAAlC,EAAiDC,UAAjD,EAA6D;AAAA,QAErDC,iBAFqD;AAIzD,iCAAYC,eAAZ,EAA2C;AAAA,YAAdC,OAAc,uEAAJ,EAAI;;AAAA;;AAAA,YACpCC,KADoC,GAC3BD,OAD2B,CACpCC,KADoC;;;AAGzC,aAAKF,eAAL,GAAuBA,eAAvB;AACA,aAAKE,KAAL,GAAaA,SAASC,mBAAtB;AACD;;AAED;;;;;;AAXyD;AAAA;AAAA,0CAevCC,YAfuC,EAezB;AAC9B,cAAIC,KAAKC,EAAEC,IAAF,CAAOV,cAAcW,MAAd,EAAP,EAA+B,EAAC,MAAMJ,YAAP,EAA/B,CAAT;AACA,cAAIC,EAAJ,EAAQ;AACN,mBAAOR,cAAcY,cAAd,CAA6BJ,GAAGK,IAAhC,EACNC,IADM,CACD,cAAM;AACVC,sBAAQC,GAAR,CAAY,wBAAZ,EAAsCR,EAAtC;AACD,aAHM,CAAP;AAID,WALD,MAKO;AACL,mBAAOS,QAAQC,MAAR,8BAA0CX,YAA1C,gBAAP;AACD;AACF;AAzBwD;AAAA;AAAA,4CA8BrC;AAClB,cAAIY,qGAAJ;AACA,iBAAO,KAAKC,cAAL,CAAoBD,SAApB,CAAP;AACD;AAjCwD;AAAA;AAAA,mCAmC9CE,KAnC8C,EAmCvCC,QAnCuC,EAmC7BC,QAnC6B,EAmCnBnB,OAnCmB,EAmCV;AAAA;;AAAA,cACxCoB,UADwC,GACXpB,OADW,CACxCoB,UADwC;AAAA,cAC5BC,aAD4B,GACXrB,OADW,CAC5BqB,aAD4B;;AAE7C,cAAIC,cAAcC,KAAKC,IAAL,CAAUJ,aAAa,IAAvB,CAAlB;;AAEAC,0BAAgBA,iBAAiB,KAAjC;AACA,cAAII,cAAcC,kBAAkBL,aAAlB,CAAlB;;AAEA;AACA,cAAIM,gBAAgBtB,EAAEuB,OAAF,CAAUX,KAAV,EAAiB,YAAjB,CAApB;AACA,cAAIY,WAAWxB,EAAEyB,GAAF,CAAMH,aAAN,EAAqB,UAACV,KAAD,EAAQc,UAAR,EAAuB;AACzD,gBAAIC,UAAU3B,EAAEyB,GAAF,CAAMb,KAAN,EAAa,QAAb,EAAuBgB,IAAvB,CAA4B,IAA5B,CAAd;AACA,gBAAIC,QAAQC,qBAAqBJ,UAArB,CAAZ;;AAEA,gBAAIK,iCAA+Bd,WAA/B,WAAgDA,WAApD;AACA,gBAAIe,kDACyBD,eADzB,sBACyDX,WADzD,2CAEOS,KAFP,uCAGmBF,OAHnB,qCAIgBd,QAJhB,qBAIwCC,QAJxC,+BAKWiB,eALX,uBAAJ;;AAQAC,oBAAQC,gBAAgBD,KAAhB,CAAR;AACA,mBAAO,MAAKrB,cAAL,CAAoBqB,KAApB,CAAP;AACD,WAfc,CAAf;;AAiBA,iBAAOxB,QAAQ0B,GAAR,CAAYV,QAAZ,EAAsBnB,IAAtB,CAA2B,mBAAW;AAC3C,mBAAOL,EAAEmC,OAAF,CAAUC,OAAV,CAAP;AACD,WAFM,CAAP;AAGD;AAhEwD;AAAA;AAAA,kCAkE/CxB,KAlE+C,EAkExCC,QAlEwC,EAkE9BC,QAlE8B,EAkEpBnB,OAlEoB,EAkEX;AAAA;;AAAA,cACvCoB,UADuC,GACVpB,OADU,CACvCoB,UADuC;AAAA,cAC3BC,aAD2B,GACVrB,OADU,CAC3BqB,aAD2B;;AAE5C,cAAIC,cAAcC,KAAKC,IAAL,CAAUJ,aAAa,IAAvB,CAAlB;;AAEAC,0BAAgBA,iBAAiB,KAAjC;AACA,cAAII,cAAcC,kBAAkBL,aAAlB,CAAlB;;AAEA;AACA,cAAIM,gBAAgBtB,EAAEuB,OAAF,CAAUX,KAAV,EAAiB,YAAjB,CAApB;AACA,cAAIY,WAAWxB,EAAEyB,GAAF,CAAMH,aAAN,EAAqB,UAACV,KAAD,EAAQc,UAAR,EAAuB;AACzD,gBAAIC,UAAU3B,EAAEyB,GAAF,CAAMb,KAAN,EAAa,QAAb,EAAuBgB,IAAvB,CAA4B,IAA5B,CAAd;AACA,gBAAIC,QAAQQ,mBAAmBX,UAAnB,CAAZ;AACA,gBAAIY,cAActC,EAAEuC,QAAF,CAAW,CAAC,KAAD,EAAQ,KAAR,EAAe,KAAf,CAAX,EAAkCvB,aAAlC,IAAmDA,aAAnD,GAAmE,KAArF;AACAsB,0BAAcE,0BAA0BF,WAA1B,CAAd;;AAEA,gBAAIP,iCAA+Bd,WAA/B,WAAgDA,WAApD;AACA,gBAAIe,kDACyBD,eADzB,sBACyDX,WADzD,SACwEkB,WADxE,qCAEOT,KAFP,uCAGmBF,OAHnB,qCAIgBd,QAJhB,qBAIwCC,QAJxC,+BAKWiB,eALX,uBAAJ;;AAQAC,oBAAQC,gBAAgBD,KAAhB,CAAR;AACA,mBAAO,OAAKrB,cAAL,CAAoBqB,KAApB,CAAP;AACD,WAjBc,CAAf;;AAmBA,iBAAOxB,QAAQ0B,GAAR,CAAYV,QAAZ,EAAsBnB,IAAtB,CAA2B,mBAAW;AAC3C,mBAAOL,EAAEmC,OAAF,CAAUC,OAAV,CAAP;AACD,WAFM,CAAP;AAGD;AAjGwD;AAAA;AAAA,gDAmGjCK,OAnGiC,EAmGxB7B,KAnGwB,EAmGG;AAAA,cAApB8B,WAAoB,uEAAN,IAAM;;AAC1D,iBAAOC,yBAAyBF,OAAzB,EAAkC7B,KAAlC,EAAyC8B,WAAzC,CAAP;AACD;AArGwD;AAAA;AAAA,uCAuG1CV,KAvG0C,EAuGnC;AACpB,cAAIY,WAAW;AACbC,mBAAO,GADM;AAEbC,oBAAQ,aAFK;AAGbhD,0BAAc,KAAKJ,eAHN;AAIbqD,oBAAQf,KAJK;AAKbgB,2BAAe,KAAKpD;AALP,WAAf;;AAQA,iBAAOJ,WAAWyD,iBAAX,CAA6B;AAClCC,iBAAK,iBAD6B;AAElCC,oBAAQ,MAF0B;AAGlCC,kBAAM;AACJC,uBAAS,CAACT,QAAD;AADL;AAH4B,WAA7B,EAONvC,IAPM,CAOD,oBAAY;AAChB,gBAAI+B,UAAUkB,SAASF,IAAT,CAAchB,OAA5B;AACA,gBAAIA,QAAQ,GAAR,CAAJ,EAAkB;AAChB,qBAAOA,QAAQ,GAAR,EAAamB,MAApB;AACD,aAFD,MAEO;AACL,qBAAO,IAAP;AACD;AACF,WAdM,CAAP;AAeD;AA/HwD;;AAAA;AAAA;;AAkI3D,WAAO9D,iBAAP;AACD;;AAMD;;AAEA,WAASkD,wBAAT,CAAkCa,WAAlC,EAA+C5C,KAA/C,EAAsD8B,WAAtD,EAAmE;AACjE,QAAIe,QAAQzD,EAAE0D,MAAF,CAAS1D,EAAEmC,OAAF,CAAUnC,EAAEyB,GAAF,CAAMb,KAAN,EAAa,OAAb,CAAV,CAAT,EAA2C,QAA3C,CAAZ,CADiE,CACC;AAClE,QAAI+C,gBAAgB3D,EAAEyB,GAAF,CAAM+B,WAAN,EAAmB,kBAAU;AAC/C,UAAII,SAASL,OAAOnD,IAApB;AACA,UAAIyD,OAAO7D,EAAEC,IAAF,CAAOW,KAAP,EAAc,EAAC,UAAUgD,MAAX,EAAd,CAAX;AACA,UAAIE,QAAQD,KAAKzD,IAAjB;AACA,UAAIJ,EAAE+D,IAAF,CAAON,KAAP,EAAcO,MAAd,GAAuB,CAAvB,IAA4BtB,WAAhC,EAA6C;AAAE;AAC7C,YAAIuB,OAAOjE,EAAEC,IAAF,CAAOwD,KAAP,EAAc,EAAC,UAAUI,KAAKK,MAAhB,EAAd,CAAX;AACAJ,gBAAQG,KAAK7D,IAAL,GAAY,IAAZ,GAAmB0D,KAA3B;AACD;AACD;AACA;AACA,UAAIK,aAAanE,EAAEoE,SAAF,CAAYb,OAAOc,MAAnB,CAAjB;AACA,aAAO;AACLC,gBAAQR,KADH;AAELK,oBAAYA;AAFP,OAAP;AAID,KAfmB,CAApB;;AAiBA,WAAOnE,EAAEuE,MAAF,CAASZ,aAAT,EAAwB,QAAxB,CAAP;AACD;;AAED,WAAS1B,eAAT,CAAyBD,KAAzB,EAAgC;AAC9B,WAAOA,MAAMwC,OAAN,CAAc,MAAd,EAAsB,GAAtB,CAAP;AACD;;;AAnMMC,a;;AACAzE,O;;;;;;;;;;;;;;;;;;;;;AAEDH,yB,GAAsB,K;AACtBiC,0B,GAAuB;AAC3B,aAAK,SADsB;AAE3B,aAAK,aAFsB;AAG3B,aAAK,aAHsB;AAI3B,aAAK,cAJsB;AAK3B,aAAK;AALsB,O;AAQvBO,wB,GAAqB;AACzB,aAAK,QADoB;AAEzB,aAAK;AAFoB,O;AAKrBhB,uB,GAAoB;AACxB,eAAO,KADiB;AAExB,eAAO,KAFiB;AAGxB,eAAO,KAHiB;AAIxB,eAAO,KAJiB;AAKxB,iBAAS;AALe,O;AAQpBmB,+B,GAA4B;AAChC,eAAO,WADyB;AAEhC,eAAO,WAFyB;AAGhC,eAAO;AAHyB,O;AA4IlCiC,cACGC,MADH,CACU,kBADV,EAEGC,OAFH,CAEW,mBAFX,EAEgCrF,wBAFhC","file":"zabbixDBConnector.js","sourcesContent":["import angular from 'angular';\nimport _ from 'lodash';\n\nconst DEFAULT_QUERY_LIMIT = 10000;\nconst HISTORY_TO_TABLE_MAP = {\n '0': 'history',\n '1': 'history_str',\n '2': 'history_log',\n '3': 'history_uint',\n '4': 'history_text'\n};\n\nconst TREND_TO_TABLE_MAP = {\n '0': 'trends',\n '3': 'trends_uint'\n};\n\nconst consolidateByFunc = {\n 'avg': 'AVG',\n 'min': 'MIN',\n 'max': 'MAX',\n 'sum': 'SUM',\n 'count': 'COUNT'\n};\n\nconst consolidateByTrendColumns = {\n 'avg': 'value_avg',\n 'min': 'value_min',\n 'max': 'value_max'\n};\n\n/** @ngInject */\nfunction ZabbixDBConnectorFactory(datasourceSrv, backendSrv) {\n\n class ZabbixDBConnector {\n\n constructor(sqlDataSourceId, options = {}) {\n let {limit} = options;\n\n this.sqlDataSourceId = sqlDataSourceId;\n this.limit = limit || DEFAULT_QUERY_LIMIT;\n }\n\n /**\n * Try to load DS with given id to check it's exist.\n * @param {*} datasourceId ID of SQL data source\n */\n loadSQLDataSource(datasourceId) {\n let ds = _.find(datasourceSrv.getAll(), {'id': datasourceId});\n if (ds) {\n return datasourceSrv.loadDatasource(ds.name)\n .then(ds => {\n console.log('SQL data source loaded', ds);\n });\n } else {\n return Promise.reject(`SQL Data Source with ID ${datasourceId} not found`);\n }\n }\n\n /**\n * Try to invoke test query for one of Zabbix database tables.\n */\n testSQLDataSource() {\n let testQuery = `SELECT itemid AS metric, clock AS time_sec, value_avg AS value FROM trends_uint LIMIT 1`;\n return this.invokeSQLQuery(testQuery);\n }\n\n getHistory(items, timeFrom, timeTill, options) {\n let {intervalMs, consolidateBy} = options;\n let intervalSec = Math.ceil(intervalMs / 1000);\n\n consolidateBy = consolidateBy || 'avg';\n let aggFunction = consolidateByFunc[consolidateBy];\n\n // Group items by value type and perform request for each value type\n let grouped_items = _.groupBy(items, 'value_type');\n let promises = _.map(grouped_items, (items, value_type) => {\n let itemids = _.map(items, 'itemid').join(', ');\n let table = HISTORY_TO_TABLE_MAP[value_type];\n\n let time_expression = `clock DIV ${intervalSec} * ${intervalSec}`;\n let query = `\n SELECT itemid AS metric, ${time_expression} AS time_sec, ${aggFunction}(value) AS value\n FROM ${table}\n WHERE itemid IN (${itemids})\n AND clock > ${timeFrom} AND clock < ${timeTill}\n GROUP BY ${time_expression}, metric\n `;\n\n query = compactSQLQuery(query);\n return this.invokeSQLQuery(query);\n });\n\n return Promise.all(promises).then(results => {\n return _.flatten(results);\n });\n }\n\n getTrends(items, timeFrom, timeTill, options) {\n let {intervalMs, consolidateBy} = options;\n let intervalSec = Math.ceil(intervalMs / 1000);\n\n consolidateBy = consolidateBy || 'avg';\n let aggFunction = consolidateByFunc[consolidateBy];\n\n // Group items by value type and perform request for each value type\n let grouped_items = _.groupBy(items, 'value_type');\n let promises = _.map(grouped_items, (items, value_type) => {\n let itemids = _.map(items, 'itemid').join(', ');\n let table = TREND_TO_TABLE_MAP[value_type];\n let valueColumn = _.includes(['avg', 'min', 'max'], consolidateBy) ? consolidateBy : 'avg';\n valueColumn = consolidateByTrendColumns[valueColumn];\n\n let time_expression = `clock DIV ${intervalSec} * ${intervalSec}`;\n let query = `\n SELECT itemid AS metric, ${time_expression} AS time_sec, ${aggFunction}(${valueColumn}) AS value\n FROM ${table}\n WHERE itemid IN (${itemids})\n AND clock > ${timeFrom} AND clock < ${timeTill}\n GROUP BY ${time_expression}, metric\n `;\n\n query = compactSQLQuery(query);\n return this.invokeSQLQuery(query);\n });\n\n return Promise.all(promises).then(results => {\n return _.flatten(results);\n });\n }\n\n handleGrafanaTSResponse(history, items, addHostName = true) {\n return convertGrafanaTSResponse(history, items, addHostName);\n }\n\n invokeSQLQuery(query) {\n let queryDef = {\n refId: 'A',\n format: 'time_series',\n datasourceId: this.sqlDataSourceId,\n rawSql: query,\n maxDataPoints: this.limit\n };\n\n return backendSrv.datasourceRequest({\n url: '/api/tsdb/query',\n method: 'POST',\n data: {\n queries: [queryDef],\n }\n })\n .then(response => {\n let results = response.data.results;\n if (results['A']) {\n return results['A'].series;\n } else {\n return null;\n }\n });\n }\n }\n\n return ZabbixDBConnector;\n}\n\nangular\n .module('grafana.services')\n .factory('ZabbixDBConnector', ZabbixDBConnectorFactory);\n\n///////////////////////////////////////////////////////////////////////////////\n\nfunction convertGrafanaTSResponse(time_series, items, addHostName) {\n var hosts = _.uniqBy(_.flatten(_.map(items, 'hosts')), 'hostid'); //uniqBy is needed to deduplicate\n let grafanaSeries = _.map(time_series, series => {\n let itemid = series.name;\n var item = _.find(items, {'itemid': itemid});\n var alias = item.name;\n if (_.keys(hosts).length > 1 && addHostName) { //only when actual multi hosts selected\n var host = _.find(hosts, {'hostid': item.hostid});\n alias = host.name + \": \" + alias;\n }\n // zabbixCachingProxy deduplicates requests and returns one time series for equal queries.\n // Clone is needed to prevent changing of series object shared between all targets.\n let datapoints = _.cloneDeep(series.points);\n return {\n target: alias,\n datapoints: datapoints\n };\n });\n\n return _.sortBy(grafanaSeries, 'target');\n}\n\nfunction compactSQLQuery(query) {\n return query.replace(/\\s+/g, ' ');\n}\n"]} \ No newline at end of file +{"version":3,"sources":["../../src/datasource-zabbix/zabbixDBConnector.js"],"names":["ZabbixDBConnectorFactory","datasourceSrv","backendSrv","ZabbixDBConnector","sqlDataSourceId","options","limit","DEFAULT_QUERY_LIMIT","loadSQLDataSource","datasourceId","ds","_","find","getAll","loadDatasource","name","then","sqlDataSourceType","meta","id","Promise","reject","testQuery","TEST_MYSQL_QUERY","TEST_POSTGRES_QUERY","invokeSQLQuery","items","timeFrom","timeTill","intervalMs","consolidateBy","intervalSec","Math","ceil","aggFunction","consolidateByFunc","grouped_items","groupBy","promises","map","value_type","itemids","join","table","HISTORY_TO_TABLE_MAP","dialect","query","buildSQLHistoryQuery","compactSQLQuery","all","flatten","results","TREND_TO_TABLE_MAP","valueColumn","includes","consolidateByTrendColumns","buildSQLTrendsQuery","history","addHostName","convertGrafanaTSResponse","queryDef","refId","format","rawSql","maxDataPoints","datasourceRequest","url","method","data","queries","response","series","time_series","hosts","uniqBy","grafanaSeries","itemid","item","alias","keys","length","host","hostid","datapoints","cloneDeep","points","target","sortBy","replace","buildPostgresHistoryQuery","buildMysqlHistoryQuery","buildPostgresTrendsQuery","buildMysqlTrendsQuery","time_expression","angular","module","factory"],"mappings":"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","file":"zabbixDBConnector.js","sourcesContent":["import angular from 'angular';\nimport _ from 'lodash';\n\nconst DEFAULT_QUERY_LIMIT = 10000;\nconst HISTORY_TO_TABLE_MAP = {\n '0': 'history',\n '1': 'history_str',\n '2': 'history_log',\n '3': 'history_uint',\n '4': 'history_text'\n};\n\nconst TREND_TO_TABLE_MAP = {\n '0': 'trends',\n '3': 'trends_uint'\n};\n\nconst consolidateByFunc = {\n 'avg': 'AVG',\n 'min': 'MIN',\n 'max': 'MAX',\n 'sum': 'SUM',\n 'count': 'COUNT'\n};\n\nconst consolidateByTrendColumns = {\n 'avg': 'value_avg',\n 'min': 'value_min',\n 'max': 'value_max'\n};\n\n/** @ngInject */\nfunction ZabbixDBConnectorFactory(datasourceSrv, backendSrv) {\n\n class ZabbixDBConnector {\n\n constructor(sqlDataSourceId, options = {}) {\n let {limit} = options;\n\n this.sqlDataSourceId = sqlDataSourceId;\n this.limit = limit || DEFAULT_QUERY_LIMIT;\n\n this.loadSQLDataSource(sqlDataSourceId);\n }\n\n /**\n * Try to load DS with given id to check it's exist.\n * @param {*} datasourceId ID of SQL data source\n */\n loadSQLDataSource(datasourceId) {\n let ds = _.find(datasourceSrv.getAll(), {'id': datasourceId});\n if (ds) {\n return datasourceSrv.loadDatasource(ds.name)\n .then(ds => {\n this.sqlDataSourceType = ds.meta.id;\n return ds;\n });\n } else {\n return Promise.reject(`SQL Data Source with ID ${datasourceId} not found`);\n }\n }\n\n /**\n * Try to invoke test query for one of Zabbix database tables.\n */\n testSQLDataSource() {\n let testQuery = TEST_MYSQL_QUERY;\n if (this.sqlDataSourceType === 'postgres') {\n testQuery = TEST_POSTGRES_QUERY;\n }\n return this.invokeSQLQuery(testQuery);\n }\n\n getHistory(items, timeFrom, timeTill, options) {\n let {intervalMs, consolidateBy} = options;\n let intervalSec = Math.ceil(intervalMs / 1000);\n\n consolidateBy = consolidateBy || 'avg';\n let aggFunction = consolidateByFunc[consolidateBy];\n\n // Group items by value type and perform request for each value type\n let grouped_items = _.groupBy(items, 'value_type');\n let promises = _.map(grouped_items, (items, value_type) => {\n let itemids = _.map(items, 'itemid').join(', ');\n let table = HISTORY_TO_TABLE_MAP[value_type];\n\n let dialect = this.sqlDataSourceType;\n let query = buildSQLHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, dialect);\n\n query = compactSQLQuery(query);\n return this.invokeSQLQuery(query);\n });\n\n return Promise.all(promises).then(results => {\n return _.flatten(results);\n });\n }\n\n getTrends(items, timeFrom, timeTill, options) {\n let {intervalMs, consolidateBy} = options;\n let intervalSec = Math.ceil(intervalMs / 1000);\n\n consolidateBy = consolidateBy || 'avg';\n let aggFunction = consolidateByFunc[consolidateBy];\n\n // Group items by value type and perform request for each value type\n let grouped_items = _.groupBy(items, 'value_type');\n let promises = _.map(grouped_items, (items, value_type) => {\n let itemids = _.map(items, 'itemid').join(', ');\n let table = TREND_TO_TABLE_MAP[value_type];\n let valueColumn = _.includes(['avg', 'min', 'max'], consolidateBy) ? consolidateBy : 'avg';\n valueColumn = consolidateByTrendColumns[valueColumn];\n\n let dialect = this.sqlDataSourceType;\n let query = buildSQLTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn, dialect);\n\n query = compactSQLQuery(query);\n return this.invokeSQLQuery(query);\n });\n\n return Promise.all(promises).then(results => {\n return _.flatten(results);\n });\n }\n\n handleGrafanaTSResponse(history, items, addHostName = true) {\n return convertGrafanaTSResponse(history, items, addHostName);\n }\n\n invokeSQLQuery(query) {\n let queryDef = {\n refId: 'A',\n format: 'time_series',\n datasourceId: this.sqlDataSourceId,\n rawSql: query,\n maxDataPoints: this.limit\n };\n\n return backendSrv.datasourceRequest({\n url: '/api/tsdb/query',\n method: 'POST',\n data: {\n queries: [queryDef],\n }\n })\n .then(response => {\n let results = response.data.results;\n if (results['A']) {\n return results['A'].series;\n } else {\n return null;\n }\n });\n }\n }\n\n return ZabbixDBConnector;\n}\n\nangular\n .module('grafana.services')\n .factory('ZabbixDBConnector', ZabbixDBConnectorFactory);\n\n///////////////////////////////////////////////////////////////////////////////\n\nfunction convertGrafanaTSResponse(time_series, items, addHostName) {\n var hosts = _.uniqBy(_.flatten(_.map(items, 'hosts')), 'hostid'); //uniqBy is needed to deduplicate\n let grafanaSeries = _.map(time_series, series => {\n let itemid = series.name;\n var item = _.find(items, {'itemid': itemid});\n var alias = item.name;\n if (_.keys(hosts).length > 1 && addHostName) { //only when actual multi hosts selected\n var host = _.find(hosts, {'hostid': item.hostid});\n alias = host.name + \": \" + alias;\n }\n // zabbixCachingProxy deduplicates requests and returns one time series for equal queries.\n // Clone is needed to prevent changing of series object shared between all targets.\n let datapoints = _.cloneDeep(series.points);\n return {\n target: alias,\n datapoints: datapoints\n };\n });\n\n return _.sortBy(grafanaSeries, 'target');\n}\n\nfunction compactSQLQuery(query) {\n return query.replace(/\\s+/g, ' ');\n}\n\nfunction buildSQLHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, dialect = 'mysql') {\n if (dialect === 'postgres') {\n return buildPostgresHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction);\n } else {\n return buildMysqlHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction);\n }\n}\n\nfunction buildSQLTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn, dialect = 'mysql') {\n if (dialect === 'postgres') {\n return buildPostgresTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn);\n } else {\n return buildMysqlTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn);\n }\n}\n\n///////////\n// MySQL //\n///////////\n\nfunction buildMysqlHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction) {\n let time_expression = `clock DIV ${intervalSec} * ${intervalSec}`;\n let query = `\n SELECT itemid AS metric, ${time_expression} AS time_sec, ${aggFunction}(value) AS value\n FROM ${table}\n WHERE itemid IN (${itemids})\n AND clock > ${timeFrom} AND clock < ${timeTill}\n GROUP BY ${time_expression}, metric\n ORDER BY time_sec ASC\n `;\n return query;\n}\n\nfunction buildMysqlTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn) {\n let time_expression = `clock DIV ${intervalSec} * ${intervalSec}`;\n let query = `\n SELECT itemid AS metric, ${time_expression} AS time_sec, ${aggFunction}(${valueColumn}) AS value\n FROM ${table}\n WHERE itemid IN (${itemids})\n AND clock > ${timeFrom} AND clock < ${timeTill}\n GROUP BY ${time_expression}, metric\n ORDER BY time_sec ASC\n `;\n return query;\n}\n\nconst TEST_MYSQL_QUERY = `SELECT itemid AS metric, clock AS time_sec, value_avg AS value FROM trends_uint LIMIT 1`;\n\n////////////////\n// PostgreSQL //\n////////////////\n\nfunction buildPostgresHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction) {\n let time_expression = `clock / ${intervalSec} * ${intervalSec}`;\n let query = `\n SELECT DISTINCT to_char(itemid, 'FM9999999999999') AS metric,\n ${time_expression} AS time,\n ${aggFunction}(value) OVER (PARTITION BY clock / ${intervalSec}) AS value\n FROM ${table}\n WHERE itemid IN (${itemids})\n AND clock > ${timeFrom} AND clock < ${timeTill}\n GROUP BY metric, clock, value\n ORDER BY time ASC\n `;\n return query;\n}\n\nfunction buildPostgresTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn) {\n let time_expression = `clock / ${intervalSec} * ${intervalSec}`;\n let query = `\n SELECT DISTINCT to_char(itemid, 'FM9999999999999') AS metric,\n ${time_expression} AS time,\n ${aggFunction}(${valueColumn}) OVER (PARTITION BY clock / ${intervalSec}) AS value\n FROM ${table}\n WHERE itemid IN (${itemids})\n AND clock > ${timeFrom} AND clock < ${timeTill}\n GROUP BY metric, clock, ${valueColumn}\n ORDER BY time ASC\n `;\n return query;\n}\n\nconst TEST_POSTGRES_QUERY = `\n SELECT to_char(itemid, 'FM9999999999999') AS metric, clock AS time, value_avg AS value\n FROM trends_uint LIMIT 1\n`;\n"]} \ No newline at end of file diff --git a/dist/test/datasource-zabbix/config.controller.js b/dist/test/datasource-zabbix/config.controller.js index 4cf0090..02e522f 100644 --- a/dist/test/datasource-zabbix/config.controller.js +++ b/dist/test/datasource-zabbix/config.controller.js @@ -15,7 +15,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -var SUPPORTED_SQL_DS = ['mysql']; +var SUPPORTED_SQL_DS = ['mysql', 'postgres']; var defaultConfig = { dbConnection: { diff --git a/dist/test/datasource-zabbix/zabbixDBConnector.js b/dist/test/datasource-zabbix/zabbixDBConnector.js index 285a2d1..a4f06d8 100644 --- a/dist/test/datasource-zabbix/zabbixDBConnector.js +++ b/dist/test/datasource-zabbix/zabbixDBConnector.js @@ -55,6 +55,8 @@ function ZabbixDBConnectorFactory(datasourceSrv, backendSrv) { this.sqlDataSourceId = sqlDataSourceId; this.limit = limit || DEFAULT_QUERY_LIMIT; + + this.loadSQLDataSource(sqlDataSourceId); } /** @@ -66,10 +68,13 @@ function ZabbixDBConnectorFactory(datasourceSrv, backendSrv) { _createClass(ZabbixDBConnector, [{ key: 'loadSQLDataSource', value: function loadSQLDataSource(datasourceId) { + var _this = this; + var ds = _lodash2.default.find(datasourceSrv.getAll(), { 'id': datasourceId }); if (ds) { return datasourceSrv.loadDatasource(ds.name).then(function (ds) { - console.log('SQL data source loaded', ds); + _this.sqlDataSourceType = ds.meta.id; + return ds; }); } else { return Promise.reject('SQL Data Source with ID ' + datasourceId + ' not found'); @@ -83,13 +88,16 @@ function ZabbixDBConnectorFactory(datasourceSrv, backendSrv) { }, { key: 'testSQLDataSource', value: function testSQLDataSource() { - var testQuery = 'SELECT itemid AS metric, clock AS time_sec, value_avg AS value FROM trends_uint LIMIT 1'; + var testQuery = TEST_MYSQL_QUERY; + if (this.sqlDataSourceType === 'postgres') { + testQuery = TEST_POSTGRES_QUERY; + } return this.invokeSQLQuery(testQuery); } }, { key: 'getHistory', value: function getHistory(items, timeFrom, timeTill, options) { - var _this = this; + var _this2 = this; var intervalMs = options.intervalMs, consolidateBy = options.consolidateBy; @@ -105,11 +113,11 @@ function ZabbixDBConnectorFactory(datasourceSrv, backendSrv) { var itemids = _lodash2.default.map(items, 'itemid').join(', '); var table = HISTORY_TO_TABLE_MAP[value_type]; - var time_expression = 'clock DIV ' + intervalSec + ' * ' + intervalSec; - var query = '\n SELECT itemid AS metric, ' + time_expression + ' AS time_sec, ' + aggFunction + '(value) AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY ' + time_expression + ', metric\n '; + var dialect = _this2.sqlDataSourceType; + var query = buildSQLHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, dialect); query = compactSQLQuery(query); - return _this.invokeSQLQuery(query); + return _this2.invokeSQLQuery(query); }); return Promise.all(promises).then(function (results) { @@ -119,7 +127,7 @@ function ZabbixDBConnectorFactory(datasourceSrv, backendSrv) { }, { key: 'getTrends', value: function getTrends(items, timeFrom, timeTill, options) { - var _this2 = this; + var _this3 = this; var intervalMs = options.intervalMs, consolidateBy = options.consolidateBy; @@ -137,11 +145,11 @@ function ZabbixDBConnectorFactory(datasourceSrv, backendSrv) { var valueColumn = _lodash2.default.includes(['avg', 'min', 'max'], consolidateBy) ? consolidateBy : 'avg'; valueColumn = consolidateByTrendColumns[valueColumn]; - var time_expression = 'clock DIV ' + intervalSec + ' * ' + intervalSec; - var query = '\n SELECT itemid AS metric, ' + time_expression + ' AS time_sec, ' + aggFunction + '(' + valueColumn + ') AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY ' + time_expression + ', metric\n '; + var dialect = _this3.sqlDataSourceType; + var query = buildSQLTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn, dialect); query = compactSQLQuery(query); - return _this2.invokeSQLQuery(query); + return _this3.invokeSQLQuery(query); }); return Promise.all(promises).then(function (results) { @@ -219,3 +227,59 @@ function convertGrafanaTSResponse(time_series, items, addHostName) { function compactSQLQuery(query) { return query.replace(/\s+/g, ' '); } + +function buildSQLHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction) { + var dialect = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 'mysql'; + + if (dialect === 'postgres') { + return buildPostgresHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction); + } else { + return buildMysqlHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction); + } +} + +function buildSQLTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn) { + var dialect = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 'mysql'; + + if (dialect === 'postgres') { + return buildPostgresTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn); + } else { + return buildMysqlTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn); + } +} + +/////////// +// MySQL // +/////////// + +function buildMysqlHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction) { + var time_expression = 'clock DIV ' + intervalSec + ' * ' + intervalSec; + var query = '\n SELECT itemid AS metric, ' + time_expression + ' AS time_sec, ' + aggFunction + '(value) AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY ' + time_expression + ', metric\n ORDER BY time_sec ASC\n '; + return query; +} + +function buildMysqlTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn) { + var time_expression = 'clock DIV ' + intervalSec + ' * ' + intervalSec; + var query = '\n SELECT itemid AS metric, ' + time_expression + ' AS time_sec, ' + aggFunction + '(' + valueColumn + ') AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY ' + time_expression + ', metric\n ORDER BY time_sec ASC\n '; + return query; +} + +var TEST_MYSQL_QUERY = 'SELECT itemid AS metric, clock AS time_sec, value_avg AS value FROM trends_uint LIMIT 1'; + +//////////////// +// PostgreSQL // +//////////////// + +function buildPostgresHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction) { + var time_expression = 'clock / ' + intervalSec + ' * ' + intervalSec; + var query = '\n SELECT DISTINCT to_char(itemid, \'FM9999999999999\') AS metric,\n ' + time_expression + ' AS time,\n ' + aggFunction + '(value) OVER (PARTITION BY clock / ' + intervalSec + ') AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY metric, clock, value\n ORDER BY time ASC\n '; + return query; +} + +function buildPostgresTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn) { + var time_expression = 'clock / ' + intervalSec + ' * ' + intervalSec; + var query = '\n SELECT DISTINCT to_char(itemid, \'FM9999999999999\') AS metric,\n ' + time_expression + ' AS time,\n ' + aggFunction + '(' + valueColumn + ') OVER (PARTITION BY clock / ' + intervalSec + ') AS value\n FROM ' + table + '\n WHERE itemid IN (' + itemids + ')\n AND clock > ' + timeFrom + ' AND clock < ' + timeTill + '\n GROUP BY metric, clock, ' + valueColumn + '\n ORDER BY time ASC\n '; + return query; +} + +var TEST_POSTGRES_QUERY = '\n SELECT to_char(itemid, \'FM9999999999999\') AS metric, clock AS time, value_avg AS value\n FROM trends_uint LIMIT 1\n'; diff --git a/src/datasource-zabbix/config.controller.js b/src/datasource-zabbix/config.controller.js index 226572c..0160ac9 100644 --- a/src/datasource-zabbix/config.controller.js +++ b/src/datasource-zabbix/config.controller.js @@ -1,6 +1,6 @@ import _ from 'lodash'; -const SUPPORTED_SQL_DS = ['mysql']; +const SUPPORTED_SQL_DS = ['mysql', 'postgres']; const defaultConfig = { dbConnection: { diff --git a/src/datasource-zabbix/zabbixDBConnector.js b/src/datasource-zabbix/zabbixDBConnector.js index 84f6c60..487848e 100644 --- a/src/datasource-zabbix/zabbixDBConnector.js +++ b/src/datasource-zabbix/zabbixDBConnector.js @@ -39,6 +39,8 @@ function ZabbixDBConnectorFactory(datasourceSrv, backendSrv) { this.sqlDataSourceId = sqlDataSourceId; this.limit = limit || DEFAULT_QUERY_LIMIT; + + this.loadSQLDataSource(sqlDataSourceId); } /** @@ -50,7 +52,8 @@ function ZabbixDBConnectorFactory(datasourceSrv, backendSrv) { if (ds) { return datasourceSrv.loadDatasource(ds.name) .then(ds => { - console.log('SQL data source loaded', ds); + this.sqlDataSourceType = ds.meta.id; + return ds; }); } else { return Promise.reject(`SQL Data Source with ID ${datasourceId} not found`); @@ -61,7 +64,10 @@ function ZabbixDBConnectorFactory(datasourceSrv, backendSrv) { * Try to invoke test query for one of Zabbix database tables. */ testSQLDataSource() { - let testQuery = `SELECT itemid AS metric, clock AS time_sec, value_avg AS value FROM trends_uint LIMIT 1`; + let testQuery = TEST_MYSQL_QUERY; + if (this.sqlDataSourceType === 'postgres') { + testQuery = TEST_POSTGRES_QUERY; + } return this.invokeSQLQuery(testQuery); } @@ -78,14 +84,8 @@ function ZabbixDBConnectorFactory(datasourceSrv, backendSrv) { let itemids = _.map(items, 'itemid').join(', '); let table = HISTORY_TO_TABLE_MAP[value_type]; - let time_expression = `clock DIV ${intervalSec} * ${intervalSec}`; - let query = ` - SELECT itemid AS metric, ${time_expression} AS time_sec, ${aggFunction}(value) AS value - FROM ${table} - WHERE itemid IN (${itemids}) - AND clock > ${timeFrom} AND clock < ${timeTill} - GROUP BY ${time_expression}, metric - `; + let dialect = this.sqlDataSourceType; + let query = buildSQLHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, dialect); query = compactSQLQuery(query); return this.invokeSQLQuery(query); @@ -111,14 +111,8 @@ function ZabbixDBConnectorFactory(datasourceSrv, backendSrv) { let valueColumn = _.includes(['avg', 'min', 'max'], consolidateBy) ? consolidateBy : 'avg'; valueColumn = consolidateByTrendColumns[valueColumn]; - let time_expression = `clock DIV ${intervalSec} * ${intervalSec}`; - let query = ` - SELECT itemid AS metric, ${time_expression} AS time_sec, ${aggFunction}(${valueColumn}) AS value - FROM ${table} - WHERE itemid IN (${itemids}) - AND clock > ${timeFrom} AND clock < ${timeTill} - GROUP BY ${time_expression}, metric - `; + let dialect = this.sqlDataSourceType; + let query = buildSQLTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn, dialect); query = compactSQLQuery(query); return this.invokeSQLQuery(query); @@ -194,3 +188,90 @@ function convertGrafanaTSResponse(time_series, items, addHostName) { function compactSQLQuery(query) { return query.replace(/\s+/g, ' '); } + +function buildSQLHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, dialect = 'mysql') { + if (dialect === 'postgres') { + return buildPostgresHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction); + } else { + return buildMysqlHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction); + } +} + +function buildSQLTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn, dialect = 'mysql') { + if (dialect === 'postgres') { + return buildPostgresTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn); + } else { + return buildMysqlTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn); + } +} + +/////////// +// MySQL // +/////////// + +function buildMysqlHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction) { + let time_expression = `clock DIV ${intervalSec} * ${intervalSec}`; + let query = ` + SELECT itemid AS metric, ${time_expression} AS time_sec, ${aggFunction}(value) AS value + FROM ${table} + WHERE itemid IN (${itemids}) + AND clock > ${timeFrom} AND clock < ${timeTill} + GROUP BY ${time_expression}, metric + ORDER BY time_sec ASC + `; + return query; +} + +function buildMysqlTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn) { + let time_expression = `clock DIV ${intervalSec} * ${intervalSec}`; + let query = ` + SELECT itemid AS metric, ${time_expression} AS time_sec, ${aggFunction}(${valueColumn}) AS value + FROM ${table} + WHERE itemid IN (${itemids}) + AND clock > ${timeFrom} AND clock < ${timeTill} + GROUP BY ${time_expression}, metric + ORDER BY time_sec ASC + `; + return query; +} + +const TEST_MYSQL_QUERY = `SELECT itemid AS metric, clock AS time_sec, value_avg AS value FROM trends_uint LIMIT 1`; + +//////////////// +// PostgreSQL // +//////////////// + +function buildPostgresHistoryQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction) { + let time_expression = `clock / ${intervalSec} * ${intervalSec}`; + let query = ` + SELECT DISTINCT to_char(itemid, 'FM9999999999999') AS metric, + ${time_expression} AS time, + ${aggFunction}(value) OVER (PARTITION BY clock / ${intervalSec}) AS value + FROM ${table} + WHERE itemid IN (${itemids}) + AND clock > ${timeFrom} AND clock < ${timeTill} + GROUP BY metric, clock, value + ORDER BY time ASC + `; + return query; +} + +function buildPostgresTrendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn) { + let time_expression = `clock / ${intervalSec} * ${intervalSec}`; + let query = ` + SELECT DISTINCT to_char(itemid, 'FM9999999999999') AS metric, + ${time_expression} AS time, + ${aggFunction}(${valueColumn}) OVER (PARTITION BY clock / ${intervalSec}) AS value + FROM ${table} + WHERE itemid IN (${itemids}) + AND clock > ${timeFrom} AND clock < ${timeTill} + GROUP BY metric, clock, ${valueColumn} + ORDER BY time ASC + `; + return query; +} + +const TEST_POSTGRES_QUERY = ` + SELECT to_char(itemid, 'FM9999999999999') AS metric, clock AS time, value_avg AS value + FROM trends_uint LIMIT 1 +`;