Alerting: azure monitoring manual backports (#42528)
Co-authored-by: Peter Holmberg <peter.hlmbrg@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com> Co-authored-by: Domas <domas.lapinskas@grafana.com>
This commit is contained in:
co-authored by
Peter Holmberg
Domas
parent
7bcc44e44e
commit
febe5c9304
@@ -240,6 +240,15 @@ abstract class DataSourceApi<
|
||||
*/
|
||||
abstract testDatasource(): Promise<any>;
|
||||
|
||||
/**
|
||||
* Override to skip executing a query
|
||||
*
|
||||
* @returns false if the query should be skipped
|
||||
*
|
||||
* @virtual
|
||||
*/
|
||||
filterQuery?(query: TQuery): boolean;
|
||||
|
||||
/**
|
||||
* Get hints for query improvements
|
||||
*/
|
||||
|
||||
@@ -19,6 +19,10 @@ jest.mock('@grafana/runtime', () => ({
|
||||
getDataSourceSrv: () => {
|
||||
return {
|
||||
getInstanceSettings: () => ({ name: 'prometheus' }),
|
||||
get: () =>
|
||||
Promise.resolve({
|
||||
filterQuery: () => true,
|
||||
}),
|
||||
};
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -136,6 +136,7 @@ export class QueryRows extends PureComponent<Props, State> {
|
||||
return {
|
||||
...item,
|
||||
refId: query.refId,
|
||||
queryType: item.model.queryType ?? '',
|
||||
model: {
|
||||
...item.model,
|
||||
...query,
|
||||
|
||||
@@ -24,7 +24,8 @@ export const VizWrapper: FC<Props> = ({ data, currentPanel, changePanel, onThres
|
||||
});
|
||||
const vizHeight = useVizHeight(data, currentPanel, options.frameIndex);
|
||||
const styles = useStyles2(getStyles(vizHeight));
|
||||
const [fieldConfig, setFieldConfig] = useState<FieldConfigSource>(defaultFieldConfig(thresholds));
|
||||
|
||||
const [fieldConfig, setFieldConfig] = useState<FieldConfigSource>(defaultFieldConfig(thresholds, data));
|
||||
|
||||
useEffect(() => {
|
||||
setFieldConfig((fieldConfig) => ({
|
||||
@@ -32,6 +33,7 @@ export const VizWrapper: FC<Props> = ({ data, currentPanel, changePanel, onThres
|
||||
defaults: {
|
||||
...fieldConfig.defaults,
|
||||
thresholds: thresholds,
|
||||
unit: defaultUnit(data),
|
||||
custom: {
|
||||
...fieldConfig.defaults.custom,
|
||||
thresholdsStyle: {
|
||||
@@ -40,7 +42,7 @@ export const VizWrapper: FC<Props> = ({ data, currentPanel, changePanel, onThres
|
||||
},
|
||||
},
|
||||
}));
|
||||
}, [thresholds, setFieldConfig]);
|
||||
}, [thresholds, setFieldConfig, data]);
|
||||
|
||||
const context: PanelContext = useMemo(
|
||||
() => ({
|
||||
@@ -98,13 +100,19 @@ const getStyles = (visHeight: number) => (theme: GrafanaTheme2) => ({
|
||||
`,
|
||||
});
|
||||
|
||||
function defaultFieldConfig(thresholds: ThresholdsConfig): FieldConfigSource {
|
||||
function defaultUnit(data: PanelData): string | undefined {
|
||||
return data.series[0]?.fields.find((field) => field.type === 'number')?.config.unit;
|
||||
}
|
||||
|
||||
function defaultFieldConfig(thresholds: ThresholdsConfig, data: PanelData): FieldConfigSource {
|
||||
if (!thresholds) {
|
||||
return { defaults: {}, overrides: [] };
|
||||
}
|
||||
|
||||
return {
|
||||
defaults: {
|
||||
thresholds: thresholds,
|
||||
unit: defaultUnit(data),
|
||||
custom: {
|
||||
thresholdsStyle: {
|
||||
mode: 'line',
|
||||
|
||||
@@ -2,13 +2,14 @@ import {
|
||||
ArrayVector,
|
||||
DataFrame,
|
||||
DataFrameJSON,
|
||||
DataSourceApi,
|
||||
Field,
|
||||
FieldType,
|
||||
getDefaultRelativeTimeRange,
|
||||
LoadingState,
|
||||
rangeUtil,
|
||||
} from '@grafana/data';
|
||||
import { FetchResponse } from '@grafana/runtime';
|
||||
import { DataSourceSrv, FetchResponse } from '@grafana/runtime';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
||||
import { Observable, of, throwError } from 'rxjs';
|
||||
@@ -28,7 +29,8 @@ describe('AlertingQueryRunner', () => {
|
||||
const runner = new AlertingQueryRunner(
|
||||
mockBackendSrv({
|
||||
fetch: () => of(response),
|
||||
})
|
||||
}),
|
||||
mockDataSourceSrv()
|
||||
);
|
||||
|
||||
const data = runner.get();
|
||||
@@ -82,7 +84,8 @@ describe('AlertingQueryRunner', () => {
|
||||
const runner = new AlertingQueryRunner(
|
||||
mockBackendSrv({
|
||||
fetch: () => of(response),
|
||||
})
|
||||
}),
|
||||
mockDataSourceSrv()
|
||||
);
|
||||
|
||||
const data = runner.get();
|
||||
@@ -110,7 +113,8 @@ describe('AlertingQueryRunner', () => {
|
||||
const runner = new AlertingQueryRunner(
|
||||
mockBackendSrv({
|
||||
fetch: () => of(response).pipe(delay(210)),
|
||||
})
|
||||
}),
|
||||
mockDataSourceSrv()
|
||||
);
|
||||
|
||||
const data = runner.get();
|
||||
@@ -162,7 +166,8 @@ describe('AlertingQueryRunner', () => {
|
||||
const runner = new AlertingQueryRunner(
|
||||
mockBackendSrv({
|
||||
fetch: () => throwError(error),
|
||||
})
|
||||
}),
|
||||
mockDataSourceSrv()
|
||||
);
|
||||
|
||||
const data = runner.get();
|
||||
@@ -178,6 +183,28 @@ describe('AlertingQueryRunner', () => {
|
||||
expect(data.B.error).toEqual(error);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not execute if a query fails filterQuery check', async () => {
|
||||
const runner = new AlertingQueryRunner(
|
||||
mockBackendSrv({
|
||||
fetch: () => throwError(new Error("shouldn't happen")),
|
||||
}),
|
||||
mockDataSourceSrv({ filterQuery: () => false })
|
||||
);
|
||||
|
||||
const data = runner.get();
|
||||
runner.run([createQuery('A'), createQuery('B')]);
|
||||
|
||||
await expect(data.pipe(take(1))).toEmitValuesWith((values) => {
|
||||
const [data] = values;
|
||||
|
||||
expect(data.A.state).toEqual(LoadingState.Done);
|
||||
expect(data.A.series).toHaveLength(0);
|
||||
|
||||
expect(data.B.state).toEqual(LoadingState.Done);
|
||||
expect(data.B.series).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
type MockBackendSrvConfig = {
|
||||
@@ -191,6 +218,12 @@ const mockBackendSrv = ({ fetch }: MockBackendSrvConfig): BackendSrv => {
|
||||
} as unknown) as BackendSrv;
|
||||
};
|
||||
|
||||
const mockDataSourceSrv = (dsApi?: Partial<DataSourceApi>) => {
|
||||
return ({
|
||||
get: () => Promise.resolve(dsApi ?? {}),
|
||||
} as unknown) as DataSourceSrv;
|
||||
};
|
||||
|
||||
const expectDataFrameWithValues = ({ time, values }: { time: number[]; values: number[] }): DataFrame => {
|
||||
return {
|
||||
fields: [
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
TimeRange,
|
||||
withLoadingIndicator,
|
||||
} from '@grafana/data';
|
||||
import { FetchResponse, toDataQueryError } from '@grafana/runtime';
|
||||
import { FetchResponse, getDataSourceSrv, toDataQueryError } from '@grafana/runtime';
|
||||
import { BackendSrv, getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import { preProcessPanelData } from 'app/features/query/state/runRequest';
|
||||
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
||||
@@ -32,7 +32,7 @@ export class AlertingQueryRunner {
|
||||
private subscription?: Unsubscribable;
|
||||
private lastResult: Record<string, PanelData>;
|
||||
|
||||
constructor(private backendSrv = getBackendSrv()) {
|
||||
constructor(private backendSrv = getBackendSrv(), private dataSourceSrv = getDataSourceSrv()) {
|
||||
this.subject = new ReplaySubject(1);
|
||||
this.lastResult = {};
|
||||
}
|
||||
@@ -41,12 +41,24 @@ export class AlertingQueryRunner {
|
||||
return this.subject.asObservable();
|
||||
}
|
||||
|
||||
run(queries: AlertQuery[]) {
|
||||
async run(queries: AlertQuery[]) {
|
||||
if (queries.length === 0) {
|
||||
const empty = initialState(queries, LoadingState.Done);
|
||||
return this.subject.next(empty);
|
||||
}
|
||||
|
||||
// do not execute if one more of the queries are not runnable,
|
||||
// for example not completely configured
|
||||
for (const query of queries) {
|
||||
if (!isExpressionQuery(query.model)) {
|
||||
const ds = await this.dataSourceSrv.get(query.datasourceUid);
|
||||
if (ds.filterQuery && !ds.filterQuery(query.model)) {
|
||||
const empty = initialState(queries, LoadingState.Done);
|
||||
return this.subject.next(empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.subscription = runRequest(this.backendSrv, queries).subscribe({
|
||||
next: (dataPerQuery) => {
|
||||
const nextResult = applyChange(dataPerQuery, (refId, data) => {
|
||||
|
||||
@@ -73,6 +73,14 @@ export default class Datasource extends DataSourceApi<AzureMonitorQuery, AzureDa
|
||||
}
|
||||
}
|
||||
|
||||
filterQuery(item: AzureMonitorQuery): boolean {
|
||||
if (!item.queryType) {
|
||||
return true;
|
||||
}
|
||||
const ds = this.pseudoDatasource[item.queryType];
|
||||
return ds?.filterQuery?.(item) ?? true;
|
||||
}
|
||||
|
||||
query(options: DataQueryRequest<AzureMonitorQuery>): Observable<DataQueryResponse> {
|
||||
const byType = new Map<AzureQueryType, DataQueryRequest<AzureMonitorQuery>>();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user