SLA support in Zabbix 6.0 (#1547)
This commit is contained in:
@@ -11,7 +11,7 @@ import { QueryOptionsEditor } from './QueryEditor/QueryOptionsEditor';
|
|||||||
import { TextMetricsQueryEditor } from './QueryEditor/TextMetricsQueryEditor';
|
import { TextMetricsQueryEditor } from './QueryEditor/TextMetricsQueryEditor';
|
||||||
import { ProblemsQueryEditor } from './QueryEditor/ProblemsQueryEditor';
|
import { ProblemsQueryEditor } from './QueryEditor/ProblemsQueryEditor';
|
||||||
import { ItemIdQueryEditor } from './QueryEditor/ItemIdQueryEditor';
|
import { ItemIdQueryEditor } from './QueryEditor/ItemIdQueryEditor';
|
||||||
import { ITServicesQueryEditor } from './QueryEditor/ITServicesQueryEditor';
|
import { ServicesQueryEditor } from './QueryEditor/ServicesQueryEditor';
|
||||||
import { TriggersQueryEditor } from './QueryEditor/TriggersQueryEditor';
|
import { TriggersQueryEditor } from './QueryEditor/TriggersQueryEditor';
|
||||||
|
|
||||||
const zabbixQueryTypeOptions: Array<SelectableValue<string>> = [
|
const zabbixQueryTypeOptions: Array<SelectableValue<string>> = [
|
||||||
@@ -27,8 +27,8 @@ const zabbixQueryTypeOptions: Array<SelectableValue<string>> = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: c.MODE_ITSERVICE,
|
value: c.MODE_ITSERVICE,
|
||||||
label: 'IT Services',
|
label: 'Services',
|
||||||
description: 'Query IT Services data',
|
description: 'Query services SLA',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: c.MODE_ITEMID,
|
value: c.MODE_ITEMID,
|
||||||
@@ -75,9 +75,10 @@ const getDefaultQuery: () => Partial<ZabbixMetricsQuery> = () => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function getSLAQueryDefaults() {
|
function getSLAQueryDefaults(): Partial<ZabbixMetricsQuery> {
|
||||||
return {
|
return {
|
||||||
itServiceFilter: '',
|
itServiceFilter: '',
|
||||||
|
slaFilter: '',
|
||||||
slaProperty: 'sla',
|
slaProperty: 'sla',
|
||||||
slaInterval: 'none',
|
slaInterval: 'none',
|
||||||
};
|
};
|
||||||
@@ -166,7 +167,7 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: ZabbixQ
|
|||||||
const renderITServicesEditor = () => {
|
const renderITServicesEditor = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ITServicesQueryEditor query={query} datasource={datasource} onChange={onChangeInternal} />
|
<ServicesQueryEditor query={query} datasource={datasource} onChange={onChangeInternal} />
|
||||||
<QueryFunctionsEditor query={query} onChange={onChangeInternal} />
|
<QueryFunctionsEditor query={query} onChange={onChangeInternal} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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<SelectableValue<string>> = [
|
|
||||||
{ 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<SelectableValue<string>> = [
|
|
||||||
{ 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 (
|
|
||||||
<QueryEditorRow>
|
|
||||||
<InlineField label="IT Service" labelWidth={12}>
|
|
||||||
<MetricPicker
|
|
||||||
width={24}
|
|
||||||
value={query.itServiceFilter}
|
|
||||||
options={itServicesOptions}
|
|
||||||
isLoading={itServicesLoading}
|
|
||||||
onChange={onITServiceChange}
|
|
||||||
/>
|
|
||||||
</InlineField>
|
|
||||||
<InlineField label="Property" labelWidth={12}>
|
|
||||||
<Select
|
|
||||||
isSearchable={false}
|
|
||||||
width={24}
|
|
||||||
value={query.slaProperty}
|
|
||||||
options={slaPropertyList}
|
|
||||||
onChange={onPropChange('slaProperty')}
|
|
||||||
/>
|
|
||||||
</InlineField>
|
|
||||||
<InlineField label="Interval" labelWidth={12}>
|
|
||||||
<Select
|
|
||||||
isSearchable={false}
|
|
||||||
width={24}
|
|
||||||
value={query.slaInterval}
|
|
||||||
options={slaIntervals}
|
|
||||||
onChange={onPropChange('slaInterval')}
|
|
||||||
/>
|
|
||||||
</InlineField>
|
|
||||||
</QueryEditorRow>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
133
src/datasource/components/QueryEditor/ServicesQueryEditor.tsx
Normal file
133
src/datasource/components/QueryEditor/ServicesQueryEditor.tsx
Normal file
@@ -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<SelectableValue<string>> = [
|
||||||
|
{ 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<SelectableValue<string>> = [
|
||||||
|
{ 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 (
|
||||||
|
<>
|
||||||
|
<QueryEditorRow>
|
||||||
|
<InlineField label="Service" labelWidth={12}>
|
||||||
|
<MetricPicker
|
||||||
|
width={24}
|
||||||
|
value={query.itServiceFilter}
|
||||||
|
options={itServicesOptions}
|
||||||
|
isLoading={itServicesLoading}
|
||||||
|
onChange={onStringPropChange('itServiceFilter')}
|
||||||
|
/>
|
||||||
|
</InlineField>
|
||||||
|
<InlineField label="SLA" labelWidth={12}>
|
||||||
|
<MetricPicker
|
||||||
|
width={24}
|
||||||
|
value={query.slaFilter}
|
||||||
|
options={slaOptions}
|
||||||
|
isLoading={slaLoading}
|
||||||
|
onChange={onStringPropChange('slaFilter')}
|
||||||
|
/>
|
||||||
|
</InlineField>
|
||||||
|
</QueryEditorRow>
|
||||||
|
<QueryEditorRow>
|
||||||
|
<InlineField label="Property" labelWidth={12}>
|
||||||
|
<Select
|
||||||
|
isSearchable={false}
|
||||||
|
width={24}
|
||||||
|
value={query.slaProperty}
|
||||||
|
options={slaPropertyList}
|
||||||
|
onChange={onPropChange('slaProperty')}
|
||||||
|
/>
|
||||||
|
</InlineField>
|
||||||
|
<InlineField label="Interval" labelWidth={12}>
|
||||||
|
<Select
|
||||||
|
isSearchable={false}
|
||||||
|
width={24}
|
||||||
|
value={query.slaInterval}
|
||||||
|
options={slaIntervals}
|
||||||
|
onChange={onPropChange('slaInterval')}
|
||||||
|
/>
|
||||||
|
</InlineField>
|
||||||
|
</QueryEditorRow>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -470,14 +470,14 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
/**
|
/**
|
||||||
* Query target data for IT Services
|
* Query target data for IT Services
|
||||||
*/
|
*/
|
||||||
async queryITServiceData(target, timeRange, request) {
|
async queryITServiceData(target: ZabbixMetricsQuery, timeRange, request) {
|
||||||
// Don't show undefined and hidden targets
|
// Don't show undefined and hidden targets
|
||||||
if (target.hide || (!target.itservice && !target.itServiceFilter) || !target.slaProperty) {
|
if (target.hide || (!(target as any).itservice && !target.itServiceFilter) || !target.slaProperty) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
let itServiceFilter;
|
let itServiceFilter;
|
||||||
request.isOldVersion = target.itservice && !target.itServiceFilter;
|
request.isOldVersion = (target as any).itservice && !target.itServiceFilter;
|
||||||
|
|
||||||
if (request.isOldVersion) {
|
if (request.isOldVersion) {
|
||||||
// Backward compatibility
|
// Backward compatibility
|
||||||
@@ -490,7 +490,13 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
|
|
||||||
let itservices = await this.zabbix.getITServices(itServiceFilter);
|
let itservices = await this.zabbix.getITServices(itServiceFilter);
|
||||||
if (request.isOldVersion) {
|
if (request.isOldVersion) {
|
||||||
itservices = _.filter(itservices, { serviceid: target.itservice?.serviceid });
|
itservices = _.filter(itservices, { serviceid: (target as any).itservice?.serviceid });
|
||||||
|
}
|
||||||
|
if (target.slaFilter !== undefined) {
|
||||||
|
const slaFilter = this.replaceTemplateVars(target.slaFilter, request.scopedVars);
|
||||||
|
const slas = await this.zabbix.getSLAs(slaFilter);
|
||||||
|
const result = await this.zabbix.getSLI(itservices, slas, timeRange, target, request);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
const itservicesdp = await this.zabbix.getSLA(itservices, timeRange, target, request);
|
const itservicesdp = await this.zabbix.getSLA(itservices, timeRange, target, request);
|
||||||
const backendRequest = responseHandler.itServiceResponseToTimeSeries(itservicesdp, target.slaInterval);
|
const backendRequest = responseHandler.itServiceResponseToTimeSeries(itservicesdp, target.slaInterval);
|
||||||
|
|||||||
@@ -467,7 +467,105 @@ function extractText(str, pattern, useCaptureGroups) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSLAResponse(itservice, slaProperty, slaObject) {
|
export function handleSLIResponse(response: any, itservices: any[], target: ZabbixMetricsQuery) {
|
||||||
|
const timestamps = [];
|
||||||
|
for (let i = 0; i < response?.periods?.length; i++) {
|
||||||
|
const period = response.periods[i];
|
||||||
|
if (i === 0) {
|
||||||
|
timestamps.push(period.period_from * 1000);
|
||||||
|
}
|
||||||
|
timestamps.push(period.period_to * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeFiled: Field = {
|
||||||
|
name: TIME_SERIES_TIME_FIELD_NAME,
|
||||||
|
type: FieldType.time,
|
||||||
|
config: {
|
||||||
|
custom: {},
|
||||||
|
},
|
||||||
|
values: new ArrayVector<number>(timestamps),
|
||||||
|
};
|
||||||
|
|
||||||
|
const valueFields: Field[] = [];
|
||||||
|
const values: number[][] = [];
|
||||||
|
|
||||||
|
let slaProperty = mapLegacySLAProperty(target.slaProperty);
|
||||||
|
for (let i = 0; i < response?.sli?.length; i++) {
|
||||||
|
const slis = response.sli[i];
|
||||||
|
for (let j = 0; j < slis.length; j++) {
|
||||||
|
const sli = slis[j];
|
||||||
|
const value = sli[slaProperty];
|
||||||
|
if (!values[j]) {
|
||||||
|
values[j] = [];
|
||||||
|
}
|
||||||
|
if (i === 0) {
|
||||||
|
values[j].push(value);
|
||||||
|
}
|
||||||
|
values[j].push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < response?.serviceids?.length; i++) {
|
||||||
|
const serviceId = response?.serviceids[i].toString();
|
||||||
|
const service = itservices.find((s) => s.serviceid === serviceId);
|
||||||
|
valueFields.push({
|
||||||
|
name: service ? service.name : serviceId,
|
||||||
|
type: FieldType.number,
|
||||||
|
config: {},
|
||||||
|
values: new ArrayVector<number>(values[i]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MutableDataFrame({
|
||||||
|
refId: target.refId,
|
||||||
|
name: 'SLI',
|
||||||
|
fields: [timeFiled, ...valueFields],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapLegacySLAProperty(property: string) {
|
||||||
|
switch (property) {
|
||||||
|
case 'sla':
|
||||||
|
return 'sli';
|
||||||
|
case 'okTime':
|
||||||
|
return 'uptime';
|
||||||
|
case 'downtimeTime':
|
||||||
|
return 'downtime';
|
||||||
|
default:
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleServiceResponse(response: any, itservices: any[], target: ZabbixMetricsQuery) {
|
||||||
|
const valueFields: Field[] = [];
|
||||||
|
for (let i = 0; i < response?.length; i++) {
|
||||||
|
const service = response[i];
|
||||||
|
const status = Number(service.status);
|
||||||
|
valueFields.push({
|
||||||
|
name: service ? service.name : i,
|
||||||
|
type: FieldType.number,
|
||||||
|
config: {},
|
||||||
|
values: new ArrayVector<number>([status]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeFiled: Field = {
|
||||||
|
name: TIME_SERIES_TIME_FIELD_NAME,
|
||||||
|
type: FieldType.time,
|
||||||
|
config: {
|
||||||
|
custom: {},
|
||||||
|
},
|
||||||
|
values: new ArrayVector<number>([Date.now()]),
|
||||||
|
};
|
||||||
|
|
||||||
|
return new MutableDataFrame({
|
||||||
|
refId: target.refId,
|
||||||
|
name: 'Service status',
|
||||||
|
fields: [timeFiled, ...valueFields],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleSLAResponse(itservice, slaProperty, slaObject) {
|
||||||
const targetSLA = slaObject[itservice.serviceid].sla;
|
const targetSLA = slaObject[itservice.serviceid].sla;
|
||||||
if (slaProperty === 'status') {
|
if (slaProperty === 'status') {
|
||||||
const targetStatus = parseInt(slaObject[itservice.serviceid].status, 10);
|
const targetStatus = parseInt(slaObject[itservice.serviceid].status, 10);
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export interface ZabbixMetricsQuery extends DataQuery {
|
|||||||
proxy?: { filter: string };
|
proxy?: { filter: string };
|
||||||
trigger?: { filter: string };
|
trigger?: { filter: string };
|
||||||
itServiceFilter?: string;
|
itServiceFilter?: string;
|
||||||
|
slaFilter?: string;
|
||||||
slaProperty?: any;
|
slaProperty?: any;
|
||||||
slaInterval?: string;
|
slaInterval?: string;
|
||||||
tags?: { filter: string };
|
tags?: { filter: string };
|
||||||
|
|||||||
@@ -330,7 +330,7 @@ export class ZabbixAPIConnector {
|
|||||||
return self.request('trend.get', params);
|
return self.request('trend.get', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
getITService(serviceids?) {
|
getITService(serviceids?: any[]) {
|
||||||
const params = {
|
const params = {
|
||||||
output: 'extend',
|
output: 'extend',
|
||||||
serviceids: serviceids,
|
serviceids: serviceids,
|
||||||
@@ -338,6 +338,22 @@ export class ZabbixAPIConnector {
|
|||||||
return this.request('service.get', params);
|
return this.request('service.get', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns services. Non-cached method (for getting actual service status).
|
||||||
|
getServices(serviceids?: any[]) {
|
||||||
|
const params = {
|
||||||
|
output: 'extend',
|
||||||
|
serviceids: serviceids,
|
||||||
|
};
|
||||||
|
return this.request('service.get', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSLAList() {
|
||||||
|
const params = {
|
||||||
|
output: 'extend',
|
||||||
|
};
|
||||||
|
return this.request('sla.get', params);
|
||||||
|
}
|
||||||
|
|
||||||
getSLA(serviceids, timeRange, options) {
|
getSLA(serviceids, timeRange, options) {
|
||||||
const [timeFrom, timeTo] = timeRange;
|
const [timeFrom, timeTo] = timeRange;
|
||||||
let intervals = [{ from: timeFrom, to: timeTo }];
|
let intervals = [{ from: timeFrom, to: timeTo }];
|
||||||
@@ -416,6 +432,29 @@ export class ZabbixAPIConnector {
|
|||||||
return slaLikeResponse;
|
return slaLikeResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getSLI(slaid, serviceids, timeRange, options) {
|
||||||
|
const [timeFrom, timeTo] = timeRange;
|
||||||
|
let intervals = [{ from: timeFrom, to: timeTo }];
|
||||||
|
if (options.slaInterval === 'auto') {
|
||||||
|
const interval = getSLAInterval(options.intervalMs);
|
||||||
|
intervals = buildSLAIntervals(timeRange, interval);
|
||||||
|
} else if (options.slaInterval !== 'none') {
|
||||||
|
const interval = utils.parseInterval(options.slaInterval) / 1000;
|
||||||
|
intervals = buildSLAIntervals(timeRange, interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sliParams: any = {
|
||||||
|
slaid,
|
||||||
|
serviceids,
|
||||||
|
period_from: timeFrom,
|
||||||
|
period_to: timeTo,
|
||||||
|
periods: Math.min(intervals.length, 100),
|
||||||
|
};
|
||||||
|
|
||||||
|
const sliResponse = await this.request('sla.getsli', sliParams);
|
||||||
|
return sliResponse;
|
||||||
|
}
|
||||||
|
|
||||||
getProblems(groupids, hostids, applicationids, options): Promise<ZBXProblem[]> {
|
getProblems(groupids, hostids, applicationids, options): Promise<ZBXProblem[]> {
|
||||||
const { timeFrom, timeTo, recent, severities, limit, acknowledged, tags } = options;
|
const { timeFrom, timeTo, recent, severities, limit, acknowledged, tags } = options;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import _ from 'lodash';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import * as utils from '../utils';
|
import * as utils from '../utils';
|
||||||
import responseHandler from '../responseHandler';
|
import responseHandler, { handleServiceResponse, handleSLIResponse } from '../responseHandler';
|
||||||
import { CachingProxy } from './proxy/cachingProxy';
|
import { CachingProxy } from './proxy/cachingProxy';
|
||||||
import { DBConnector } from './connectors/dbConnector';
|
import { DBConnector } from './connectors/dbConnector';
|
||||||
import { ZabbixAPIConnector } from './connectors/zabbix_api/zabbixAPIConnector';
|
import { ZabbixAPIConnector } from './connectors/zabbix_api/zabbixAPIConnector';
|
||||||
@@ -11,7 +11,7 @@ import { SQLConnector } from './connectors/sql/sqlConnector';
|
|||||||
import { InfluxDBConnector } from './connectors/influxdb/influxdbConnector';
|
import { InfluxDBConnector } from './connectors/influxdb/influxdbConnector';
|
||||||
import { ZabbixConnector } from './types';
|
import { ZabbixConnector } from './types';
|
||||||
import { joinTriggersWithEvents, joinTriggersWithProblems } from '../problemsHandler';
|
import { joinTriggersWithEvents, joinTriggersWithProblems } from '../problemsHandler';
|
||||||
import { ProblemDTO, ZBXItem, ZBXItemTag } from '../types';
|
import { ProblemDTO, ZabbixMetricsQuery, ZBXItem, ZBXItemTag } from '../types';
|
||||||
|
|
||||||
interface AppsResponse extends Array<any> {
|
interface AppsResponse extends Array<any> {
|
||||||
appFilterEmpty?: boolean;
|
appFilterEmpty?: boolean;
|
||||||
@@ -41,6 +41,7 @@ const REQUESTS_TO_PROXYFY = [
|
|||||||
'getTriggersByIds',
|
'getTriggersByIds',
|
||||||
'getScripts',
|
'getScripts',
|
||||||
'getValueMappings',
|
'getValueMappings',
|
||||||
|
'getSLAList',
|
||||||
];
|
];
|
||||||
|
|
||||||
const REQUESTS_TO_CACHE = [
|
const REQUESTS_TO_CACHE = [
|
||||||
@@ -53,6 +54,7 @@ const REQUESTS_TO_CACHE = [
|
|||||||
'getITService',
|
'getITService',
|
||||||
'getProxies',
|
'getProxies',
|
||||||
'getValueMappings',
|
'getValueMappings',
|
||||||
|
'getSLAList',
|
||||||
];
|
];
|
||||||
|
|
||||||
const REQUESTS_TO_BIND = [
|
const REQUESTS_TO_BIND = [
|
||||||
@@ -72,6 +74,7 @@ const REQUESTS_TO_BIND = [
|
|||||||
'getScripts',
|
'getScripts',
|
||||||
'executeScript',
|
'executeScript',
|
||||||
'getValueMappings',
|
'getValueMappings',
|
||||||
|
'getSLAList',
|
||||||
];
|
];
|
||||||
|
|
||||||
export class Zabbix implements ZabbixConnector {
|
export class Zabbix implements ZabbixConnector {
|
||||||
@@ -97,6 +100,7 @@ export class Zabbix implements ZabbixConnector {
|
|||||||
getExtendedEventData: (eventids) => Promise<any>;
|
getExtendedEventData: (eventids) => Promise<any>;
|
||||||
getMacros: (hostids: any[]) => Promise<any>;
|
getMacros: (hostids: any[]) => Promise<any>;
|
||||||
getValueMappings: () => Promise<any>;
|
getValueMappings: () => Promise<any>;
|
||||||
|
getSLAList: () => Promise<any>;
|
||||||
|
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
const {
|
const {
|
||||||
@@ -396,8 +400,14 @@ export class Zabbix implements ZabbixConnector {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getITServices(itServiceFilter) {
|
async getITServices(itServiceFilter: string) {
|
||||||
return this.zabbixAPI.getITService().then((itServices) => findByFilter(itServices, itServiceFilter));
|
const itServices = await this.zabbixAPI.getITService();
|
||||||
|
return findByFilter(itServices, itServiceFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSLAs(slaFilter: string) {
|
||||||
|
const slas = await this.zabbixAPI.getSLAList();
|
||||||
|
return findByFilter(slas, slaFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
getProblems(groupFilter, hostFilter, appFilter, proxyFilter?, options?): Promise<ProblemDTO[]> {
|
getProblems(groupFilter, hostFilter, appFilter, proxyFilter?, options?): Promise<ProblemDTO[]> {
|
||||||
@@ -538,6 +548,19 @@ export class Zabbix implements ZabbixConnector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getSLI(itservices: any[], slas: any[], timeRange, target: ZabbixMetricsQuery, options) {
|
||||||
|
const itServiceIds = itservices.map((s) => s.serviceid);
|
||||||
|
if (target.slaProperty === 'status') {
|
||||||
|
const res = await this.zabbixAPI.getServices(itServiceIds);
|
||||||
|
return handleServiceResponse(res, itservices, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
const slaIds = slas.map((s) => s.slaid);
|
||||||
|
const slaId = slaIds?.length > 0 ? slaIds[0] : undefined;
|
||||||
|
const result = await this.zabbixAPI.getSLI(slaId, itServiceIds, timeRange, options);
|
||||||
|
return handleSLIResponse(result, itservices, target);
|
||||||
|
}
|
||||||
|
|
||||||
async getSLA(itservices, timeRange, target, options) {
|
async getSLA(itservices, timeRange, target, options) {
|
||||||
const itServiceIds = _.map(itservices, 'serviceid');
|
const itServiceIds = _.map(itservices, 'serviceid');
|
||||||
if (this.supportSLA()) {
|
if (this.supportSLA()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user