Mix backend and frontend queries from one panel

This commit is contained in:
Alexander Zobnin
2021-06-01 20:47:16 +03:00
parent 16fe4795b3
commit c546f2143d
3 changed files with 47 additions and 70 deletions

View File

@@ -15,7 +15,7 @@ import problemsHandler from './problemsHandler';
import { Zabbix } from './zabbix/zabbix';
import { ZabbixAPIError } from './zabbix/connectors/zabbix_api/zabbixAPIConnector';
import { ZabbixMetricsQuery, ZabbixDSOptions, VariableQueryTypes, ShowProblemTypes, ProblemDTO } from './types';
import { getBackendSrv, getTemplateSrv, toDataQueryResponse } from '@grafana/runtime';
import { getBackendSrv, getTemplateSrv, toDataQueryError, toDataQueryResponse } from '@grafana/runtime';
import { DataFrame, DataQueryRequest, DataQueryResponse, DataSourceApi, DataSourceInstanceSettings, FieldType, isDataFrame, LoadingState } from '@grafana/data';
export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDSOptions> {
@@ -101,18 +101,19 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
*/
query(request: DataQueryRequest<any>): Promise<DataQueryResponse> | Observable<DataQueryResponse> {
// Migrate old targets
request.targets = request.targets.map(t => {
const requestTargets = request.targets.map(t => {
// Prevent changes of original object
const target = _.cloneDeep(t);
return migrations.migrate(target);
});
if (isBackendQuery(request)) {
return this.backendQuery(request);
}
const backendResponsePromise = this.backendQuery({...request, targets: requestTargets});
// if (isBackendQuery(request)) {
// }
// Create request for each target
const promises = _.map(request.targets, target => {
const frontendTargets = requestTargets.filter(t => !isBackendTarget(t));
const promises = _.map(frontendTargets, target => {
// Don't request for hidden targets
if (target.hide) {
return [];
@@ -172,7 +173,7 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
});
// Data for panel (all targets)
return Promise.all(_.flatten(promises))
const frontendResponsePromise: Promise<DataQueryResponse> = Promise.all(_.flatten(promises))
.then(_.flatten)
.then(data => {
if (data && data.length > 0 && isDataFrame(data[0]) && !utils.isProblemsDataFrame(data[0])) {
@@ -182,19 +183,28 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
data = responseHandler.convertToWide(data);
}
}
return data;
}).then(data => {
return { data };
});
return Promise.all([backendResponsePromise, frontendResponsePromise])
.then(rsp => {
// Merge backend and frontend queries results
const [backendRes, frontendRes] = rsp;
if (frontendRes.data) {
backendRes.data = backendRes.data.concat(frontendRes.data);
}
return {
data,
data: backendRes.data,
state: LoadingState.Done,
key: request.requestId,
};
});
}
backendQuery(request: DataQueryRequest<any>): Observable<DataQueryResponse> {
async backendQuery(request: DataQueryRequest<any>): Promise<DataQueryResponse> {
const { intervalMs, maxDataPoints, range, requestId } = request;
const targets = request.targets;
const targets = request.targets.filter(isBackendTarget);
// Add range variables
request.scopedVars = Object.assign({}, request.scopedVars, utils.getRangeScopedVars(request.range));
@@ -224,7 +234,7 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
// Return early if no queries exist
if (!queries.length) {
return of({ data: [] });
return Promise.resolve({ data: [] });
}
const body: any = { queries };
@@ -235,15 +245,18 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
body.to = range.to.valueOf().toString();
}
return getBackendSrv()
.fetch({
let rsp: any;
try {
rsp = await getBackendSrv().fetch({
url: '/api/ds/query',
method: 'POST',
data: body,
requestId,
})
.pipe(
map((rsp: any) => {
}).toPromise();
} catch (err) {
return toDataQueryResponse(err);
}
const resp = toDataQueryResponse(rsp);
this.sortByRefId(resp);
this.applyFrontendFunctions(resp, request);
@@ -251,48 +264,8 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
console.log('Converting response to the wide format');
resp.data = responseHandler.convertToWide(resp.data);
}
return resp;
}),
catchError((err) => {
return of(toDataQueryResponse(err));
})
);
}
doTsdbRequest(options) {
const tsdbRequestData: any = {
queries: options.targets.map(target => {
target.datasourceId = this.datasourceId;
target.queryType = 'zabbixAPI';
return target;
}),
};
if (options.range) {
tsdbRequestData.from = options.range.from.valueOf().toString();
tsdbRequestData.to = options.range.to.valueOf().toString();
}
return getBackendSrv().post('/api/ds/query', tsdbRequestData);
}
/**
* @returns {Promise<TSDBResponse>}
*/
doTSDBConnectionTest() {
/**
* @type {{ queries: ZabbixConnectionTestQuery[] }}
*/
const tsdbRequestData = {
queries: [
{
datasourceId: this.datasourceId,
queryType: 'connectionTest'
}
]
};
return getBackendSrv().post('/api/tsdb/query', tsdbRequestData);
}
/**
@@ -972,8 +945,10 @@ function getRequestTarget(request: DataQueryRequest<any>, refId: string): any {
}
function isBackendQuery(request: DataQueryRequest<any>): boolean {
return request.targets.every(q =>
q.queryType === c.MODE_METRICS ||
q.queryType === c.MODE_ITEMID
);
return request.targets.every(isBackendTarget);
}
function isBackendTarget(target: any): boolean {
return target.queryType === c.MODE_METRICS ||
target.queryType === c.MODE_ITEMID;
}

View File

@@ -51,7 +51,9 @@ function migrateQueryType(target) {
}
// queryType is a string in query model
target.queryType = (target.queryType as number).toString();
if (typeof target.queryType === 'number') {
target.queryType = (target.queryType as number)?.toString();
}
}
function migrateSLA(target) {

View File

@@ -76,7 +76,7 @@ export class ZabbixAPIConnector {
requestOptions.headers.Authorization = this.requestOptions.basicAuth;
}
const response = await getBackendSrv().datasourceRequest(requestOptions);
const response = await getBackendSrv().fetch<any>(requestOptions).toPromise();
return response?.data?.result;
}