From de8a1ff621594d96a801fdf19ca3ccbe0f034acd Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Tue, 15 Mar 2016 22:54:02 +0300 Subject: [PATCH] zabbixAPI (-> zabbixAPIService) and zabbixAPIService (-> zabbixAPICoreService) refactor. --- Gruntfile.js | 4 + src/datasource-zabbix/datasource.js | 8 +- src/datasource-zabbix/zabbixAPI.js | 370 --------------- src/datasource-zabbix/zabbixAPICoreService.js | 104 +++++ src/datasource-zabbix/zabbixAPIService.js | 432 ++++++++++++++---- 5 files changed, 463 insertions(+), 455 deletions(-) delete mode 100644 src/datasource-zabbix/zabbixAPI.js create mode 100644 src/datasource-zabbix/zabbixAPICoreService.js diff --git a/Gruntfile.js b/Gruntfile.js index 9823176..4b85222 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -19,6 +19,8 @@ module.exports = function(grunt) { '!**/module.js', '!**/queryCtrl.js', '!**/utils.js', + '!**/zabbixAPICoreService.js', + '!**/zabbixAPIService.js', '!**/*.scss' ], dest: 'dist/src' @@ -53,6 +55,8 @@ module.exports = function(grunt) { '**/**/datasource.js', '**/**/queryCtrl.js', '**/**/utils.js', + '**/**/zabbixAPICoreService.js', + '**/**/zabbixAPIService.js', ], dest: 'dist/src', ext:'.js' diff --git a/src/datasource-zabbix/datasource.js b/src/datasource-zabbix/datasource.js index 24e755d..77eddba 100644 --- a/src/datasource-zabbix/datasource.js +++ b/src/datasource-zabbix/datasource.js @@ -4,14 +4,15 @@ import * as dateMath from 'app/core/utils/datemath'; import * as utils from './utils'; import metricFunctions from './metricFunctions'; import {zabbixHelperSrv} from './helperFunctions'; -import {ZabbixAPI} from './zabbixAPI'; +import './zabbixAPIService'; import {ZabbixCachingProxy} from './zabbixCache'; import {QueryProcessor} from './queryProcessor'; import {DataProcessingService} from './dataProcessingService'; export class ZabbixAPIDatasource { - constructor(instanceSettings, $q, templateSrv, alertSrv, ZabbixAPI, ZabbixCachingProxy, QueryProcessor, zabbixHelperSrv, DataProcessingService) { + /** @ngInject */ + constructor(instanceSettings, $q, templateSrv, alertSrv, zabbixAPIService, ZabbixCachingProxy, QueryProcessor, zabbixHelperSrv, DataProcessingService) { // General data source settings this.name = instanceSettings.name; @@ -32,6 +33,7 @@ export class ZabbixAPIDatasource { this.cacheTTL = utils.parseInterval(ttl); // Initialize Zabbix API + var ZabbixAPI = zabbixAPIService; this.zabbixAPI = new ZabbixAPI(this.url, this.username, this.password, this.basicAuth, this.withCredentials); // Initialize cache service @@ -427,4 +429,4 @@ function formatMetric(metricObj) { text: metricObj.name, expandable: false }; -} \ No newline at end of file +} diff --git a/src/datasource-zabbix/zabbixAPI.js b/src/datasource-zabbix/zabbixAPI.js deleted file mode 100644 index eac7589..0000000 --- a/src/datasource-zabbix/zabbixAPI.js +++ /dev/null @@ -1,370 +0,0 @@ -define([ - 'angular', - 'lodash', - './zabbixAPIService' - ], -function (angular, _) { - 'use strict'; - - var module = angular.module('grafana.services'); - - /** - * Zabbix API Wrapper. - * Creates Zabbix API instance with given parameters (url, credentials and other). - * Wraps API calls and provides high-level methods. - */ - module.factory('ZabbixAPI', function($q, backendSrv, alertSrv, ZabbixAPIService) { - - // Initialize Zabbix API. - function ZabbixAPI(api_url, username, password, basicAuth, withCredentials) { - this.url = api_url; - this.username = username; - this.password = password; - this.auth = ""; - - this.requestOptions = { - basicAuth: basicAuth, - withCredentials: withCredentials - }; - - this.loginPromise = null; - } - - var p = ZabbixAPI.prototype; - - ////////////////// - // Core methods // - ////////////////// - - p.request = function(method, params) { - var self = this; - - return ZabbixAPIService.request(this.url, method, params, this.requestOptions, this.auth) - .then(function(result) { - return result; - }, - // Handle API errors - function(error) { - if (isNotAuthorized(error.data)) { - return self.loginOnce().then( - function() { - return self.request(method, params); - }, - // Handle user.login method errors - function(error) { - self.alertAPIError(error.data); - }); - } - }); - }; - - p.alertAPIError = function(message) { - alertSrv.set( - "Zabbix API Error", - message, - 'error' - ); - }; - - function isNotAuthorized(message) { - return ( - message === "Session terminated, re-login, please." || - message === "Not authorised." || - message === "Not authorized." - ); - } - - /** - * When API unauthenticated or auth token expired each request produce login() - * call. But auth token is common to all requests. This function wraps login() method - * and call it once. If login() already called just wait for it (return its promise). - * @return login promise - */ - p.loginOnce = function() { - var self = this; - var deferred = $q.defer(); - if (!self.loginPromise) { - self.loginPromise = deferred.promise; - self.login().then( - function(auth) { - self.loginPromise = null; - self.auth = auth; - deferred.resolve(auth); - }, - function(error) { - self.loginPromise = null; - deferred.reject(error); - } - ); - } else { - return self.loginPromise; - } - return deferred.promise; - }; - - /** - * Get authentication token. - */ - p.login = function() { - return ZabbixAPIService.login(this.url, this.username, this.password, this.requestOptions); - }; - - /** - * Get Zabbix API version - */ - p.getVersion = function() { - return ZabbixAPIService.getVersion(this.url, this.requestOptions); - }; - - ///////////////// - // API methods // - ///////////////// - - p.getGroups = function() { - var params = { - output: ['name'], - sortfield: 'name', - selectHosts: [] - }; - - return this.request('hostgroup.get', params); - }; - - p.getHosts = function() { - var params = { - output: ['name', 'host'], - sortfield: 'name', - selectGroups: [] - }; - - return this.request('host.get', params); - }; - - p.getApplications = function() { - var params = { - output: ['name'], - sortfield: 'name', - - // Hack for supporting different apis (2.2 vs 2.4 vs 3.0) - selectHost: [], - selectHosts: [] - }; - - return this.request('application.get', params); - }; - - p.getItems = function() { - var params = { - output: [ - 'name', 'key_', - 'value_type', - 'hostid', - 'status', - 'state' - ], - sortfield: 'name', - selectApplications: [] - }; - - return this.request('item.get', params); - }; - - /** - * Get Hosts list with host's items. - * @return {[type]} [description] - */ - p.getHostsExtend = function() { - var params = { - output: ['name', 'host'], - sortfield: 'name', - selectGroups: [], - selectItems: [ - 'name', 'key_', - 'value_type', - 'hostid', - 'status', - 'state' - ] - }; - - return this.request('host.get', params); - }; - - p.getLastValue = function(itemid) { - var params = { - output: ['lastvalue'], - itemids: itemid - }; - return this.request('item.get', params).then(function(items) { - if (items.length) { - return items[0].lastvalue; - } else { - return null; - } - }); - }; - - /** - * Perform history query from Zabbix API - * - * @param {Array} items Array of Zabbix item objects - * @param {Number} time_from Time in seconds - * @param {Number} time_till Time in seconds - * @return {Array} Array of Zabbix history objects - */ - p.getHistory = function(items, time_from, time_till) { - var self = this; - - // Group items by value type - var grouped_items = _.groupBy(items, 'value_type'); - - // Perform request for each value type - return $q.all(_.map(grouped_items, function (items, value_type) { - var itemids = _.map(items, 'itemid'); - var params = { - output: 'extend', - history: value_type, - itemids: itemids, - sortfield: 'clock', - sortorder: 'ASC', - time_from: time_from - }; - - // Relative queries (e.g. last hour) don't include an end time - if (time_till) { - params.time_till = time_till; - } - - return self.request('history.get', params); - })).then(_.flatten); - }; - - /** - * Perform trends query from Zabbix API - * Use trends api extension from ZBXNEXT-1193 patch. - * - * @param {Array} items Array of Zabbix item objects - * @param {Number} time_from Time in seconds - * @param {Number} time_till Time in seconds - * @return {Array} Array of Zabbix trend objects - */ - p.getTrend_ZBXNEXT1193 = function(items, time_from, time_till) { - var self = this; - - // Group items by value type - var grouped_items = _.groupBy(items, 'value_type'); - - // Perform request for each value type - return $q.all(_.map(grouped_items, function (items, value_type) { - var itemids = _.map(items, 'itemid'); - var params = { - output: 'extend', - trend: value_type, - itemids: itemids, - sortfield: 'clock', - sortorder: 'ASC', - time_from: time_from - }; - - // Relative queries (e.g. last hour) don't include an end time - if (time_till) { - params.time_till = time_till; - } - - return self.request('trend.get', params); - })).then(_.flatten); - }; - - p.getTrend_30 = function(items, time_from, time_till, value_type) { - var self = this; - var itemids = _.map(items, 'itemid'); - - var params = { - output: ["itemid", - "clock", - value_type - ], - itemids: itemids, - time_from: time_from - }; - - // Relative queries (e.g. last hour) don't include an end time - if (time_till) { - params.time_till = time_till; - } - - return self.request('trend.get', params); - }; - - p.getTrend = p.getTrend_ZBXNEXT1193; - //p.getTrend = p.getTrend_30; - - p.getITService = function(/* optional */ serviceids) { - var params = { - output: 'extend', - serviceids: serviceids - }; - return this.request('service.get', params); - }; - - p.getSLA = function(serviceids, from, to) { - var params = { - serviceids: serviceids, - intervals: [{ - from: from, - to: to - }] - }; - return this.request('service.getsla', params); - }; - - p.getTriggers = function(groupids, hostids, applicationids, showEvents) { - var params = { - output: 'extend', - groupids: groupids, - hostids: hostids, - applicationids: applicationids, - expandDescription: true, - expandData: true, - monitored: true, - skipDependent: true, - //only_true: true, - filter: { - value: 1 - }, - selectGroups: ['name'], - selectHosts: ['name'], - selectItems: ['name', 'key_', 'lastvalue'], - selectLastEvent: 'extend' - }; - - if (showEvents) { - params.filter.value = showEvents; - } - - return this.request('trigger.get', params); - }; - - p.getAcknowledges = function(eventids) { - var params = { - output: 'extend', - eventids: eventids, - preservekeys: true, - select_acknowledges: 'extend', - sortfield: 'clock', - sortorder: 'DESC' - }; - - return this.request('event.get', params) - .then(function (events) { - return _.filter(events, function(event) { - return event.acknowledges.length; - }); - }); - }; - - return ZabbixAPI; - - }); - -}); diff --git a/src/datasource-zabbix/zabbixAPICoreService.js b/src/datasource-zabbix/zabbixAPICoreService.js new file mode 100644 index 0000000..a1623e6 --- /dev/null +++ b/src/datasource-zabbix/zabbixAPICoreService.js @@ -0,0 +1,104 @@ +/** + * General Zabbix API methods + */ + +import angular from 'angular'; + +class ZabbixAPICoreService { + + /** @ngInject */ + constructor($q, backendSrv) { + this.$q = $q; + this.backendSrv = backendSrv; + } + + /** + * Request data from Zabbix API + * @return {object} response.result + */ + request(api_url, method, params, options, auth) { + var deferred = this.$q.defer(); + var requestData = { + jsonrpc: '2.0', + method: method, + params: params, + id: 1 + }; + + if (auth === "") { + // Reject immediately if not authenticated + deferred.reject({data: "Not authorised."}); + return deferred.promise; + } else if (auth) { + // Set auth parameter only if it needed + requestData.auth = auth; + } + + var requestOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + url: api_url, + data: requestData + }; + + // Set request options for basic auth + if (options.basicAuth || options.withCredentials) { + requestOptions.withCredentials = true; + } + if (options.basicAuth) { + requestOptions.headers.Authorization = options.basicAuth; + } + + this.backendSrv.datasourceRequest(requestOptions).then(function (response) { + // General connection issues + if (!response.data) { + deferred.reject(response); + } + + // Handle Zabbix API errors + else if (response.data.error) { + deferred.reject(response.data.error); + } + + deferred.resolve(response.data.result); + }); + return deferred.promise; + } + + /** + * Get authentication token. + * @return {string} auth token + */ + login(api_url, username, password, options) { + var params = { + user: username, + password: password + }; + return this.request(api_url, 'user.login', params, options, null); + } + + /** + * Get Zabbix API version + * Matches the version of Zabbix starting from Zabbix 2.0.4 + */ + getVersion(api_url, options) { + return this.request(api_url, 'apiinfo.version', [], options); + } +} + +// Define zabbix API exception type +function ZabbixException(error) { + this.code = error.code; + this.errorType = error.message; + this.message = error.data; +} + +ZabbixException.prototype.toString = function() { + return this.errorType + ": " + this.message; +}; + +angular + .module('grafana.services') + .service('zabbixAPICoreService', ZabbixAPICoreService); diff --git a/src/datasource-zabbix/zabbixAPIService.js b/src/datasource-zabbix/zabbixAPIService.js index 03f7789..d2f89f7 100644 --- a/src/datasource-zabbix/zabbixAPIService.js +++ b/src/datasource-zabbix/zabbixAPIService.js @@ -1,103 +1,371 @@ -/** - * General Zabbix API methods - */ +import angular from 'angular'; +import _ from 'lodash'; +import './zabbixAPICoreService'; -define([ - 'angular', -], -function (angular) { - 'use strict'; +/** @ngInject */ +function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) { - var module = angular.module('grafana.services'); + /** + * Zabbix API Wrapper. + * Creates Zabbix API instance with given parameters (url, credentials and other). + * Wraps API calls and provides high-level methods. + */ + class ZabbixAPI { - module.service('ZabbixAPIService', function($q, backendSrv) { + constructor(api_url, username, password, basicAuth, withCredentials) { + this.url = api_url; + this.username = username; + this.password = password; + this.auth = ""; + + this.requestOptions = { + basicAuth: basicAuth, + withCredentials: withCredentials + }; + + this.loginPromise = null; + + this.$q = $q; + this.alertSrv = alertSrv; + this.zabbixAPICore = zabbixAPICoreService; + + this.getTrend = this.getTrend_ZBXNEXT1193; + //getTrend = getTrend_30; + } + + ////////////////////////// + // Core method wrappers // + ////////////////////////// + + request(method, params) { + var self = this; + + return this.zabbixAPICore.request(this.url, method, params, this.requestOptions, this.auth) + .then(function(result) { + return result; + }, + // Handle API errors + function(error) { + if (isNotAuthorized(error.data)) { + return self.loginOnce().then( + function() { + return self.request(method, params); + }, + // Handle user.login method errors + function(error) { + self.alertAPIError(error.data); + }); + } + }); + } + + alertAPIError(message) { + this.alertSrv.set( + "Zabbix API Error", + message, + 'error' + ); + } /** - * Request data from Zabbix API - * @return {object} response.result + * When API unauthenticated or auth token expired each request produce login() + * call. But auth token is common to all requests. This function wraps login() method + * and call it once. If login() already called just wait for it (return its promise). + * @return login promise */ - this.request = function(api_url, method, params, options, auth) { - var deferred = $q.defer(); - var requestData = { - jsonrpc: '2.0', - method: method, - params: params, - id: 1 - }; - - if (auth === "") { - // Reject immediately if not authenticated - deferred.reject({data: "Not authorised."}); - return deferred.promise; - } else if (auth) { - // Set auth parameter only if it needed - requestData.auth = auth; + loginOnce() { + var self = this; + var deferred = this.$q.defer(); + if (!self.loginPromise) { + self.loginPromise = deferred.promise; + self.login().then( + function(auth) { + self.loginPromise = null; + self.auth = auth; + deferred.resolve(auth); + }, + function(error) { + self.loginPromise = null; + deferred.reject(error); + } + ); + } else { + return self.loginPromise; } - - var requestOptions = { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - url: api_url, - data: requestData - }; - - // Set request options for basic auth - if (options.basicAuth || options.withCredentials) { - requestOptions.withCredentials = true; - } - if (options.basicAuth) { - requestOptions.headers.Authorization = options.basicAuth; - } - - backendSrv.datasourceRequest(requestOptions).then(function (response) { - // General connection issues - if (!response.data) { - deferred.reject(response); - } - - // Handle Zabbix API errors - else if (response.data.error) { - deferred.reject(response.data.error); - } - - deferred.resolve(response.data.result); - }); return deferred.promise; - }; + } /** * Get authentication token. - * @return {string} auth token */ - this.login = function(api_url, username, password, options) { - var params = { - user: username, - password: password - }; - return this.request(api_url, 'user.login', params, options, null); - }; + login() { + return this.zabbixAPICore.login(this.url, this.username, this.password, this.requestOptions); + } /** * Get Zabbix API version - * Matches the version of Zabbix starting from Zabbix 2.0.4 */ - this.getVersion = function(api_url, options) { - return this.request(api_url, 'apiinfo.version', [], options); - }; + getVersion() { + return this.zabbixAPICore.getVersion(this.url, this.requestOptions); + } - }); + //////////////////////////////// + // Zabbix API method wrappers // + //////////////////////////////// + + getGroups() { + var params = { + output: ['name'], + sortfield: 'name', + selectHosts: [] + }; + + return this.request('hostgroup.get', params); + } + + getHosts() { + var params = { + output: ['name', 'host'], + sortfield: 'name', + selectGroups: [] + }; + + return this.request('host.get', params); + } + + getApplications() { + var params = { + output: ['name'], + sortfield: 'name', + + // Hack for supporting different apis (2.2 vs 2.4 vs 3.0) + selectHost: [], + selectHosts: [] + }; + + return this.request('application.get', params); + } + + getItems() { + var params = { + output: [ + 'name', 'key_', + 'value_type', + 'hostid', + 'status', + 'state' + ], + sortfield: 'name', + selectApplications: [] + }; + + return this.request('item.get', params); + } + + /** + * Get Hosts list with host's items. + * @return {[type]} [description] + */ + getHostsExtend() { + var params = { + output: ['name', 'host'], + sortfield: 'name', + selectGroups: [], + selectItems: [ + 'name', 'key_', + 'value_type', + 'hostid', + 'status', + 'state' + ] + }; + + return this.request('host.get', params); + } + + getLastValue(itemid) { + var params = { + output: ['lastvalue'], + itemids: itemid + }; + return this.request('item.get', params).then(function(items) { + if (items.length) { + return items[0].lastvalue; + } else { + return null; + } + }); + } + + /** + * Perform history query from Zabbix API + * + * @param {Array} items Array of Zabbix item objects + * @param {Number} time_from Time in seconds + * @param {Number} time_till Time in seconds + * @return {Array} Array of Zabbix history objects + */ + getHistory(items, time_from, time_till) { + var self = this; + + // Group items by value type + var grouped_items = _.groupBy(items, 'value_type'); + + // Perform request for each value type + return this.$q.all(_.map(grouped_items, function (items, value_type) { + var itemids = _.map(items, 'itemid'); + var params = { + output: 'extend', + history: value_type, + itemids: itemids, + sortfield: 'clock', + sortorder: 'ASC', + time_from: time_from + }; + + // Relative queries (e.g. last hour) don't include an end time + if (time_till) { + params.time_till = time_till; + } + + return self.request('history.get', params); + })).then(_.flatten); + } + + /** + * Perform trends query from Zabbix API + * Use trends api extension from ZBXNEXT-1193 patch. + * + * @param {Array} items Array of Zabbix item objects + * @param {Number} time_from Time in seconds + * @param {Number} time_till Time in seconds + * @return {Array} Array of Zabbix trend objects + */ + getTrend_ZBXNEXT1193(items, time_from, time_till) { + var self = this; + + // Group items by value type + var grouped_items = _.groupBy(items, 'value_type'); + + // Perform request for each value type + return this.$q.all(_.map(grouped_items, function (items, value_type) { + var itemids = _.map(items, 'itemid'); + var params = { + output: 'extend', + trend: value_type, + itemids: itemids, + sortfield: 'clock', + sortorder: 'ASC', + time_from: time_from + }; + + // Relative queries (e.g. last hour) don't include an end time + if (time_till) { + params.time_till = time_till; + } + + return self.request('trend.get', params); + })).then(_.flatten); + } + + getTrend_30(items, time_from, time_till, value_type) { + var self = this; + var itemids = _.map(items, 'itemid'); + + var params = { + output: ["itemid", + "clock", + value_type + ], + itemids: itemids, + time_from: time_from + }; + + // Relative queries (e.g. last hour) don't include an end time + if (time_till) { + params.time_till = time_till; + } + + return self.request('trend.get', params); + } + + getITService(/* optional */ serviceids) { + var params = { + output: 'extend', + serviceids: serviceids + }; + return this.request('service.get', params); + } + + getSLA(serviceids, from, to) { + var params = { + serviceids: serviceids, + intervals: [{ + from: from, + to: to + }] + }; + return this.request('service.getsla', params); + } + + getTriggers(groupids, hostids, applicationids, showEvents) { + var params = { + output: 'extend', + groupids: groupids, + hostids: hostids, + applicationids: applicationids, + expandDescription: true, + expandData: true, + monitored: true, + skipDependent: true, + //only_true: true, + filter: { + value: 1 + }, + selectGroups: ['name'], + selectHosts: ['name'], + selectItems: ['name', 'key_', 'lastvalue'], + selectLastEvent: 'extend' + }; + + if (showEvents) { + params.filter.value = showEvents; + } + + return this.request('trigger.get', params); + } + + getAcknowledges(eventids) { + var params = { + output: 'extend', + eventids: eventids, + preservekeys: true, + select_acknowledges: 'extend', + sortfield: 'clock', + sortorder: 'DESC' + }; + + return this.request('event.get', params) + .then(function (events) { + return _.filter(events, function(event) { + return event.acknowledges.length; + }); + }); + } - // Define zabbix API exception type - function ZabbixException(error) { - this.code = error.code; - this.errorType = error.message; - this.message = error.data; } - ZabbixException.prototype.toString = function() { - return this.errorType + ": " + this.message; - }; + return ZabbixAPI; +} -}); \ No newline at end of file +function isNotAuthorized(message) { + return ( + message === "Session terminated, re-login, please." || + message === "Not authorised." || + message === "Not authorized." + ); +} + +angular + .module('grafana.services') + .factory('zabbixAPIService', ZabbixAPIService);