From 1cee6f0ae366df1699715c52dec9e560885b93e3 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 29 Dec 2022 15:32:39 +0300 Subject: [PATCH] SLA support in Zabbix 6.0 (#1547) --- src/datasource/components/QueryEditor.tsx | 11 +- .../QueryEditor/ITServicesQueryEditor.tsx | 102 -------------- .../QueryEditor/ServicesQueryEditor.tsx | 133 ++++++++++++++++++ src/datasource/datasource.ts | 14 +- src/datasource/responseHandler.ts | 100 ++++++++++++- src/datasource/types.ts | 1 + .../zabbix_api/zabbixAPIConnector.ts | 41 +++++- src/datasource/zabbix/zabbix.ts | 31 +++- 8 files changed, 316 insertions(+), 117 deletions(-) delete mode 100644 src/datasource/components/QueryEditor/ITServicesQueryEditor.tsx create mode 100644 src/datasource/components/QueryEditor/ServicesQueryEditor.tsx diff --git a/src/datasource/components/QueryEditor.tsx b/src/datasource/components/QueryEditor.tsx index 534635c..aee3227 100644 --- a/src/datasource/components/QueryEditor.tsx +++ b/src/datasource/components/QueryEditor.tsx @@ -11,7 +11,7 @@ import { QueryOptionsEditor } from './QueryEditor/QueryOptionsEditor'; import { TextMetricsQueryEditor } from './QueryEditor/TextMetricsQueryEditor'; import { ProblemsQueryEditor } from './QueryEditor/ProblemsQueryEditor'; import { ItemIdQueryEditor } from './QueryEditor/ItemIdQueryEditor'; -import { ITServicesQueryEditor } from './QueryEditor/ITServicesQueryEditor'; +import { ServicesQueryEditor } from './QueryEditor/ServicesQueryEditor'; import { TriggersQueryEditor } from './QueryEditor/TriggersQueryEditor'; const zabbixQueryTypeOptions: Array> = [ @@ -27,8 +27,8 @@ const zabbixQueryTypeOptions: Array> = [ }, { value: c.MODE_ITSERVICE, - label: 'IT Services', - description: 'Query IT Services data', + label: 'Services', + description: 'Query services SLA', }, { value: c.MODE_ITEMID, @@ -75,9 +75,10 @@ const getDefaultQuery: () => Partial = () => ({ }, }); -function getSLAQueryDefaults() { +function getSLAQueryDefaults(): Partial { return { itServiceFilter: '', + slaFilter: '', slaProperty: 'sla', slaInterval: 'none', }; @@ -166,7 +167,7 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: ZabbixQ const renderITServicesEditor = () => { return ( <> - + ); diff --git a/src/datasource/components/QueryEditor/ITServicesQueryEditor.tsx b/src/datasource/components/QueryEditor/ITServicesQueryEditor.tsx deleted file mode 100644 index 11ec611..0000000 --- a/src/datasource/components/QueryEditor/ITServicesQueryEditor.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import _ from 'lodash'; -import React, { useEffect } from 'react'; -import { useAsyncFn } from 'react-use'; - -import { SelectableValue } from '@grafana/data'; -import { InlineField, Select } from '@grafana/ui'; -import { QueryEditorRow } from './QueryEditorRow'; -import { MetricPicker } from '../../../components'; -import { getVariableOptions } from './utils'; -import { ZabbixDatasource } from '../../datasource'; -import { ZabbixMetricsQuery } from '../../types'; - -const slaPropertyList: Array> = [ - { label: 'Status', value: 'status' }, - { label: 'SLA', value: 'sla' }, - { label: 'OK time', value: 'okTime' }, - { label: 'Problem time', value: 'problemTime' }, - { label: 'Down time', value: 'downtimeTime' }, -]; - -const slaIntervals: Array> = [ - { label: 'No interval', value: 'none' }, - { label: 'Auto', value: 'auto' }, - { label: '1 hour', value: '1h' }, - { label: '12 hours', value: '12h' }, - { label: '24 hours', value: '1d' }, - { label: '1 week', value: '1w' }, - { label: '1 month', value: '1M' }, -]; - -export interface Props { - query: ZabbixMetricsQuery; - datasource: ZabbixDatasource; - onChange: (query: ZabbixMetricsQuery) => void; -} - -export const ITServicesQueryEditor = ({ query, datasource, onChange }: Props) => { - const loadITServiceOptions = async () => { - const services = await datasource.zabbix.getITService(); - const options = services?.map((s) => ({ - value: s.name, - label: s.name, - })); - options.unshift(...getVariableOptions()); - return options; - }; - - const [{ loading: itServicesLoading, value: itServicesOptions }, fetchITServices] = useAsyncFn(async () => { - const options = await loadITServiceOptions(); - return options; - }, []); - - useEffect(() => { - fetchITServices(); - }, []); - - const onPropChange = (prop: string) => { - return (option: SelectableValue) => { - if (option.value) { - onChange({ ...query, [prop]: option.value }); - } - }; - }; - - const onITServiceChange = (value: string) => { - if (value !== null) { - onChange({ ...query, itServiceFilter: value }); - } - }; - - return ( - - - - - - - - - ); -}; diff --git a/src/datasource/components/QueryEditor/ServicesQueryEditor.tsx b/src/datasource/components/QueryEditor/ServicesQueryEditor.tsx new file mode 100644 index 0000000..669a9ca --- /dev/null +++ b/src/datasource/components/QueryEditor/ServicesQueryEditor.tsx @@ -0,0 +1,133 @@ +import _ from 'lodash'; +import React, { useEffect } from 'react'; +import { useAsyncFn } from 'react-use'; + +import { SelectableValue } from '@grafana/data'; +import { InlineField, Select } from '@grafana/ui'; +import { QueryEditorRow } from './QueryEditorRow'; +import { MetricPicker } from '../../../components'; +import { getVariableOptions } from './utils'; +import { ZabbixDatasource } from '../../datasource'; +import { ZabbixMetricsQuery } from '../../types'; + +const slaPropertyList: Array> = [ + { label: 'Status', value: 'status' }, + { label: 'SLI', value: 'sli' }, + { label: 'Uptime', value: 'uptime' }, + { label: 'Downtime', value: 'downtime' }, + { label: 'Error budget', value: 'error_budget' }, +]; + +const slaIntervals: Array> = [ + { label: 'No interval', value: 'none' }, + { label: 'Auto', value: 'auto' }, + { label: '1 hour', value: '1h' }, + { label: '12 hours', value: '12h' }, + { label: '24 hours', value: '1d' }, + { label: '1 week', value: '1w' }, + { label: '1 month', value: '1M' }, +]; + +export interface Props { + query: ZabbixMetricsQuery; + datasource: ZabbixDatasource; + onChange: (query: ZabbixMetricsQuery) => void; +} + +export const ServicesQueryEditor = ({ query, datasource, onChange }: Props) => { + const loadITServiceOptions = async () => { + const services = await datasource.zabbix.getITService(); + const options = services?.map((s) => ({ + value: s.name, + label: s.name, + })); + options.unshift(...getVariableOptions()); + return options; + }; + + const [{ loading: itServicesLoading, value: itServicesOptions }, fetchITServices] = useAsyncFn(async () => { + const options = await loadITServiceOptions(); + return options; + }, []); + + const loadSLAOptions = async () => { + const slaOptions = await datasource.zabbix.getSLAList(); + const options = slaOptions?.map((s) => ({ + value: s.name, + label: s.name, + })); + options.unshift(...getVariableOptions()); + return options; + }; + + const [{ loading: slaLoading, value: slaOptions }, fetchSLAOptions] = useAsyncFn(async () => { + const options = await loadSLAOptions(); + return options; + }, []); + + useEffect(() => { + fetchITServices(); + fetchSLAOptions(); + }, []); + + const onPropChange = (prop: string) => { + return (option: SelectableValue) => { + if (option.value) { + onChange({ ...query, [prop]: option.value }); + } + }; + }; + + const onStringPropChange = (prop: string) => { + return (value: string) => { + if (value !== undefined) { + onChange({ ...query, [prop]: value }); + } + }; + }; + + return ( + <> + + + + + + + + + + + + + + + ); +}; diff --git a/src/datasource/datasource.ts b/src/datasource/datasource.ts index 7af9674..2a78a2e 100644 --- a/src/datasource/datasource.ts +++ b/src/datasource/datasource.ts @@ -470,14 +470,14 @@ export class ZabbixDatasource extends DataSourceApi