datasource: convert to TS

This commit is contained in:
Alexander Zobnin
2020-05-07 11:33:15 +03:00
parent b704bf23c1
commit 44660476ca
2 changed files with 84 additions and 63 deletions

View File

@@ -14,9 +14,33 @@ import { VariableQueryTypes } from './types';
const DEFAULT_ZABBIX_VERSION = 3; const DEFAULT_ZABBIX_VERSION = 3;
export class ZabbixDatasource { export class ZabbixDatasource {
name: string;
url: string;
basicAuth: any;
withCredentials: any;
username: string;
password: string;
trends: boolean;
trendsFrom: string;
trendsRange: string;
cacheTTL: any;
alertingEnabled: boolean;
addThresholds: boolean;
alertingMinSeverity: string;
disableReadOnlyUsersAck: boolean;
zabbixVersion: string;
enableDirectDBConnection: boolean;
dbConnectionDatasourceId: number;
dbConnectionDatasourceName: string;
dbConnectionRetentionPolicy: string;
enableDebugLog: boolean;
zabbix: any;
replaceTemplateVars: (templateSrv: any, target: any, scopedVars?: any) => any;
/** @ngInject */ /** @ngInject */
constructor(instanceSettings, templateSrv, zabbixAlertingSrv) { constructor(instanceSettings, private templateSrv, private zabbixAlertingSrv) {
this.templateSrv = templateSrv; this.templateSrv = templateSrv;
this.zabbixAlertingSrv = zabbixAlertingSrv; this.zabbixAlertingSrv = zabbixAlertingSrv;
@@ -43,7 +67,7 @@ export class ZabbixDatasource {
this.trendsRange = jsonData.trendsRange || '4d'; this.trendsRange = jsonData.trendsRange || '4d';
// Set cache update interval // Set cache update interval
var ttl = jsonData.cacheTTL || '1h'; const ttl = jsonData.cacheTTL || '1h';
this.cacheTTL = utils.parseInterval(ttl); this.cacheTTL = utils.parseInterval(ttl);
// Alerting options // Alerting options
@@ -61,7 +85,7 @@ export class ZabbixDatasource {
this.dbConnectionDatasourceName = jsonData.dbConnectionDatasourceName; this.dbConnectionDatasourceName = jsonData.dbConnectionDatasourceName;
this.dbConnectionRetentionPolicy = jsonData.dbConnectionRetentionPolicy; this.dbConnectionRetentionPolicy = jsonData.dbConnectionRetentionPolicy;
let zabbixOptions = { const zabbixOptions = {
url: this.url, url: this.url,
username: this.username, username: this.username,
password: this.password, password: this.password,
@@ -103,7 +127,7 @@ export class ZabbixDatasource {
} }
// Create request for each target // Create request for each target
let promises = _.map(options.targets, t => { const promises = _.map(options.targets, t => {
// Don't request for hidden targets // Don't request for hidden targets
if (t.hide) { if (t.hide) {
return []; return [];
@@ -123,15 +147,15 @@ export class ZabbixDatasource {
this.replaceTargetVariables(target, options); this.replaceTargetVariables(target, options);
// Apply Time-related functions (timeShift(), etc) // Apply Time-related functions (timeShift(), etc)
let timeFunctions = bindFunctionDefs(target.functions, 'Time'); const timeFunctions = bindFunctionDefs(target.functions, 'Time');
if (timeFunctions.length) { if (timeFunctions.length) {
const [time_from, time_to] = utils.sequence(timeFunctions)([timeFrom, timeTo]); const [time_from, time_to] = utils.sequence(timeFunctions)([timeFrom, timeTo]);
timeFrom = time_from; timeFrom = time_from;
timeTo = time_to; timeTo = time_to;
} }
let timeRange = [timeFrom, timeTo]; const timeRange = [timeFrom, timeTo];
let useTrends = this.isUseTrends(timeRange); const useTrends = this.isUseTrends(timeRange);
// Metrics or Text query // Metrics or Text query
if (!target.queryType || target.queryType === c.MODE_METRICS || target.queryType === c.MODE_TEXT) { if (!target.queryType || target.queryType === c.MODE_METRICS || target.queryType === c.MODE_TEXT) {
@@ -175,7 +199,7 @@ export class ZabbixDatasource {
*/ */
queryNumericData(target, timeRange, useTrends, options) { queryNumericData(target, timeRange, useTrends, options) {
let queryStart, queryEnd; let queryStart, queryEnd;
let getItemOptions = { const getItemOptions = {
itemtype: 'num' itemtype: 'num'
}; };
return this.zabbix.getItemsFromTarget(target, getItemOptions) return this.zabbix.getItemsFromTarget(target, getItemOptions)
@@ -185,7 +209,7 @@ export class ZabbixDatasource {
}).then(result => { }).then(result => {
queryEnd = new Date().getTime(); queryEnd = new Date().getTime();
if (this.enableDebugLog) { if (this.enableDebugLog) {
console.debug(`Datasource::Performance Query Time (${this.name}): ${queryEnd - queryStart}`); console.log(`Datasource::Performance Query Time (${this.name}): ${queryEnd - queryStart}`);
} }
return result; return result;
}); });
@@ -212,18 +236,18 @@ export class ZabbixDatasource {
getTrendValueType(target) { getTrendValueType(target) {
// Find trendValue() function and get specified trend value // Find trendValue() function and get specified trend value
var trendFunctions = _.map(metricFunctions.getCategories()['Trends'], 'name'); const trendFunctions = _.map(metricFunctions.getCategories()['Trends'], 'name');
var trendValueFunc = _.find(target.functions, func => { const trendValueFunc = _.find(target.functions, func => {
return _.includes(trendFunctions, func.def.name); return _.includes(trendFunctions, func.def.name);
}); });
return trendValueFunc ? trendValueFunc.params[0] : "avg"; return trendValueFunc ? trendValueFunc.params[0] : "avg";
} }
applyDataProcessingFunctions(timeseries_data, target) { applyDataProcessingFunctions(timeseries_data, target) {
let transformFunctions = bindFunctionDefs(target.functions, 'Transform'); const transformFunctions = bindFunctionDefs(target.functions, 'Transform');
let aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate'); const aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate');
let filterFunctions = bindFunctionDefs(target.functions, 'Filter'); const filterFunctions = bindFunctionDefs(target.functions, 'Filter');
let aliasFunctions = bindFunctionDefs(target.functions, 'Alias'); const aliasFunctions = bindFunctionDefs(target.functions, 'Alias');
// Apply transformation functions // Apply transformation functions
timeseries_data = _.cloneDeep(_.map(timeseries_data, timeseries => { timeseries_data = _.cloneDeep(_.map(timeseries_data, timeseries => {
@@ -241,8 +265,8 @@ export class ZabbixDatasource {
let dp = _.map(timeseries_data, 'datapoints'); let dp = _.map(timeseries_data, 'datapoints');
dp = utils.sequence(aggregationFunctions)(dp); dp = utils.sequence(aggregationFunctions)(dp);
let aggFuncNames = _.map(metricFunctions.getCategories()['Aggregate'], 'name'); const aggFuncNames = _.map(metricFunctions.getCategories()['Aggregate'], 'name');
let lastAgg = _.findLast(target.functions, func => { const lastAgg = _.findLast(target.functions, func => {
return _.includes(aggFuncNames, func.def.name); return _.includes(aggFuncNames, func.def.name);
}); });
@@ -264,11 +288,11 @@ export class ZabbixDatasource {
applyTimeShiftFunction(timeseries_data, target) { applyTimeShiftFunction(timeseries_data, target) {
// Find timeShift() function and get specified interval // Find timeShift() function and get specified interval
let timeShiftFunc = _.find(target.functions, (func) => { const timeShiftFunc = _.find(target.functions, (func) => {
return func.def.name === 'timeShift'; return func.def.name === 'timeShift';
}); });
if (timeShiftFunc) { if (timeShiftFunc) {
let shift = timeShiftFunc.params[0]; const shift = timeShiftFunc.params[0];
_.forEach(timeseries_data, (series) => { _.forEach(timeseries_data, (series) => {
series.datapoints = dataProcessor.unShiftTimeSeries(shift, series.datapoints); series.datapoints = dataProcessor.unShiftTimeSeries(shift, series.datapoints);
}); });
@@ -279,7 +303,7 @@ export class ZabbixDatasource {
* Query target data for Text * Query target data for Text
*/ */
queryTextData(target, timeRange) { queryTextData(target, timeRange) {
let options = { const options = {
itemtype: 'text' itemtype: 'text'
}; };
return this.zabbix.getItemsFromTarget(target, options) return this.zabbix.getItemsFromTarget(target, options)
@@ -332,14 +356,14 @@ export class ZabbixDatasource {
} }
queryTriggersData(target, timeRange) { queryTriggersData(target, timeRange) {
let [timeFrom, timeTo] = timeRange; const [timeFrom, timeTo] = timeRange;
return this.zabbix.getHostsFromTarget(target) return this.zabbix.getHostsFromTarget(target)
.then(results => { .then(results => {
let [hosts, apps] = results; const [hosts, apps] = results;
if (hosts.length) { if (hosts.length) {
let hostids = _.map(hosts, 'hostid'); const hostids = _.map(hosts, 'hostid');
let appids = _.map(apps, 'applicationid'); const appids = _.map(apps, 'applicationid');
let options = { const options = {
minSeverity: target.triggers.minSeverity, minSeverity: target.triggers.minSeverity,
acknowledged: target.triggers.acknowledged, acknowledged: target.triggers.acknowledged,
count: target.triggers.count, count: target.triggers.count,
@@ -480,16 +504,16 @@ export class ZabbixDatasource {
const timeRange = options.range || options.rangeRaw; const timeRange = options.range || options.rangeRaw;
const timeFrom = Math.ceil(dateMath.parse(timeRange.from) / 1000); const timeFrom = Math.ceil(dateMath.parse(timeRange.from) / 1000);
const timeTo = Math.ceil(dateMath.parse(timeRange.to) / 1000); const timeTo = Math.ceil(dateMath.parse(timeRange.to) / 1000);
var annotation = options.annotation; const annotation = options.annotation;
var showOkEvents = annotation.showOkEvents ? c.SHOW_ALL_EVENTS : c.SHOW_OK_EVENTS; const showOkEvents = annotation.showOkEvents ? c.SHOW_ALL_EVENTS : c.SHOW_OK_EVENTS;
// Show all triggers // Show all triggers
let triggersOptions = { const triggersOptions = {
showTriggers: c.SHOW_ALL_TRIGGERS, showTriggers: c.SHOW_ALL_TRIGGERS,
hideHostsInMaintenance: false hideHostsInMaintenance: false
}; };
var getTriggers = this.zabbix.getTriggers(this.replaceTemplateVars(annotation.group, {}), const getTriggers = this.zabbix.getTriggers(this.replaceTemplateVars(annotation.group, {}),
this.replaceTemplateVars(annotation.host, {}), this.replaceTemplateVars(annotation.host, {}),
this.replaceTemplateVars(annotation.application, {}), this.replaceTemplateVars(annotation.application, {}),
triggersOptions); triggersOptions);
@@ -497,7 +521,7 @@ export class ZabbixDatasource {
return getTriggers.then(triggers => { return getTriggers.then(triggers => {
// Filter triggers by description // Filter triggers by description
let triggerName = this.replaceTemplateVars(annotation.trigger, {}); const triggerName = this.replaceTemplateVars(annotation.trigger, {});
if (utils.isRegex(triggerName)) { if (utils.isRegex(triggerName)) {
triggers = _.filter(triggers, trigger => { triggers = _.filter(triggers, trigger => {
return utils.buildRegex(triggerName).test(trigger.description); return utils.buildRegex(triggerName).test(trigger.description);
@@ -513,11 +537,11 @@ export class ZabbixDatasource {
return Number(trigger.priority) >= Number(annotation.minseverity); return Number(trigger.priority) >= Number(annotation.minseverity);
}); });
var objectids = _.map(triggers, 'triggerid'); const objectids = _.map(triggers, 'triggerid');
return this.zabbix return this.zabbix
.getEvents(objectids, timeFrom, timeTo, showOkEvents) .getEvents(objectids, timeFrom, timeTo, showOkEvents)
.then(events => { .then(events => {
var indexedTriggers = _.keyBy(triggers, 'triggerid'); const indexedTriggers = _.keyBy(triggers, 'triggerid');
// Hide acknowledged events if option enabled // Hide acknowledged events if option enabled
if (annotation.hideAcknowledged) { if (annotation.hideAcknowledged) {
@@ -533,10 +557,10 @@ export class ZabbixDatasource {
} }
// Show event type (OK or Problem) // Show event type (OK or Problem)
let title = Number(event.value) ? 'Problem' : 'OK'; const title = Number(event.value) ? 'Problem' : 'OK';
let formattedAcknowledges = utils.formatAcknowledges(event.acknowledges); const formattedAcknowledges = utils.formatAcknowledges(event.acknowledges);
let eventName = event.name || indexedTriggers[event.objectid].description; const eventName = event.name || indexedTriggers[event.objectid].description;
return { return {
annotation: annotation, annotation: annotation,
time: event.clock * 1000, time: event.clock * 1000,
@@ -555,8 +579,8 @@ export class ZabbixDatasource {
* or empty object if no related triggers are finded. * or empty object if no related triggers are finded.
*/ */
alertQuery(options) { alertQuery(options) {
let enabled_targets = filterEnabledTargets(options.targets); const enabled_targets = filterEnabledTargets(options.targets);
let getPanelItems = _.map(enabled_targets, t => { const getPanelItems = _.map(enabled_targets, t => {
let target = _.cloneDeep(t); let target = _.cloneDeep(t);
target = migrations.migrate(target); target = migrations.migrate(target);
this.replaceTargetVariables(target, options); this.replaceTargetVariables(target, options);
@@ -565,8 +589,8 @@ export class ZabbixDatasource {
return Promise.all(getPanelItems) return Promise.all(getPanelItems)
.then(results => { .then(results => {
let items = _.flatten(results); const items = _.flatten(results);
let itemids = _.map(items, 'itemid'); const itemids = _.map(items, 'itemid');
if (itemids.length === 0) { if (itemids.length === 0) {
return []; return [];
@@ -584,12 +608,12 @@ export class ZabbixDatasource {
let state = 'ok'; let state = 'ok';
let firedTriggers = _.filter(triggers, {value: '1'}); const firedTriggers = _.filter(triggers, {value: '1'});
if (firedTriggers.length) { if (firedTriggers.length) {
state = 'alerting'; state = 'alerting';
} }
let thresholds = _.map(triggers, trigger => { const thresholds = _.map(triggers, trigger => {
return getTriggerThreshold(trigger.expression); return getTriggerThreshold(trigger.expression);
}); });
@@ -603,7 +627,7 @@ export class ZabbixDatasource {
// Replace template variables // Replace template variables
replaceTargetVariables(target, options) { replaceTargetVariables(target, options) {
let parts = ['group', 'host', 'application', 'item']; const parts = ['group', 'host', 'application', 'item'];
_.forEach(parts, p => { _.forEach(parts, p => {
if (target[p] && target[p].filter) { if (target[p] && target[p].filter) {
target[p].filter = this.replaceTemplateVars(target[p].filter, options.scopedVars); target[p].filter = this.replaceTemplateVars(target[p].filter, options.scopedVars);
@@ -623,10 +647,10 @@ export class ZabbixDatasource {
} }
isUseTrends(timeRange) { isUseTrends(timeRange) {
let [timeFrom, timeTo] = timeRange; const [timeFrom, timeTo] = timeRange;
let useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000); const useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000);
let useTrendsRange = Math.ceil(utils.parseInterval(this.trendsRange) / 1000); const useTrendsRange = Math.ceil(utils.parseInterval(this.trendsRange) / 1000);
let useTrends = this.trends && ( const useTrends = this.trends && (
(timeFrom < useTrendsFrom) || (timeFrom < useTrendsFrom) ||
(timeTo - timeFrom > useTrendsRange) (timeTo - timeFrom > useTrendsRange)
); );
@@ -635,20 +659,20 @@ export class ZabbixDatasource {
} }
function bindFunctionDefs(functionDefs, category) { function bindFunctionDefs(functionDefs, category) {
var aggregationFunctions = _.map(metricFunctions.getCategories()[category], 'name'); const aggregationFunctions = _.map(metricFunctions.getCategories()[category], 'name');
var aggFuncDefs = _.filter(functionDefs, function(func) { const aggFuncDefs = _.filter(functionDefs, func => {
return _.includes(aggregationFunctions, func.def.name); return _.includes(aggregationFunctions, func.def.name);
}); });
return _.map(aggFuncDefs, function(func) { return _.map(aggFuncDefs, func => {
var funcInstance = metricFunctions.createFuncInstance(func.def, func.params); const funcInstance = metricFunctions.createFuncInstance(func.def, func.params);
return funcInstance.bindFunction(dataProcessor.metricFunctions); return funcInstance.bindFunction(dataProcessor.metricFunctions);
}); });
} }
function getConsolidateBy(target) { function getConsolidateBy(target) {
let consolidateBy; let consolidateBy;
let funcDef = _.find(target.functions, func => { const funcDef = _.find(target.functions, func => {
return func.def.name === 'consolidateBy'; return func.def.name === 'consolidateBy';
}); });
if (funcDef && funcDef.params && funcDef.params.length) { if (funcDef && funcDef.params && funcDef.params.length) {
@@ -658,8 +682,8 @@ function getConsolidateBy(target) {
} }
function downsampleSeries(timeseries_data, options) { function downsampleSeries(timeseries_data, options) {
let defaultAgg = dataProcessor.aggregationFunctions['avg']; const defaultAgg = dataProcessor.aggregationFunctions['avg'];
let consolidateByFunc = dataProcessor.aggregationFunctions[options.consolidateBy] || defaultAgg; const consolidateByFunc = dataProcessor.aggregationFunctions[options.consolidateBy] || defaultAgg;
return _.map(timeseries_data, timeseries => { return _.map(timeseries_data, timeseries => {
if (timeseries.datapoints.length > options.maxDataPoints) { if (timeseries.datapoints.length > options.maxDataPoints) {
timeseries.datapoints = dataProcessor timeseries.datapoints = dataProcessor
@@ -691,7 +715,7 @@ export function zabbixTemplateFormat(value) {
return utils.escapeRegex(value); return utils.escapeRegex(value);
} }
var escapedValues = _.map(value, utils.escapeRegex); const escapedValues = _.map(value, utils.escapeRegex);
return '(' + escapedValues.join('|') + ')'; return '(' + escapedValues.join('|') + ')';
} }
@@ -711,7 +735,7 @@ function zabbixItemIdsTemplateFormat(value) {
* /$variable/ -> /a|b|c/ -> /a|b|c/ * /$variable/ -> /a|b|c/ -> /a|b|c/
*/ */
function replaceTemplateVars(templateSrv, target, scopedVars) { function replaceTemplateVars(templateSrv, target, scopedVars) {
var replacedTarget = templateSrv.replace(target, scopedVars, zabbixTemplateFormat); let replacedTarget = templateSrv.replace(target, scopedVars, zabbixTemplateFormat);
if (target !== replacedTarget && !utils.isRegex(replacedTarget)) { if (target !== replacedTarget && !utils.isRegex(replacedTarget)) {
replacedTarget = '/^' + replacedTarget + '$/'; replacedTarget = '/^' + replacedTarget + '$/';
} }
@@ -725,8 +749,8 @@ function filterEnabledTargets(targets) {
} }
function getTriggerThreshold(expression) { function getTriggerThreshold(expression) {
let thresholdPattern = /.*[<>=]{1,2}([\d\.]+)/; const thresholdPattern = /.*[<>=]{1,2}([\d\.]+)/;
let finded_thresholds = expression.match(thresholdPattern); const finded_thresholds = expression.match(thresholdPattern);
if (finded_thresholds && finded_thresholds.length >= 2) { if (finded_thresholds && finded_thresholds.length >= 2) {
let threshold = finded_thresholds[1]; let threshold = finded_thresholds[1];
threshold = Number(threshold); threshold = Number(threshold);
@@ -735,7 +759,3 @@ function getTriggerThreshold(expression) {
return null; return null;
} }
} }
// Fix for backward compatibility with lodash 2.4
if (!_.includes) {_.includes = _.contains;}
if (!_.keyBy) {_.keyBy = _.indexBy;}

View File

@@ -222,10 +222,11 @@ export function escapeRegex(value) {
return value.replace(/[\\^$*+?.()|[\]{}\/]/g, '\\$&'); return value.replace(/[\\^$*+?.()|[\]{}\/]/g, '\\$&');
} }
export function parseInterval(interval) { export function parseInterval(interval: string): number {
const intervalPattern = /(^[\d]+)(y|M|w|d|h|m|s)/g; const intervalPattern = /(^[\d]+)(y|M|w|d|h|m|s)/g;
const momentInterval: any[] = intervalPattern.exec(interval); const momentInterval: any[] = intervalPattern.exec(interval);
return moment.duration(Number(momentInterval[1]), momentInterval[2]).valueOf(); const duration = moment.duration(Number(momentInterval[1]), momentInterval[2]);
return (duration.valueOf() as number);
} }
export function parseTimeShiftInterval(interval) { export function parseTimeShiftInterval(interval) {