Merge branch 'feat-418', closes #418
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import mocks from '../../test-setup/mocks';
|
||||||
import { Datasource } from "../module";
|
import { Datasource } from "../module";
|
||||||
import { zabbixTemplateFormat } from "../datasource";
|
import { zabbixTemplateFormat } from "../datasource";
|
||||||
|
|
||||||
@@ -17,15 +18,11 @@ describe('ZabbixDatasource', () => {
|
|||||||
dbConnectionEnable: false
|
dbConnectionEnable: false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ctx.templateSrv = {};
|
|
||||||
ctx.backendSrv = {
|
ctx.templateSrv = mocks.templateSrvMock;
|
||||||
datasourceRequest: jest.fn()
|
ctx.backendSrv = mocks.backendSrvMock;
|
||||||
};
|
ctx.datasourceSrv = mocks.datasourceSrvMock;
|
||||||
ctx.datasourceSrv = {};
|
ctx.zabbixAlertingSrv = mocks.zabbixAlertingSrvMock;
|
||||||
ctx.zabbixAlertingSrv = {
|
|
||||||
setPanelAlertState: jest.fn(),
|
|
||||||
removeZabbixThreshold: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
ctx.ds = new Datasource(ctx.instanceSettings, ctx.templateSrv, ctx.backendSrv, ctx.datasourceSrv, ctx.zabbixAlertingSrv);
|
ctx.ds = new Datasource(ctx.instanceSettings, ctx.templateSrv, ctx.backendSrv, ctx.datasourceSrv, ctx.zabbixAlertingSrv);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
|
import mocks from '../../test-setup/mocks';
|
||||||
import DBConnector from '../zabbix/connectors/dbConnector';
|
import DBConnector from '../zabbix/connectors/dbConnector';
|
||||||
|
|
||||||
describe('DBConnector', () => {
|
describe('DBConnector', () => {
|
||||||
let ctx = {};
|
let ctx = {};
|
||||||
const backendSrvMock = {};
|
const backendSrv = mocks.backendSrvMock;
|
||||||
const datasourceSrvMock = {
|
const datasourceSrv = mocks.datasourceSrvMock;
|
||||||
loadDatasource: jest.fn().mockResolvedValue(
|
datasourceSrv.loadDatasource.mockResolvedValue({ id: 42, name: 'foo', meta: {} });
|
||||||
{ id: 42, name: 'foo', meta: {} }
|
datasourceSrv.getAll.mockReturnValue([{ id: 42, name: 'foo' }]);
|
||||||
),
|
|
||||||
getAll: jest.fn().mockReturnValue([
|
|
||||||
{ id: 42, name: 'foo' }
|
|
||||||
])
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('When init DB connector', () => {
|
describe('When init DB connector', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -24,28 +20,28 @@ describe('DBConnector', () => {
|
|||||||
ctx.options = {
|
ctx.options = {
|
||||||
datasourceName: 'bar'
|
datasourceName: 'bar'
|
||||||
};
|
};
|
||||||
const dbConnector = new DBConnector(ctx.options, backendSrvMock, datasourceSrvMock);
|
const dbConnector = new DBConnector(ctx.options, backendSrv, datasourceSrv);
|
||||||
dbConnector.loadDBDataSource();
|
dbConnector.loadDBDataSource();
|
||||||
expect(datasourceSrvMock.getAll).not.toHaveBeenCalled();
|
expect(datasourceSrv.getAll).not.toHaveBeenCalled();
|
||||||
expect(datasourceSrvMock.loadDatasource).toHaveBeenCalledWith('bar');
|
expect(datasourceSrv.loadDatasource).toHaveBeenCalledWith('bar');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load datasource by id if name not present', () => {
|
it('should load datasource by id if name not present', () => {
|
||||||
const dbConnector = new DBConnector(ctx.options, backendSrvMock, datasourceSrvMock);
|
const dbConnector = new DBConnector(ctx.options, backendSrv, datasourceSrv);
|
||||||
dbConnector.loadDBDataSource();
|
dbConnector.loadDBDataSource();
|
||||||
expect(datasourceSrvMock.getAll).toHaveBeenCalled();
|
expect(datasourceSrv.getAll).toHaveBeenCalled();
|
||||||
expect(datasourceSrvMock.loadDatasource).toHaveBeenCalledWith('foo');
|
expect(datasourceSrv.loadDatasource).toHaveBeenCalledWith('foo');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw error if no name and id specified', () => {
|
it('should throw error if no name and id specified', () => {
|
||||||
ctx.options = {};
|
ctx.options = {};
|
||||||
const dbConnector = new DBConnector(ctx.options, backendSrvMock, datasourceSrvMock);
|
const dbConnector = new DBConnector(ctx.options, backendSrv, datasourceSrv);
|
||||||
return expect(dbConnector.loadDBDataSource()).rejects.toBe('SQL Data Source name should be specified');
|
return expect(dbConnector.loadDBDataSource()).rejects.toBe('SQL Data Source name should be specified');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw error if datasource with given id is not found', () => {
|
it('should throw error if datasource with given id is not found', () => {
|
||||||
ctx.options.datasourceId = 45;
|
ctx.options.datasourceId = 45;
|
||||||
const dbConnector = new DBConnector(ctx.options, backendSrvMock, datasourceSrvMock);
|
const dbConnector = new DBConnector(ctx.options, backendSrv, datasourceSrv);
|
||||||
return expect(dbConnector.loadDBDataSource()).rejects.toBe('SQL Data Source with ID 45 not found');
|
return expect(dbConnector.loadDBDataSource()).rejects.toBe('SQL Data Source with ID 45 not found');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ export class ZabbixAPIConnector {
|
|||||||
value: 1
|
value: 1
|
||||||
},
|
},
|
||||||
selectGroups: ['name'],
|
selectGroups: ['name'],
|
||||||
selectHosts: ['name', 'host', 'maintenance_status'],
|
selectHosts: ['name', 'host', 'maintenance_status', 'proxy_hostid'],
|
||||||
selectItems: ['name', 'key_', 'lastvalue'],
|
selectItems: ['name', 'key_', 'lastvalue'],
|
||||||
selectLastEvent: 'extend',
|
selectLastEvent: 'extend',
|
||||||
selectTags: 'extend'
|
selectTags: 'extend'
|
||||||
@@ -463,6 +463,14 @@ export class ZabbixAPIConnector {
|
|||||||
return triggers;
|
return triggers;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProxies() {
|
||||||
|
var params = {
|
||||||
|
output: ['proxyid', 'host'],
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.request('proxy.get', params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterTriggersByAcknowledge(triggers, acknowledged) {
|
function filterTriggersByAcknowledge(triggers, acknowledged) {
|
||||||
|
|||||||
@@ -8,16 +8,16 @@ import { ZabbixNotImplemented } from './connectors/dbConnector';
|
|||||||
|
|
||||||
const REQUESTS_TO_PROXYFY = [
|
const REQUESTS_TO_PROXYFY = [
|
||||||
'getHistory', 'getTrend', 'getGroups', 'getHosts', 'getApps', 'getItems', 'getMacros', 'getItemsByIDs',
|
'getHistory', 'getTrend', 'getGroups', 'getHosts', 'getApps', 'getItems', 'getMacros', 'getItemsByIDs',
|
||||||
'getEvents', 'getAlerts', 'getHostAlerts', 'getAcknowledges', 'getITService', 'getSLA', 'getVersion'
|
'getEvents', 'getAlerts', 'getHostAlerts', 'getAcknowledges', 'getITService', 'getSLA', 'getVersion', 'getProxies'
|
||||||
];
|
];
|
||||||
|
|
||||||
const REQUESTS_TO_CACHE = [
|
const REQUESTS_TO_CACHE = [
|
||||||
'getGroups', 'getHosts', 'getApps', 'getItems', 'getMacros', 'getItemsByIDs', 'getITService'
|
'getGroups', 'getHosts', 'getApps', 'getItems', 'getMacros', 'getItemsByIDs', 'getITService', 'getProxies'
|
||||||
];
|
];
|
||||||
|
|
||||||
const REQUESTS_TO_BIND = [
|
const REQUESTS_TO_BIND = [
|
||||||
'getHistory', 'getTrend', 'getMacros', 'getItemsByIDs', 'getEvents', 'getAlerts', 'getHostAlerts',
|
'getHistory', 'getTrend', 'getMacros', 'getItemsByIDs', 'getEvents', 'getAlerts', 'getHostAlerts',
|
||||||
'getAcknowledges', 'getITService', 'getVersion', 'login', 'acknowledgeEvent'
|
'getAcknowledges', 'getITService', 'getVersion', 'login', 'acknowledgeEvent', 'getProxies'
|
||||||
];
|
];
|
||||||
|
|
||||||
export class Zabbix {
|
export class Zabbix {
|
||||||
@@ -243,7 +243,7 @@ export class Zabbix {
|
|||||||
/**
|
/**
|
||||||
* Build query - convert target filters to array of Zabbix items
|
* Build query - convert target filters to array of Zabbix items
|
||||||
*/
|
*/
|
||||||
getTriggers(groupFilter, hostFilter, appFilter, options) {
|
getTriggers(groupFilter, hostFilter, appFilter, options, proxyFilter) {
|
||||||
let promises = [
|
let promises = [
|
||||||
this.getGroups(groupFilter),
|
this.getGroups(groupFilter),
|
||||||
this.getHosts(groupFilter, hostFilter),
|
this.getHosts(groupFilter, hostFilter),
|
||||||
@@ -252,9 +252,7 @@ export class Zabbix {
|
|||||||
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
.then(results => {
|
.then(results => {
|
||||||
let filteredGroups = results[0];
|
let [filteredGroups, filteredHosts, filteredApps] = results;
|
||||||
let filteredHosts = results[1];
|
|
||||||
let filteredApps = results[2];
|
|
||||||
let query = {};
|
let query = {};
|
||||||
|
|
||||||
if (appFilter) {
|
if (appFilter) {
|
||||||
@@ -268,8 +266,36 @@ export class Zabbix {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
}).then(query => {
|
})
|
||||||
return this.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, options);
|
.then(query => this.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, options))
|
||||||
|
.then(triggers => this.filterTriggersByProxy(triggers, proxyFilter));
|
||||||
|
}
|
||||||
|
|
||||||
|
filterTriggersByProxy(triggers, proxyFilter) {
|
||||||
|
return this.getFilteredProxies(proxyFilter)
|
||||||
|
.then(proxies => {
|
||||||
|
if (proxyFilter && proxyFilter !== '/.*/' && triggers) {
|
||||||
|
const proxy_ids = proxies.map(proxy => proxy.proxyid);
|
||||||
|
triggers = triggers.filter(trigger => {
|
||||||
|
let filtered = false;
|
||||||
|
for(let i = 0; i < trigger.hosts.length; i++) {
|
||||||
|
const host = trigger.hosts[i];
|
||||||
|
if (proxy_ids.includes(host.proxy_hostid)) {
|
||||||
|
filtered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filtered;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return triggers;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getFilteredProxies(proxyFilter) {
|
||||||
|
return this.zabbixAPI.getProxies()
|
||||||
|
.then(proxies => {
|
||||||
|
proxies.forEach(proxy => proxy.name = proxy.host);
|
||||||
|
return findByFilter(proxies, proxyFilter);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
98
src/datasource-zabbix/zabbix/zabbix.test.js
Normal file
98
src/datasource-zabbix/zabbix/zabbix.test.js
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import mocks from '../../test-setup/mocks';
|
||||||
|
import { Zabbix } from './zabbix';
|
||||||
|
|
||||||
|
describe('Zabbix', () => {
|
||||||
|
let ctx = {};
|
||||||
|
let zabbix;
|
||||||
|
let options = {
|
||||||
|
url: 'http://localhost',
|
||||||
|
username: 'zabbix',
|
||||||
|
password: 'zabbix',
|
||||||
|
zabbixVersion: 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ctx.options = options;
|
||||||
|
ctx.backendSrv = mocks.backendSrvMock;
|
||||||
|
ctx.datasourceSrv = mocks.datasourceSrvMock;
|
||||||
|
zabbix = new Zabbix(ctx.options, ctx.backendSrvMock, ctx.datasourceSrvMock);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When querying proxies', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
zabbix.zabbixAPI.getProxies = jest.fn().mockResolvedValue([
|
||||||
|
{ host: 'proxy-foo', proxyid: '10101' },
|
||||||
|
{ host: 'proxy-bar', proxyid: '10102' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return all proxies if filter set to /.*/", done => {
|
||||||
|
zabbix.getFilteredProxies('/.*/').then(proxies => {
|
||||||
|
expect(proxies).toMatchObject([{ host: 'proxy-foo' }, { host: 'proxy-bar' }]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return matched proxies if regex filter used", done => {
|
||||||
|
zabbix.getFilteredProxies('/.*-foo/').then(proxies => {
|
||||||
|
expect(proxies).toMatchObject([{ host: 'proxy-foo' }]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return matched proxies if simple filter used", done => {
|
||||||
|
zabbix.getFilteredProxies('proxy-bar').then(proxies => {
|
||||||
|
expect(proxies).toMatchObject([{ host: 'proxy-bar' }]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return empty list for empty filter", done => {
|
||||||
|
zabbix.getFilteredProxies('').then(proxies => {
|
||||||
|
expect(proxies).toEqual([]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When filtering triggers by proxy', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
zabbix.zabbixAPI.getProxies = jest.fn().mockResolvedValue([
|
||||||
|
{ host: 'proxy-foo', proxyid: '10101' },
|
||||||
|
{ host: 'proxy-bar', proxyid: '10102' },
|
||||||
|
]);
|
||||||
|
ctx.triggers = [
|
||||||
|
{ triggerid: '1', hosts: [{ name: 'backend01', proxy_hostid: '0' }] },
|
||||||
|
{ triggerid: '2', hosts: [{ name: 'backend02', proxy_hostid: '0' }] },
|
||||||
|
{ triggerid: '3', hosts: [{ name: 'frontend01', proxy_hostid: '10101' }] },
|
||||||
|
{ triggerid: '4', hosts: [{ name: 'frontend02', proxy_hostid: '10101' }] },
|
||||||
|
{ triggerid: '5', hosts: [{ name: 'db01', proxy_hostid: '10102' }] },
|
||||||
|
{ triggerid: '6', hosts: [{ name: 'db02', proxy_hostid: '10102' }] },
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return all triggers for empty filter", done => {
|
||||||
|
zabbix.filterTriggersByProxy(ctx.triggers, '').then(triggers => {
|
||||||
|
const triggerids = triggers.map(t => t.triggerid);
|
||||||
|
expect(triggerids).toEqual(['1', '2', '3', '4', '5', '6']);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return triggers belonging proxy matched regex filter", done => {
|
||||||
|
zabbix.filterTriggersByProxy(ctx.triggers, '/.*-foo/').then(triggers => {
|
||||||
|
const triggerids = triggers.map(t => t.triggerid);
|
||||||
|
expect(triggerids).toEqual(['3', '4']);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return triggers belonging proxy matched name filter", done => {
|
||||||
|
zabbix.filterTriggersByProxy(ctx.triggers, 'proxy-bar').then(triggers => {
|
||||||
|
const triggerids = triggers.map(t => t.triggerid);
|
||||||
|
expect(triggerids).toEqual(['5', '6']);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,7 +2,7 @@ import _ from 'lodash';
|
|||||||
import {DEFAULT_TARGET} from './triggers_panel_ctrl';
|
import {DEFAULT_TARGET} from './triggers_panel_ctrl';
|
||||||
|
|
||||||
// Actual schema version
|
// Actual schema version
|
||||||
export const CURRENT_SCHEMA_VERSION = 4;
|
export const CURRENT_SCHEMA_VERSION = 5;
|
||||||
|
|
||||||
export function migratePanelSchema(panel) {
|
export function migratePanelSchema(panel) {
|
||||||
if (isEmptyPanel(panel)) {
|
if (isEmptyPanel(panel)) {
|
||||||
@@ -31,7 +31,7 @@ export function migratePanelSchema(panel) {
|
|||||||
delete panel.hideHostsInMaintenance;
|
delete panel.hideHostsInMaintenance;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schemaVersion < 4) {
|
if (schemaVersion < 5) {
|
||||||
if (panel.targets && !_.isEmpty(panel.targets)) {
|
if (panel.targets && !_.isEmpty(panel.targets)) {
|
||||||
_.each(panel.targets, (target) => {
|
_.each(panel.targets, (target) => {
|
||||||
_.defaultsDeep(target, DEFAULT_TARGET);
|
_.defaultsDeep(target, DEFAULT_TARGET);
|
||||||
|
|||||||
@@ -19,6 +19,12 @@
|
|||||||
checked="ctrl.panel.hostGroups"
|
checked="ctrl.panel.hostGroups"
|
||||||
on-change="ctrl.render()">
|
on-change="ctrl.render()">
|
||||||
</gf-form-switch>
|
</gf-form-switch>
|
||||||
|
<gf-form-switch class="gf-form"
|
||||||
|
label-class="width-9"
|
||||||
|
label="Host proxy"
|
||||||
|
checked="ctrl.panel.hostProxy"
|
||||||
|
on-change="ctrl.refresh()">
|
||||||
|
</gf-form-switch>
|
||||||
<gf-form-switch class="gf-form"
|
<gf-form-switch class="gf-form"
|
||||||
label-class="width-9"
|
label-class="width-9"
|
||||||
label="Tags"
|
label="Tags"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<div class="section gf-form-group">
|
<div class="section gf-form-group">
|
||||||
<h5 class="section-heading">{{ ds }}</h5>
|
<h5 class="section-heading">{{ ds }}</h5>
|
||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
<div class="gf-form max-width-20">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label query-keyword width-7">Group</label>
|
<label class="gf-form-label query-keyword width-7">Group</label>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
ng-model="ctrl.panel.targets[ds].group.filter"
|
ng-model="ctrl.panel.targets[ds].group.filter"
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
ng-blur="editor.parseTarget()"
|
ng-blur="editor.parseTarget()"
|
||||||
data-min-length=0
|
data-min-length=0
|
||||||
data-items=100
|
data-items=100
|
||||||
class="gf-form-input"
|
class="gf-form-input width-14"
|
||||||
ng-class="{
|
ng-class="{
|
||||||
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].group.filter),
|
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].group.filter),
|
||||||
'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].group.filter)
|
'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].group.filter)
|
||||||
@@ -41,16 +41,30 @@
|
|||||||
ng-blur="editor.parseTarget()"
|
ng-blur="editor.parseTarget()"
|
||||||
data-min-length=0
|
data-min-length=0
|
||||||
data-items=100
|
data-items=100
|
||||||
class="gf-form-input"
|
class="gf-form-input width-14"
|
||||||
ng-class="{
|
ng-class="{
|
||||||
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].host.filter),
|
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].host.filter),
|
||||||
'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].host.filter)
|
'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].host.filter)
|
||||||
}">
|
}">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Proxy</label>
|
||||||
|
<input type="text"
|
||||||
|
ng-model="ctrl.panel.targets[ds].proxy.filter"
|
||||||
|
bs-typeahead="editor.getProxyNames[ds]"
|
||||||
|
ng-blur="editor.parseTarget()"
|
||||||
|
data-min-length=0
|
||||||
|
data-items=100
|
||||||
|
class="gf-form-input width-14"
|
||||||
|
ng-class="{
|
||||||
|
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].proxy.filter),
|
||||||
|
'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].proxy.filter)
|
||||||
|
}">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
<div class="gf-form max-width-20">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label query-keyword width-7">Application</label>
|
<label class="gf-form-label query-keyword width-7">Application</label>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
ng-model="ctrl.panel.targets[ds].application.filter"
|
ng-model="ctrl.panel.targets[ds].application.filter"
|
||||||
@@ -58,7 +72,7 @@
|
|||||||
ng-blur="editor.parseTarget()"
|
ng-blur="editor.parseTarget()"
|
||||||
data-min-length=0
|
data-min-length=0
|
||||||
data-items=100
|
data-items=100
|
||||||
class="gf-form-input"
|
class="gf-form-input width-14"
|
||||||
ng-class="{
|
ng-class="{
|
||||||
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].application.filter),
|
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].application.filter),
|
||||||
'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].application.filter)
|
'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].application.filter)
|
||||||
@@ -70,7 +84,7 @@
|
|||||||
ng-model="ctrl.panel.targets[ds].trigger.filter"
|
ng-model="ctrl.panel.targets[ds].trigger.filter"
|
||||||
ng-blur="editor.parseTarget()"
|
ng-blur="editor.parseTarget()"
|
||||||
placeholder="trigger name"
|
placeholder="trigger name"
|
||||||
class="gf-form-input"
|
class="gf-form-input width-14"
|
||||||
ng-style="ctrl.panel.targets[ds].trigger.style"
|
ng-style="ctrl.panel.targets[ds].trigger.style"
|
||||||
ng-class="{
|
ng-class="{
|
||||||
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].trigger.filter),
|
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].trigger.filter),
|
||||||
@@ -80,7 +94,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label query-keyword width-7">Tags</label>
|
<label class="gf-form-label query-keyword width-7">Tags</label>
|
||||||
<input type="text" class="gf-form-input"
|
<input type="text" class="gf-form-input width-14"
|
||||||
ng-model="ctrl.panel.targets[ds].tags.filter"
|
ng-model="ctrl.panel.targets[ds].tags.filter"
|
||||||
ng-blur="editor.parseTarget()"
|
ng-blur="editor.parseTarget()"
|
||||||
placeholder="tag1:value1, tag2:value2">
|
placeholder="tag1:value1, tag2:value2">
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export const DEFAULT_TARGET = {
|
|||||||
application: {filter: ""},
|
application: {filter: ""},
|
||||||
trigger: {filter: ""},
|
trigger: {filter: ""},
|
||||||
tags: {filter: ""},
|
tags: {filter: ""},
|
||||||
|
proxy: {filter: ""},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_SEVERITY = [
|
export const DEFAULT_SEVERITY = [
|
||||||
@@ -36,6 +37,7 @@ export const PANEL_DEFAULTS = {
|
|||||||
hostField: true,
|
hostField: true,
|
||||||
hostTechNameField: false,
|
hostTechNameField: false,
|
||||||
hostGroups: false,
|
hostGroups: false,
|
||||||
|
hostProxy: false,
|
||||||
showTags: true,
|
showTags: true,
|
||||||
statusField: true,
|
statusField: true,
|
||||||
severityField: true,
|
severityField: true,
|
||||||
@@ -203,31 +205,37 @@ export class TriggerPanelCtrl extends PanelCtrl {
|
|||||||
|
|
||||||
getTriggers() {
|
getTriggers() {
|
||||||
let promises = _.map(this.panel.datasources, (ds) => {
|
let promises = _.map(this.panel.datasources, (ds) => {
|
||||||
|
let proxies;
|
||||||
return this.datasourceSrv.get(ds)
|
return this.datasourceSrv.get(ds)
|
||||||
.then(datasource => {
|
.then(datasource => {
|
||||||
var zabbix = datasource.zabbix;
|
const zabbix = datasource.zabbix;
|
||||||
var showEvents = this.panel.showEvents.value;
|
const showEvents = this.panel.showEvents.value;
|
||||||
var triggerFilter = this.panel.targets[ds];
|
const triggerFilter = this.panel.targets[ds];
|
||||||
|
const showProxy = this.panel.hostProxy;
|
||||||
|
const getProxiesPromise = showProxy ? zabbix.getProxies() : () => [];
|
||||||
|
|
||||||
// Replace template variables
|
// Replace template variables
|
||||||
var groupFilter = datasource.replaceTemplateVars(triggerFilter.group.filter);
|
const groupFilter = datasource.replaceTemplateVars(triggerFilter.group.filter);
|
||||||
var hostFilter = datasource.replaceTemplateVars(triggerFilter.host.filter);
|
const hostFilter = datasource.replaceTemplateVars(triggerFilter.host.filter);
|
||||||
var appFilter = datasource.replaceTemplateVars(triggerFilter.application.filter);
|
const appFilter = datasource.replaceTemplateVars(triggerFilter.application.filter);
|
||||||
|
const proxyFilter = datasource.replaceTemplateVars(triggerFilter.proxy.filter);
|
||||||
|
|
||||||
let triggersOptions = {
|
let triggersOptions = {
|
||||||
showTriggers: showEvents
|
showTriggers: showEvents
|
||||||
};
|
};
|
||||||
|
|
||||||
return zabbix.getTriggers(groupFilter, hostFilter, appFilter, triggersOptions);
|
return Promise.all([
|
||||||
}).then((triggers) => {
|
zabbix.getTriggers(groupFilter, hostFilter, appFilter, triggersOptions, proxyFilter),
|
||||||
|
getProxiesPromise
|
||||||
|
]);
|
||||||
|
}).then(([triggers, sourceProxies]) => {
|
||||||
|
proxies = _.keyBy(sourceProxies, 'proxyid');
|
||||||
return this.getAcknowledges(triggers, ds);
|
return this.getAcknowledges(triggers, ds);
|
||||||
}).then((triggers) => {
|
})
|
||||||
return this.setMaintenanceStatus(triggers);
|
.then(triggers => this.setMaintenanceStatus(triggers))
|
||||||
}).then((triggers) => {
|
.then(triggers => this.filterTriggersPre(triggers, ds))
|
||||||
return this.filterTriggersPre(triggers, ds);
|
.then(triggers => this.addTriggerDataSource(triggers, ds))
|
||||||
}).then((triggers) => {
|
.then(triggers => this.addTriggerHostProxy(triggers, proxies));
|
||||||
return this.addTriggerDataSource(triggers, ds);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
@@ -344,6 +352,19 @@ export class TriggerPanelCtrl extends PanelCtrl {
|
|||||||
return triggers;
|
return triggers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addTriggerHostProxy(triggers, proxies) {
|
||||||
|
triggers.forEach(trigger => {
|
||||||
|
if (trigger.hosts && trigger.hosts.length) {
|
||||||
|
let host = trigger.hosts[0];
|
||||||
|
if (host.proxy_hostid !== '0') {
|
||||||
|
const hostProxy = proxies[host.proxy_hostid];
|
||||||
|
host.proxy = hostProxy ? hostProxy.host : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return triggers;
|
||||||
|
}
|
||||||
|
|
||||||
sortTriggers(triggerList) {
|
sortTriggers(triggerList) {
|
||||||
if (this.panel.sortTriggersBy.value === 'priority') {
|
if (this.panel.sortTriggersBy.value === 'priority') {
|
||||||
triggerList = _.orderBy(triggerList, ['priority', 'lastchangeUnix', 'triggerid'], ['desc', 'desc', 'desc']);
|
triggerList = _.orderBy(triggerList, ['priority', 'lastchangeUnix', 'triggerid'], ['desc', 'desc', 'desc']);
|
||||||
@@ -355,12 +376,15 @@ export class TriggerPanelCtrl extends PanelCtrl {
|
|||||||
|
|
||||||
formatTrigger(zabbixTrigger) {
|
formatTrigger(zabbixTrigger) {
|
||||||
let trigger = _.cloneDeep(zabbixTrigger);
|
let trigger = _.cloneDeep(zabbixTrigger);
|
||||||
let triggerObj = trigger;
|
|
||||||
|
|
||||||
// Set host that the trigger belongs
|
// Set host and proxy that the trigger belongs
|
||||||
if (trigger.hosts && trigger.hosts.length) {
|
if (trigger.hosts && trigger.hosts.length) {
|
||||||
triggerObj.host = trigger.hosts[0].name;
|
const host = trigger.hosts[0];
|
||||||
triggerObj.hostTechName = trigger.hosts[0].host;
|
trigger.host = host.name;
|
||||||
|
trigger.hostTechName = host.host;
|
||||||
|
if (host.proxy) {
|
||||||
|
trigger.proxy = host.proxy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set tags if present
|
// Set tags if present
|
||||||
@@ -375,9 +399,9 @@ export class TriggerPanelCtrl extends PanelCtrl {
|
|||||||
|
|
||||||
// Format last change and age
|
// Format last change and age
|
||||||
trigger.lastchangeUnix = Number(trigger.lastchange);
|
trigger.lastchangeUnix = Number(trigger.lastchange);
|
||||||
triggerObj = this.setTriggerLastChange(triggerObj);
|
trigger = this.setTriggerLastChange(trigger);
|
||||||
triggerObj = this.setTriggerSeverity(triggerObj);
|
trigger = this.setTriggerSeverity(trigger);
|
||||||
return triggerObj;
|
return trigger;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTriggerFormat(trigger) {
|
updateTriggerFormat(trigger) {
|
||||||
@@ -491,6 +515,9 @@ export class TriggerPanelCtrl extends PanelCtrl {
|
|||||||
} else if (this.panel.hostField || this.panel.hostTechNameField) {
|
} else if (this.panel.hostField || this.panel.hostTechNameField) {
|
||||||
host = this.panel.hostField ? trigger.host : trigger.hostTechName;
|
host = this.panel.hostField ? trigger.host : trigger.hostTechName;
|
||||||
}
|
}
|
||||||
|
if (this.panel.hostProxy && trigger.proxy) {
|
||||||
|
host = `${trigger.proxy}: ${host}`;
|
||||||
|
}
|
||||||
|
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class TriggersTabCtrl {
|
|||||||
getGroupNames: {},
|
getGroupNames: {},
|
||||||
getHostNames: {},
|
getHostNames: {},
|
||||||
getApplicationNames: {},
|
getApplicationNames: {},
|
||||||
|
getProxyNames: {},
|
||||||
oldTarget: _.cloneDeep(this.panel.targets)
|
oldTarget: _.cloneDeep(this.panel.targets)
|
||||||
};
|
};
|
||||||
_.defaultsDeep(this, scopeDefaults);
|
_.defaultsDeep(this, scopeDefaults);
|
||||||
@@ -40,6 +41,7 @@ class TriggersTabCtrl {
|
|||||||
this.getGroupNames[ds] = _.bind(this.suggestGroups, this, datasource);
|
this.getGroupNames[ds] = _.bind(this.suggestGroups, this, datasource);
|
||||||
this.getHostNames[ds] = _.bind(this.suggestHosts, this, datasource);
|
this.getHostNames[ds] = _.bind(this.suggestHosts, this, datasource);
|
||||||
this.getApplicationNames[ds] = _.bind(this.suggestApps, this, datasource);
|
this.getApplicationNames[ds] = _.bind(this.suggestApps, this, datasource);
|
||||||
|
this.getProxyNames[ds] = _.bind(this.suggestProxies, this, datasource);
|
||||||
}
|
}
|
||||||
|
|
||||||
suggestGroups(datasource, query, callback) {
|
suggestGroups(datasource, query, callback) {
|
||||||
@@ -69,6 +71,12 @@ class TriggersTabCtrl {
|
|||||||
.then(callback);
|
.then(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suggestProxies(datasource, query, callback) {
|
||||||
|
return datasource.zabbix.getProxies()
|
||||||
|
.then(proxies => _.map(proxies, 'host'))
|
||||||
|
.then(callback);
|
||||||
|
}
|
||||||
|
|
||||||
datasourcesChanged() {
|
datasourcesChanged() {
|
||||||
_.each(this.panel.datasources, (ds) => {
|
_.each(this.panel.datasources, (ds) => {
|
||||||
if (!this.panel.targets[ds]) {
|
if (!this.panel.targets[ds]) {
|
||||||
@@ -84,8 +92,8 @@ class TriggersTabCtrl {
|
|||||||
var newTarget = _.cloneDeep(this.panel.targets);
|
var newTarget = _.cloneDeep(this.panel.targets);
|
||||||
if (!_.isEqual(this.oldTarget, newTarget)) {
|
if (!_.isEqual(this.oldTarget, newTarget)) {
|
||||||
this.oldTarget = newTarget;
|
this.oldTarget = newTarget;
|
||||||
}
|
|
||||||
this.panelCtrl.refresh();
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
src/test-setup/mocks.js
Normal file
26
src/test-setup/mocks.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export let templateSrvMock = {
|
||||||
|
replace: jest.fn().mockImplementation(query => query)
|
||||||
|
};
|
||||||
|
|
||||||
|
export let backendSrvMock = {
|
||||||
|
datasourceRequest: jest.fn()
|
||||||
|
};
|
||||||
|
|
||||||
|
export let datasourceSrvMock = {
|
||||||
|
loadDatasource: jest.fn(),
|
||||||
|
getAll: jest.fn()
|
||||||
|
};
|
||||||
|
|
||||||
|
export let zabbixAlertingSrvMock = {
|
||||||
|
setPanelAlertState: jest.fn(),
|
||||||
|
removeZabbixThreshold: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultExports = {
|
||||||
|
templateSrvMock,
|
||||||
|
backendSrvMock,
|
||||||
|
datasourceSrvMock,
|
||||||
|
zabbixAlertingSrvMock
|
||||||
|
};
|
||||||
|
|
||||||
|
export default defaultExports;
|
||||||
Reference in New Issue
Block a user