diff --git a/public/app/plugins/datasource/prometheus/datasource.test.ts b/public/app/plugins/datasource/prometheus/datasource.test.ts index de61312c84b..1fadcd72741 100644 --- a/public/app/plugins/datasource/prometheus/datasource.test.ts +++ b/public/app/plugins/datasource/prometheus/datasource.test.ts @@ -131,6 +131,7 @@ describe('PrometheusDatasource', () => { describe('customQueryParams', () => { const target = { expr: 'test{job="testjob"}', format: 'time_series', refId: '' }; + function makeQuery(target: PromQuery) { return { range: { from: time({ seconds: 63 }), to: time({ seconds: 183 }) }, @@ -140,19 +141,27 @@ describe('PrometheusDatasource', () => { } describe('with GET http method', () => { - const promDs = new PrometheusDatasource( - { ...instanceSettings, jsonData: { customQueryParameters: 'customQuery=123', httpMethod: 'GET' } as any }, - templateSrvStub as any, - timeSrvStub as any - ); + const getPromDs = (access: 'direct' | 'proxy') => { + return new PrometheusDatasource( + { + ...instanceSettings, + access, + jsonData: { customQueryParameters: 'customQuery=123', httpMethod: 'GET' } as any, + }, + templateSrvStub as any, + timeSrvStub as any + ); + }; it('added to metadata request', () => { + const promDs = getPromDs('proxy'); promDs.metadataRequest('/foo'); expect(fetchMock.mock.calls.length).toBe(1); expect(fetchMock.mock.calls[0][0].url).toBe('/api/datasources/1/resources/foo?customQuery=123'); }); it('adds params to timeseries query', () => { + const promDs = getPromDs('direct'); promDs.query(makeQuery(target)); expect(fetchMock.mock.calls.length).toBe(1); expect(fetchMock.mock.calls[0][0].url).toBe( @@ -160,6 +169,7 @@ describe('PrometheusDatasource', () => { ); }); it('adds params to exemplars query', () => { + const promDs = getPromDs('direct'); promDs.query(makeQuery({ ...target, exemplar: true })); // We do also range query for single exemplars target expect(fetchMock.mock.calls.length).toBe(2); @@ -168,6 +178,7 @@ describe('PrometheusDatasource', () => { }); it('adds params to instant query', () => { + const promDs = getPromDs('direct'); promDs.query(makeQuery({ ...target, instant: true })); expect(fetchMock.mock.calls.length).toBe(1); expect(fetchMock.mock.calls[0][0].url).toContain('&customQuery=123'); @@ -175,19 +186,31 @@ describe('PrometheusDatasource', () => { }); describe('with POST http method', () => { - const promDs = new PrometheusDatasource( - { ...instanceSettings, jsonData: { customQueryParameters: 'customQuery=123', httpMethod: 'POST' } as any }, - templateSrvStub as any, - timeSrvStub as any - ); + const getPromDs = (access: 'direct' | 'proxy') => { + return new PrometheusDatasource( + { + ...instanceSettings, + access, + jsonData: { customQueryParameters: 'customQuery=123', httpMethod: 'POST' } as any, + }, + templateSrvStub as any, + timeSrvStub as any + ); + }; - it('added to metadata request with non-POST endpoint', () => { - promDs.metadataRequest('/foo'); + it('added to metadata request with non-POST endpoint ', () => { + const proxyPromDs = getPromDs('proxy'); + proxyPromDs.metadataRequest('/foo'); expect(fetchMock.mock.calls.length).toBe(1); expect(fetchMock.mock.calls[0][0].url).toBe('/api/datasources/1/resources/foo?customQuery=123'); + const directPromDs = getPromDs('direct'); + directPromDs.metadataRequest('/foo'); + expect(fetchMock.mock.calls.length).toBe(2); + expect(fetchMock.mock.calls[1][0].url).toBe('proxied/foo?customQuery=123'); }); it('added to metadata request with POST endpoint', () => { + const promDs = getPromDs('proxy'); promDs.metadataRequest('/api/v1/labels'); expect(fetchMock.mock.calls.length).toBe(1); expect(fetchMock.mock.calls[0][0].url).toBe('/api/datasources/1/resources/api/v1/labels'); @@ -195,6 +218,7 @@ describe('PrometheusDatasource', () => { }); it('adds params to timeseries query', () => { + const promDs = getPromDs('direct'); promDs.query(makeQuery(target)); expect(fetchMock.mock.calls.length).toBe(1); expect(fetchMock.mock.calls[0][0].url).toBe('proxied/api/v1/query_range'); @@ -206,7 +230,9 @@ describe('PrometheusDatasource', () => { start: 60, }); }); + it('adds params to exemplars query', () => { + const promDs = getPromDs('direct'); promDs.query(makeQuery({ ...target, exemplar: true })); // We do also range query for single exemplars target expect(fetchMock.mock.calls.length).toBe(2); @@ -215,6 +241,7 @@ describe('PrometheusDatasource', () => { }); it('adds params to instant query', () => { + const promDs = getPromDs('direct'); promDs.query(makeQuery({ ...target, instant: true })); expect(fetchMock.mock.calls.length).toBe(1); expect(fetchMock.mock.calls[0][0].data.customQuery).toBe('123'); diff --git a/public/app/plugins/datasource/prometheus/datasource.tsx b/public/app/plugins/datasource/prometheus/datasource.tsx index 98b72c1bd46..bfad420e39e 100644 --- a/public/app/plugins/datasource/prometheus/datasource.tsx +++ b/public/app/plugins/datasource/prometheus/datasource.tsx @@ -5,8 +5,10 @@ import { forkJoin, lastValueFrom, merge, Observable, of, OperatorFunction, pipe, import { catchError, filter, map, tap } from 'rxjs/operators'; import { + AbstractQuery, AnnotationEvent, CoreApp, + DataFrame, DataQueryError, DataQueryRequest, DataQueryResponse, @@ -15,31 +17,29 @@ import { DataSourceWithQueryImportSupport, dateMath, DateTime, - AbstractQuery, + dateTime, LoadingState, + QueryFixAction, rangeUtil, ScopedVars, TimeRange, - DataFrame, - dateTime, - QueryFixAction, } from '@grafana/data'; import { + BackendDataSourceResponse, BackendSrvRequest, + DataSourceWithBackend, FetchError, FetchResponse, getBackendSrv, - DataSourceWithBackend, - BackendDataSourceResponse, - toDataQueryResponse, isFetchError, + toDataQueryResponse, } from '@grafana/runtime'; import { Badge, BadgeColor, Tooltip } from '@grafana/ui'; import { safeStringifyValue } from 'app/core/utils/explore'; import { discoverDataSourceFeatures } from 'app/features/alerting/unified/api/buildInfo'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv'; -import { PromApplication, PromApiFeatures } from 'app/types/unified-alerting-dto'; +import { PromApiFeatures, PromApplication } from 'app/types/unified-alerting-dto'; import { addLabelToQuery } from './add_label_to_query'; import { AnnotationQueryEditor } from './components/AnnotationQueryEditor'; @@ -214,11 +214,16 @@ export class PrometheusDatasource // Use this for tab completion features, wont publish response to other components async metadataRequest(url: string, params = {}, options?: Partial) { + // Build the request URL based on the access mode + let queryUrl = url; + if (this.access === 'proxy') { + queryUrl = `/api/datasources/${this.id}/resources` + queryUrl; + } // If URL includes endpoint that supports POST and GET method, try to use configured method. This might fail as POST is supported only in v2.10+. if (GET_AND_POST_METADATA_ENDPOINTS.some((endpoint) => url.includes(endpoint))) { try { return await lastValueFrom( - this._request(`/api/datasources/${this.id}/resources${url}`, params, { + this._request(queryUrl, params, { method: this.httpMethod, hideFromInspector: true, showErrorAlert: false, @@ -236,7 +241,7 @@ export class PrometheusDatasource } return await lastValueFrom( - this._request(`/api/datasources/${this.id}/resources${url}`, params, { + this._request(queryUrl, params, { method: 'GET', hideFromInspector: true, ...options, diff --git a/public/app/plugins/datasource/prometheus/metric_find_query.test.ts b/public/app/plugins/datasource/prometheus/metric_find_query.test.ts index e29934db580..cf15290e149 100644 --- a/public/app/plugins/datasource/prometheus/metric_find_query.test.ts +++ b/public/app/plugins/datasource/prometheus/metric_find_query.test.ts @@ -76,7 +76,7 @@ describe('PrometheusMetricFindQuery', () => { expect(fetchMock).toHaveBeenCalledTimes(1); expect(fetchMock).toHaveBeenCalledWith({ method: 'GET', - url: `/api/datasources/1/resources/api/v1/labels?start=${raw.from.unix()}&end=${raw.to.unix()}`, + url: `proxied/api/v1/labels?start=${raw.from.unix()}&end=${raw.to.unix()}`, hideFromInspector: true, showErrorAlert: false, headers: {}, @@ -96,7 +96,7 @@ describe('PrometheusMetricFindQuery', () => { expect(fetchMock).toHaveBeenCalledTimes(1); expect(fetchMock).toHaveBeenCalledWith({ method: 'GET', - url: `/api/datasources/1/resources/api/v1/label/resource/values?start=${raw.from.unix()}&end=${raw.to.unix()}`, + url: `proxied/api/v1/label/resource/values?start=${raw.from.unix()}&end=${raw.to.unix()}`, hideFromInspector: true, headers: {}, }); @@ -119,7 +119,7 @@ describe('PrometheusMetricFindQuery', () => { expect(fetchMock).toHaveBeenCalledTimes(1); expect(fetchMock).toHaveBeenCalledWith({ method: 'GET', - url: `/api/datasources/1/resources/api/v1/series?match${encodeURIComponent( + url: `proxied/api/v1/series?match${encodeURIComponent( '[]' )}=metric&start=${raw.from.unix()}&end=${raw.to.unix()}`, hideFromInspector: true, @@ -145,7 +145,7 @@ describe('PrometheusMetricFindQuery', () => { expect(fetchMock).toHaveBeenCalledTimes(1); expect(fetchMock).toHaveBeenCalledWith({ method: 'GET', - url: '/api/datasources/1/resources/api/v1/series?match%5B%5D=metric%7Blabel1%3D%22foo%22%2C%20label2%3D%22bar%22%2C%20label3%3D%22baz%22%7D&start=1524650400&end=1524654000', + url: 'proxied/api/v1/series?match%5B%5D=metric%7Blabel1%3D%22foo%22%2C%20label2%3D%22bar%22%2C%20label3%3D%22baz%22%7D&start=1524650400&end=1524654000', hideFromInspector: true, showErrorAlert: false, headers: {}, @@ -171,7 +171,7 @@ describe('PrometheusMetricFindQuery', () => { expect(fetchMock).toHaveBeenCalledTimes(1); expect(fetchMock).toHaveBeenCalledWith({ method: 'GET', - url: `/api/datasources/1/resources/api/v1/series?match${encodeURIComponent( + url: `proxied/api/v1/series?match${encodeURIComponent( '[]' )}=metric&start=${raw.from.unix()}&end=${raw.to.unix()}`, hideFromInspector: true, @@ -193,7 +193,7 @@ describe('PrometheusMetricFindQuery', () => { expect(fetchMock).toHaveBeenCalledTimes(1); expect(fetchMock).toHaveBeenCalledWith({ method: 'GET', - url: `/api/datasources/1/resources/api/v1/label/__name__/values?start=${raw.from.unix()}&end=${raw.to.unix()}`, + url: `proxied/api/v1/label/__name__/values?start=${raw.from.unix()}&end=${raw.to.unix()}`, hideFromInspector: true, headers: {}, }); @@ -269,7 +269,7 @@ describe('PrometheusMetricFindQuery', () => { expect(fetchMock).toHaveBeenCalledTimes(1); expect(fetchMock).toHaveBeenCalledWith({ method: 'GET', - url: `/api/datasources/1/resources/api/v1/series?match${encodeURIComponent('[]')}=${encodeURIComponent( + url: `proxied/api/v1/series?match${encodeURIComponent('[]')}=${encodeURIComponent( 'up{job="job1"}' )}&start=${raw.from.unix()}&end=${raw.to.unix()}`, hideFromInspector: true,