From 056f82731e234e269adb5066143194e6816182a2 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Fri, 15 May 2020 18:17:54 +0300 Subject: [PATCH] Problems: use problems.get method for fetching triggers, closes #495 --- src/datasource-zabbix/datasource.ts | 48 ++--- src/datasource-zabbix/problemsHandler.ts | 65 ++++--- src/datasource-zabbix/types.ts | 169 ++++++++++++++++++ .../zabbix_api/zabbixAPIConnector.ts | 58 +++++- src/datasource-zabbix/zabbix/zabbix.ts | 19 +- .../components/AlertList/AlertCard.tsx | 27 +-- .../components/AlertList/AlertList.tsx | 11 +- .../components/Problems/ProblemDetails.tsx | 17 +- .../components/Problems/Problems.tsx | 42 ++--- src/panel-triggers/triggers_panel_ctrl.ts | 35 ++-- 10 files changed, 361 insertions(+), 130 deletions(-) diff --git a/src/datasource-zabbix/datasource.ts b/src/datasource-zabbix/datasource.ts index d405b74..5c0d7a7 100644 --- a/src/datasource-zabbix/datasource.ts +++ b/src/datasource-zabbix/datasource.ts @@ -412,39 +412,29 @@ export class ZabbixDatasource { tags: { filter: tagsFilter }, }; - const triggersOptions: any = { - showTriggers: showProblems + const problemsOptions: any = { + recent: showProblems === ShowProblemTypes.Recent, + limit: target.options?.limit, }; if (showProblems !== ShowProblemTypes.Problems) { - triggersOptions.timeFrom = timeFrom; - triggersOptions.timeTo = timeTo; + problemsOptions.timeFrom = timeFrom; + problemsOptions.timeTo = timeTo; } const problemsPromises = Promise.all([ - this.zabbix.getTriggers(groupFilter, hostFilter, appFilter, triggersOptions, proxyFilter), + this.zabbix.getProblems(groupFilter, hostFilter, appFilter, proxyFilter, problemsOptions), getProxiesPromise ]) - .then(([triggers, sourceProxies]) => { + .then(([problems, sourceProxies]) => { proxies = _.keyBy(sourceProxies, 'proxyid'); - const eventids = _.compact(triggers.map(trigger => { - return trigger.lastEvent.eventid; - })); - return Promise.all([ - this.zabbix.getExtendedEventData(eventids), - Promise.resolve(triggers) - ]); + return problems; }) - .then(([events, triggers]) => { - problemsHandler.addEventTags(events, triggers); - problemsHandler.addAcknowledges(events, triggers); - return triggers; - }) - .then(triggers => problemsHandler.setMaintenanceStatus(triggers)) - .then(triggers => problemsHandler.setAckButtonStatus(triggers, showAckButton)) - .then(triggers => problemsHandler.filterTriggersPre(triggers, replacedTarget)) - .then(triggers => problemsHandler.addTriggerDataSource(triggers, target)) - .then(triggers => problemsHandler.addTriggerHostProxy(triggers, proxies)); + .then(problems => problemsHandler.setMaintenanceStatus(problems)) + .then(problems => problemsHandler.setAckButtonStatus(problems, showAckButton)) + .then(problems => problemsHandler.filterTriggersPre(problems, replacedTarget)) + .then(problems => problemsHandler.addTriggerDataSource(problems, target)) + .then(problems => problemsHandler.addTriggerHostProxy(problems, proxies)); return problemsPromises.then(problems => { const problemsDataFrame = problemsHandler.toDataFrame(problems); @@ -567,13 +557,13 @@ export class ZabbixDatasource { hideHostsInMaintenance: false }; - const getTriggers = this.zabbix.getTriggers(this.replaceTemplateVars(annotation.group, {}), - this.replaceTemplateVars(annotation.host, {}), - this.replaceTemplateVars(annotation.application, {}), - triggersOptions); - - return getTriggers.then(triggers => { + const groupFilter = this.replaceTemplateVars(annotation.group, {}); + const hostFilter = this.replaceTemplateVars(annotation.host, {}); + const appFilter = this.replaceTemplateVars(annotation.application, {}); + const proxyFilter = undefined; + return this.zabbix.getProblems(groupFilter, hostFilter, appFilter, proxyFilter, triggersOptions) + .then(triggers => { // Filter triggers by description const triggerName = this.replaceTemplateVars(annotation.trigger, {}); if (utils.isRegex(triggerName)) { diff --git a/src/datasource-zabbix/problemsHandler.ts b/src/datasource-zabbix/problemsHandler.ts index 6ed4c72..906ee9a 100644 --- a/src/datasource-zabbix/problemsHandler.ts +++ b/src/datasource-zabbix/problemsHandler.ts @@ -4,36 +4,45 @@ import TableModel from 'grafana/app/core/table_model'; import * as utils from '../datasource-zabbix/utils'; import * as c from './constants'; import { DataFrame, Field, FieldType, ArrayVector } from '@grafana/data'; +import { ZBXProblem, ZBXTrigger, ProblemDTO } from './types'; -export function addEventTags(events, triggers) { - _.each(triggers, trigger => { - const event = _.find(events, event => { - return event.eventid === trigger.lastEvent.eventid; - }); - if (event && event.tags && event.tags.length) { - trigger.tags = event.tags; - } - }); - return triggers; -} +export function joinTriggersWithProblems(problems: ZBXProblem[], triggers: ZBXTrigger[]): ProblemDTO[] { + const problemDTOList: ProblemDTO[] = []; + for (let i = 0; i < problems.length; i++) { + const p = problems[i]; + const triggerId = Number(p.objectid); + const t = triggers[triggerId]; + const problemDTO: ProblemDTO = { + timestamp: Number(p.clock), + triggerid: p.objectid, + eventid: p.eventid, + name: p.name, + severity: p.severity, + acknowledged: p.acknowledged, + acknowledges: p.acknowledges, + tags: p.tags, + suppressed: p.suppressed, + suppression_data: p.suppression_data, + description: t.description, + comments: t.comments, + value: t.value, + groups: t.groups, + hosts: t.hosts, + items: t.items, + alerts: t.alerts, + url: t.url, + expression: t.expression, + correlation_mode: t.correlation_mode, + correlation_tag: t.correlation_tag, + manual_close: t.manual_close, + state: t.state, + error: t.error, + }; -export function addAcknowledges(events, triggers) { - // Map events to triggers - _.each(triggers, trigger => { - const event = _.find(events, event => { - return event.eventid === trigger.lastEvent.eventid; - }); + problemDTOList.push(problemDTO); + } - if (event) { - trigger.acknowledges = event.acknowledges; - } - - if (!trigger.lastEvent.eventid) { - trigger.lastEvent = null; - } - }); - - return triggers; + return problemDTOList; } export function setMaintenanceStatus(triggers) { @@ -129,8 +138,6 @@ export function toDataFrame(problems: any[]): DataFrame { } const problemsHandler = { - addEventTags, - addAcknowledges, addTriggerDataSource, addTriggerHostProxy, setMaintenanceStatus, diff --git a/src/datasource-zabbix/types.ts b/src/datasource-zabbix/types.ts index ba2d45f..a05dc6d 100644 --- a/src/datasource-zabbix/types.ts +++ b/src/datasource-zabbix/types.ts @@ -34,3 +34,172 @@ export enum ShowProblemTypes { Recent = 'recent', History = 'history', } + +export interface ProblemDTO { + triggerid?: string; + eventid?: string; + timestamp: number; + + /** Name of the trigger. */ + name?: string; + + /** Same as a name. */ + description?: string; + + /** Whether the trigger is in OK or problem state. */ + value?: string; + + datasource?: string; + comments?: string; + host?: string; + hostTechName?: string; + proxy?: string; + severity?: string; + + acknowledged?: '1' | '0'; + acknowledges?: ZBXAcknowledge[]; + + groups?: ZBXGroup[]; + hosts?: ZBXHost[]; + items?: ZBXItem[]; + alerts?: ZBXAlert[]; + tags?: ZBXTag[]; + url?: string; + + expression?: string; + correlation_mode?: string; + correlation_tag?: string; + suppressed?: string; + suppression_data?: any[]; + state?: string; + maintenance?: boolean; + manual_close?: string; + error?: string; + + showAckButton?: boolean; +} + +export interface ZBXProblem { + acknowledged?: '1' | '0'; + acknowledges?: ZBXAcknowledge[]; + clock: string; + ns: string; + correlationid?: string; + datasource?: string; + name?: string; + eventid?: string; + maintenance?: boolean; + object?: string; + objectid?: string; + opdata?: any; + r_eventid?: string; + r_clock?: string; + r_ns?: string; + severity?: string; + showAckButton?: boolean; + source?: string; + suppressed?: string; + suppression_data?: any[]; + tags?: ZBXTag[]; + userid?: string; +} + +export interface ZBXTrigger { + acknowledges?: ZBXAcknowledge[]; + showAckButton?: boolean; + alerts?: ZBXAlert[]; + age?: string; + color?: string; + comments?: string; + correlation_mode?: string; + correlation_tag?: string; + datasource?: string; + description?: string; + error?: string; + expression?: string; + flags?: string; + groups?: ZBXGroup[]; + host?: string; + hostTechName?: string; + hosts?: ZBXHost[]; + items?: ZBXItem[]; + lastEvent?: ZBXEvent; + lastchange?: string; + lastchangeUnix?: number; + maintenance?: boolean; + manual_close?: string; + priority?: string; + proxy?: string; + recovery_expression?: string; + recovery_mode?: string; + severity?: string; + state?: string; + status?: string; + tags?: ZBXTag[]; + templateid?: string; + triggerid?: string; + /** Whether the trigger can generate multiple problem events. */ + type?: string; + url?: string; + value?: string; +} + +export interface ZBXGroup { + groupid: string; + name: string; +} + +export interface ZBXHost { + hostid: string; + name: string; + host: string; + maintenance_status?: string; + proxy_hostid?: string; +} + +export interface ZBXItem { + itemid: string; + name: string; + key_: string; + lastvalue?: string; +} + +export interface ZBXEvent { + eventid: string; + clock: string; + ns?: string; + value?: string; + source?: string; + object?: string; + objectid?: string; + acknowledged?: string; + severity?: string; + hosts?: ZBXHost[]; + acknowledges?: ZBXAcknowledge[]; +} + +export interface ZBXTag { + tag: string; + value?: string; +} + +export interface ZBXAcknowledge { + acknowledgeid: string; + eventid: string; + userid: string; + action: string; + clock: string; + time: string; + message?: string; + user: string; + alias: string; + name: string; + surname: string; +} + +export interface ZBXAlert { + eventid: string; + clock: string; + message: string; + error: string; +} diff --git a/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts b/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts index 0e8af58..89fdb7b 100644 --- a/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts +++ b/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts @@ -4,7 +4,7 @@ import kbn from 'grafana/app/core/utils/kbn'; import * as utils from '../../../utils'; import { ZabbixAPICore } from './zabbixAPICore'; import { ZBX_ACK_ACTION_NONE, ZBX_ACK_ACTION_ACK, ZBX_ACK_ACTION_ADD_MESSAGE, MIN_SLA_INTERVAL } from '../../../constants'; -import { ShowProblemTypes } from '../../../types'; +import { ShowProblemTypes, ZBXProblem } from '../../../types'; const DEFAULT_ZABBIX_VERSION = '3.0.0'; @@ -367,6 +367,62 @@ export class ZabbixAPIConnector { return this.request('service.getsla', params); } + getProblems(groupids, hostids, applicationids, options): Promise { + const { timeFrom, timeTo, recent, severities, limit } = options; + + const params: any = { + output: 'extend', + selectAcknowledges: 'extend', + selectSuppressionData: 'extend', + selectTags: 'extend', + source: '0', + object: '0', + sortfield: ['eventid'], + sortorder: 'DESC', + evaltype: '0', + // preservekeys: '1', + groupids, + hostids, + applicationids, + recent, + }; + + if (severities) { + params.severities = severities; + } + + if (limit) { + params.limit = limit; + } + + if (timeFrom || timeTo) { + params.time_from = timeFrom; + params.time_till = timeTo; + } + + return this.request('problem.get', params); + } + + getTriggersByIds(triggerids: string[]) { + const params: any = { + output: 'extend', + triggerids: triggerids, + expandDescription: true, + expandData: true, + expandComment: true, + monitored: true, + skipDependent: true, + selectGroups: ['name'], + selectHosts: ['name', 'host', 'maintenance_status', 'proxy_hostid'], + selectItems: ['name', 'key_', 'lastvalue'], + // selectLastEvent: 'extend', + // selectTags: 'extend', + preservekeys: '1', + }; + + return this.request('trigger.get', params); + } + getTriggers(groupids, hostids, applicationids, options) { const {showTriggers, maintenance, timeFrom, timeTo} = options; diff --git a/src/datasource-zabbix/zabbix/zabbix.ts b/src/datasource-zabbix/zabbix/zabbix.ts index 239eaef..fca8d7c 100644 --- a/src/datasource-zabbix/zabbix/zabbix.ts +++ b/src/datasource-zabbix/zabbix/zabbix.ts @@ -8,6 +8,7 @@ import { ZabbixAPIConnector } from './connectors/zabbix_api/zabbixAPIConnector'; import { SQLConnector } from './connectors/sql/sqlConnector'; import { InfluxDBConnector } from './connectors/influxdb/influxdbConnector'; import { ZabbixConnector } from './types'; +import { joinTriggersWithProblems } from '../problemsHandler'; const REQUESTS_TO_PROXYFY = [ 'getHistory', 'getTrend', 'getGroups', 'getHosts', 'getApps', 'getItems', 'getMacros', 'getItemsByIDs', @@ -286,10 +287,7 @@ export class Zabbix implements ZabbixConnector { .then(itServices => findByFilter(itServices, itServiceFilter)); } - /** - * Build query - convert target filters to array of Zabbix items - */ - getTriggers(groupFilter, hostFilter, appFilter, options?, proxyFilter?) { + getProblems(groupFilter, hostFilter, appFilter, proxyFilter?, options?) { const promises = [ this.getGroups(groupFilter), this.getHosts(groupFilter, hostFilter), @@ -313,7 +311,13 @@ export class Zabbix implements ZabbixConnector { return query; }) - .then(query => this.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, options)) + // .then(query => this.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, options)) + .then(query => this.zabbixAPI.getProblems(query.groupids, query.hostids, query.applicationids, options)) + .then(problems => { + const triggerids = problems?.map(problem => problem.objectid); + return Promise.all([Promise.resolve(problems), this.zabbixAPI.getTriggersByIds(triggerids)]); + }) + .then(([problems, triggers]) => joinTriggersWithProblems(problems, triggers)) .then(triggers => this.filterTriggersByProxy(triggers, proxyFilter)) .then(triggers => this.expandUserMacro.bind(this)(triggers, true)); } @@ -324,14 +328,13 @@ export class Zabbix implements ZabbixConnector { 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 true; } } - return filtered; + return false; }); } return triggers; diff --git a/src/panel-triggers/components/AlertList/AlertCard.tsx b/src/panel-triggers/components/AlertList/AlertCard.tsx index dd71228..7d6dc5d 100644 --- a/src/panel-triggers/components/AlertList/AlertCard.tsx +++ b/src/panel-triggers/components/AlertList/AlertCard.tsx @@ -3,18 +3,19 @@ import classNames from 'classnames'; import _ from 'lodash'; import moment from 'moment'; import { isNewProblem, formatLastChange } from '../../utils'; -import { ProblemsPanelOptions, ZBXTrigger, TriggerSeverity, ZBXTag } from '../../types'; +import { ProblemsPanelOptions, TriggerSeverity } from '../../types'; import { AckProblemData, Modal } from '.././Modal'; import EventTag from '../EventTag'; import Tooltip from '.././Tooltip/Tooltip'; import AlertAcknowledges from './AlertAcknowledges'; import AlertIcon from './AlertIcon'; +import { ProblemDTO, ZBXTag } from '../../../datasource-zabbix/types'; interface AlertCardProps { - problem: ZBXTrigger; + problem: ProblemDTO; panelOptions: ProblemsPanelOptions; onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void; - onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => Promise | any; + onProblemAck?: (problem: ProblemDTO, data: AckProblemData) => Promise | any; } interface AlertCardState { @@ -61,13 +62,13 @@ export default class AlertCard extends PureComponent s.priority === Number(problem.priority)); - if (problem.lastEvent?.severity) { - severityDesc = _.find(panelOptions.triggerSeverity, s => s.priority === Number(problem.lastEvent.severity)); + severityDesc = _.find(panelOptions.triggerSeverity, s => s.priority === Number(problem.severity)); + if (problem.severity) { + severityDesc = _.find(panelOptions.triggerSeverity, s => s.priority === Number(problem.severity)); } - const lastchange = formatLastChange(problem.lastchangeUnix, panelOptions.customLastChangeFormat && panelOptions.lastChangeFormat); - const age = moment.unix(problem.lastchangeUnix).fromNow(true); + const lastchange = formatLastChange(problem.timestamp, panelOptions.customLastChangeFormat && panelOptions.lastChangeFormat); + const age = moment.unix(problem.timestamp).fromNow(true); let newProblem = false; if (panelOptions.highlightNewerThan) { @@ -78,7 +79,7 @@ export default class AlertCard extends PureComponent )} - {problem.lastEvent && ( + {problem.eventid && ( )} @@ -174,7 +175,7 @@ export default class AlertCard extends PureComponent void; } diff --git a/src/panel-triggers/components/AlertList/AlertList.tsx b/src/panel-triggers/components/AlertList/AlertList.tsx index a01c155..8862334 100644 --- a/src/panel-triggers/components/AlertList/AlertList.tsx +++ b/src/panel-triggers/components/AlertList/AlertList.tsx @@ -1,23 +1,24 @@ import React, { PureComponent, CSSProperties } from 'react'; import classNames from 'classnames'; -import { ProblemsPanelOptions, ZBXTrigger, GFTimeRange, ZBXTag } from '../../types'; +import { ProblemsPanelOptions, GFTimeRange } from '../../types'; import { AckProblemData } from '.././Modal'; import AlertCard from './AlertCard'; +import { ProblemDTO, ZBXTag } from '../../../datasource-zabbix/types'; export interface AlertListProps { - problems: ZBXTrigger[]; + problems: ProblemDTO[]; panelOptions: ProblemsPanelOptions; loading?: boolean; timeRange?: GFTimeRange; pageSize?: number; fontSize?: number; - onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => void; + onProblemAck?: (problem: ProblemDTO, data: AckProblemData) => void; onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void; } interface AlertListState { page: number; - currentProblems: ZBXTrigger[]; + currentProblems: ProblemDTO[]; } export default class AlertList extends PureComponent { @@ -51,7 +52,7 @@ export default class AlertList extends PureComponent { + handleProblemAck = (problem: ProblemDTO, data: AckProblemData) => { return this.props.onProblemAck(problem, data); } diff --git a/src/panel-triggers/components/Problems/ProblemDetails.tsx b/src/panel-triggers/components/Problems/ProblemDetails.tsx index 67154b1..13009cd 100644 --- a/src/panel-triggers/components/Problems/ProblemDetails.tsx +++ b/src/panel-triggers/components/Problems/ProblemDetails.tsx @@ -1,7 +1,7 @@ import React, { PureComponent } from 'react'; import moment from 'moment'; import * as utils from '../../../datasource-zabbix/utils'; -import { ZBXTrigger, ZBXItem, ZBXAcknowledge, ZBXHost, ZBXGroup, ZBXEvent, GFTimeRange, RTRow, ZBXTag, ZBXAlert } from '../../types'; +import { ZBXItem, ZBXAcknowledge, GFTimeRange, RTRow } from '../../types'; import { Modal, AckProblemData } from '../Modal'; import EventTag from '../EventTag'; import Tooltip from '../Tooltip/Tooltip'; @@ -9,14 +9,15 @@ import ProblemStatusBar from './ProblemStatusBar'; import AcknowledgesList from './AcknowledgesList'; import ProblemTimeline from './ProblemTimeline'; import FAIcon from '../FAIcon'; +import { ProblemDTO, ZBXHost, ZBXGroup, ZBXEvent, ZBXTag, ZBXAlert } from '../../../datasource-zabbix/types'; -interface ProblemDetailsProps extends RTRow { +interface ProblemDetailsProps extends RTRow { rootWidth: number; timeRange: GFTimeRange; showTimeline?: boolean; - getProblemEvents: (problem: ZBXTrigger) => Promise; - getProblemAlerts: (problem: ZBXTrigger) => Promise; - onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => Promise | any; + getProblemEvents: (problem: ProblemDTO) => Promise; + getProblemAlerts: (problem: ProblemDTO) => Promise; + onProblemAck?: (problem: ProblemDTO, data: AckProblemData) => Promise | any; onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void; } @@ -71,7 +72,7 @@ export default class ProblemDetails extends PureComponent { - const problem = this.props.original as ZBXTrigger; + const problem = this.props.original as ProblemDTO; return this.props.onProblemAck(problem, data).then(result => { this.closeAckDialog(); }).catch(err => { @@ -89,13 +90,13 @@ export default class ProblemDetails extends PureComponent 1200; const compactStatusBar = rootWidth < 800 || problem.acknowledges && wideLayout && rootWidth < 1400; - const age = moment.unix(problem.lastchangeUnix).fromNow(true); + const age = moment.unix(problem.timestamp).fromNow(true); const showAcknowledges = problem.acknowledges && problem.acknowledges.length !== 0; return ( diff --git a/src/panel-triggers/components/Problems/Problems.tsx b/src/panel-triggers/components/Problems/Problems.tsx index c5bc3c5..8338286 100644 --- a/src/panel-triggers/components/Problems/Problems.tsx +++ b/src/panel-triggers/components/Problems/Problems.tsx @@ -5,22 +5,23 @@ import _ from 'lodash'; import moment from 'moment'; import * as utils from '../../../datasource-zabbix/utils'; import { isNewProblem } from '../../utils'; -import { ProblemsPanelOptions, ZBXTrigger, ZBXEvent, GFTimeRange, RTCell, ZBXTag, TriggerSeverity, RTResized, ZBXAlert } from '../../types'; import EventTag from '../EventTag'; import ProblemDetails from './ProblemDetails'; import { AckProblemData } from '../Modal'; import GFHeartIcon from '../GFHeartIcon'; +import { ProblemsPanelOptions, GFTimeRange, RTCell, TriggerSeverity, RTResized } from '../../types'; +import { ProblemDTO, ZBXEvent, ZBXTag, ZBXAlert } from '../../../datasource-zabbix/types'; export interface ProblemListProps { - problems: ZBXTrigger[]; + problems: ProblemDTO[]; panelOptions: ProblemsPanelOptions; loading?: boolean; timeRange?: GFTimeRange; pageSize?: number; fontSize?: number; - getProblemEvents: (problem: ZBXTrigger) => Promise; - getProblemAlerts: (problem: ZBXTrigger) => Promise; - onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => void; + getProblemEvents: (problem: ProblemDTO) => Promise; + getProblemAlerts: (problem: ProblemDTO) => Promise; + onProblemAck?: (problem: ProblemDTO, data: AckProblemData) => void; onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void; onPageSizeChange?: (pageSize: number, pageIndex: number) => void; onColumnResize?: (newResized: RTResized) => void; @@ -47,7 +48,7 @@ export default class ProblemList extends PureComponent { + handleProblemAck = (problem: ProblemDTO, data: AckProblemData) => { return this.props.onProblemAck(problem, data); } @@ -177,20 +178,21 @@ export default class ProblemList extends PureComponent, problemSeverityDesc: TriggerSeverity[], markAckEvents?: boolean, ackEventColor?: string) { +function SeverityCell(props: RTCell, problemSeverityDesc: TriggerSeverity[], markAckEvents?: boolean, ackEventColor?: string) { const problem = props.original; let color: string; let severityDesc: TriggerSeverity; - severityDesc = _.find(problemSeverityDesc, s => s.priority === Number(problem.priority)); - if (problem.lastEvent?.severity && problem.value === '1') { - severityDesc = _.find(problemSeverityDesc, s => s.priority === Number(problem.lastEvent.severity)); + const severity = Number(problem.severity); + severityDesc = _.find(problemSeverityDesc, s => s.priority === severity); + if (problem.severity && problem.value === '1') { + severityDesc = _.find(problemSeverityDesc, s => s.priority === severity); } color = severityDesc.color; // Mark acknowledged triggers with different color - if (markAckEvents && problem.lastEvent?.acknowledged === "1") { + if (markAckEvents && problem.acknowledged === "1") { color = ackEventColor; } @@ -204,7 +206,7 @@ function SeverityCell(props: RTCell, problemSeverityDesc: TriggerSev const DEFAULT_OK_COLOR = 'rgb(56, 189, 113)'; const DEFAULT_PROBLEM_COLOR = 'rgb(215, 0, 0)'; -function StatusCell(props: RTCell, okColor = DEFAULT_OK_COLOR, problemColor = DEFAULT_PROBLEM_COLOR, highlightNewerThan?: string) { +function StatusCell(props: RTCell, okColor = DEFAULT_OK_COLOR, problemColor = DEFAULT_PROBLEM_COLOR, highlightNewerThan?: string) { const status = props.value === '0' ? 'RESOLVED' : 'PROBLEM'; const color = props.value === '0' ? okColor : problemColor; let newProblem = false; @@ -216,7 +218,7 @@ function StatusCell(props: RTCell, okColor = DEFAULT_OK_COLOR, probl ); } -function StatusIconCell(props: RTCell, highlightNewerThan?: string) { +function StatusIconCell(props: RTCell, highlightNewerThan?: string) { const status = props.value === '0' ? 'ok' : 'problem'; let newProblem = false; if (highlightNewerThan) { @@ -230,7 +232,7 @@ function StatusIconCell(props: RTCell, highlightNewerThan?: string) return ; } -function GroupCell(props: RTCell) { +function GroupCell(props: RTCell) { let groups = ""; if (props.value && props.value.length) { groups = props.value.map(g => g.name).join(', '); @@ -240,7 +242,7 @@ function GroupCell(props: RTCell) { ); } -function ProblemCell(props: RTCell) { +function ProblemCell(props: RTCell) { const comments = props.original.comments; return (
@@ -250,23 +252,23 @@ function ProblemCell(props: RTCell) { ); } -function AgeCell(props: RTCell) { +function AgeCell(props: RTCell) { const problem = props.original; - const timestamp = moment.unix(problem.lastchangeUnix); + const timestamp = moment.unix(problem.timestamp); const age = timestamp.fromNow(true); return {age}; } -function LastChangeCell(props: RTCell, customFormat?: string) { +function LastChangeCell(props: RTCell, customFormat?: string) { const DEFAULT_TIME_FORMAT = "DD MMM YYYY HH:mm:ss"; const problem = props.original; - const timestamp = moment.unix(problem.lastchangeUnix); + const timestamp = moment.unix(problem.timestamp); const format = customFormat || DEFAULT_TIME_FORMAT; const lastchange = timestamp.format(format); return {lastchange}; } -interface TagCellProps extends RTCell { +interface TagCellProps extends RTCell { onTagClick: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void; } diff --git a/src/panel-triggers/triggers_panel_ctrl.ts b/src/panel-triggers/triggers_panel_ctrl.ts index 982c877..1942fe1 100644 --- a/src/panel-triggers/triggers_panel_ctrl.ts +++ b/src/panel-triggers/triggers_panel_ctrl.ts @@ -10,6 +10,7 @@ import { triggerPanelOptionsTab } from './options_tab'; import { migratePanelSchema, CURRENT_SCHEMA_VERSION } from './migrations'; import ProblemList from './components/Problems/Problems'; import AlertList from './components/AlertList/AlertList'; +import { ProblemDTO } from 'datasource-zabbix/types'; const PROBLEM_EVENTS_LIMIT = 100; @@ -174,7 +175,7 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl { let triggers = _.cloneDeep(problems); triggers = _.map(triggers, this.formatTrigger.bind(this)); - triggers = this.filterTriggersPost(triggers); + triggers = this.filterProblems(triggers); triggers = this.sortTriggers(triggers); this.renderData = triggers; @@ -184,30 +185,30 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl { }); } - filterTriggersPost(triggers) { - let triggerList = _.cloneDeep(triggers); + filterProblems(problems) { + let problemsList = _.cloneDeep(problems); // Filter acknowledged triggers if (this.panel.showTriggers === 'unacknowledged') { - triggerList = _.filter(triggerList, trigger => { + problemsList = _.filter(problemsList, trigger => { return !(trigger.acknowledges && trigger.acknowledges.length); }); } else if (this.panel.showTriggers === 'acknowledged') { - triggerList = _.filter(triggerList, trigger => { + problemsList = _.filter(problemsList, trigger => { return trigger.acknowledges && trigger.acknowledges.length; }); } // Filter triggers by severity - triggerList = _.filter(triggerList, trigger => { - if (trigger.lastEvent && trigger.lastEvent.severity) { - return this.panel.triggerSeverity[trigger.lastEvent.severity].show; + problemsList = _.filter(problemsList, problem => { + if (problem.severity) { + return this.panel.triggerSeverity[problem.severity].show; } else { - return this.panel.triggerSeverity[trigger.priority].show; + return this.panel.triggerSeverity[problem.priority].show; } }); - return triggerList; + return problemsList; } sortTriggers(triggerList) { @@ -303,11 +304,11 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl { }); } - getProblemAlerts(problem) { - if (!problem.lastEvent || problem.lastEvent.length === 0) { + getProblemAlerts(problem: ProblemDTO) { + if (!problem.eventid) { return Promise.resolve([]); } - const eventids = [problem.lastEvent.eventid]; + const eventids = [problem.eventid]; return getDataSourceSrv().get(problem.datasource) .then((datasource: any) => { return datasource.zabbix.getEventAlerts(eventids); @@ -327,11 +328,11 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl { this.render(); } - acknowledgeTrigger(trigger, message) { - const eventid = trigger.lastEvent ? trigger.lastEvent.eventid : null; + acknowledgeProblem(problem: ProblemDTO, message) { + const eventid = problem.eventid; const grafana_user = this.contextSrv.user.name; const ack_message = grafana_user + ' (Grafana): ' + message; - return getDataSourceSrv().get(trigger.datasource) + return getDataSourceSrv().get(problem.datasource) .then((datasource: any) => { const userIsEditor = this.contextSrv.isEditor || this.contextSrv.isGrafanaAdmin; if (datasource.disableReadOnlyUsersAck && !userIsEditor) { @@ -399,7 +400,7 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl { onColumnResize: ctrl.handleColumnResize.bind(ctrl), onProblemAck: (trigger, data) => { const message = data.message; - return ctrl.acknowledgeTrigger(trigger, message); + return ctrl.acknowledgeProblem(trigger, message); }, onTagClick: (tag, datasource, ctrlKey, shiftKey) => { if (ctrlKey || shiftKey) {