Prometheus: Throw error on direct access (#50162)

* Disable direct access

* Hide access select if Server mode is already selected

* Update docs

* Add more tests

Co-authored-by: Beto Muniz <contato@betomuniz.com>
This commit is contained in:
Andrej Ocenas 2022-08-17 14:37:29 +02:00 committed by GitHub
parent b5cb7738da
commit f30795b088
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 84 additions and 15 deletions

View File

@ -7857,7 +7857,10 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "102"],
[0, 0, 0, "Unexpected any. Specify a different type.", "103"],
[0, 0, 0, "Unexpected any. Specify a different type.", "104"],
[0, 0, 0, "Unexpected any. Specify a different type.", "105"]
[0, 0, 0, "Unexpected any. Specify a different type.", "105"],
[0, 0, 0, "Unexpected any. Specify a different type.", "106"],
[0, 0, 0, "Unexpected any. Specify a different type.", "107"],
[0, 0, 0, "Unexpected any. Specify a different type.", "108"]
],
"public/app/plugins/datasource/prometheus/datasource.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
@ -7882,9 +7885,9 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "19"],
[0, 0, 0, "Unexpected any. Specify a different type.", "20"],
[0, 0, 0, "Unexpected any. Specify a different type.", "21"],
[0, 0, 0, "Unexpected any. Specify a different type.", "22"],
[0, 0, 0, "Do not use any type assertions.", "22"],
[0, 0, 0, "Unexpected any. Specify a different type.", "23"],
[0, 0, 0, "Do not use any type assertions.", "24"],
[0, 0, 0, "Unexpected any. Specify a different type.", "24"],
[0, 0, 0, "Unexpected any. Specify a different type.", "25"],
[0, 0, 0, "Unexpected any. Specify a different type.", "26"],
[0, 0, 0, "Unexpected any. Specify a different type.", "27"],
@ -7893,9 +7896,7 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "30"],
[0, 0, 0, "Unexpected any. Specify a different type.", "31"],
[0, 0, 0, "Unexpected any. Specify a different type.", "32"],
[0, 0, 0, "Unexpected any. Specify a different type.", "33"],
[0, 0, 0, "Unexpected any. Specify a different type.", "34"],
[0, 0, 0, "Unexpected any. Specify a different type.", "35"]
[0, 0, 0, "Unexpected any. Specify a different type.", "33"]
],
"public/app/plugins/datasource/prometheus/language_provider.test.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],

View File

@ -26,7 +26,7 @@ To access Prometheus settings, hover your mouse over the **Configuration** (gear
| `Name` | The data source name. This is how you refer to the data source in panels and queries. |
| `Default` | Default data source that is pre-selected for new panels. |
| `Url` | The URL of your Prometheus server, for example, `http://prometheus.example.org:9090`. |
| `Access` | Server (default) = URL needs to be accessible from the Grafana backend/server, Browser = URL needs to be accessible from the browser. **Note**: Browser (direct) access is deprecated and will be removed in a future release. |
| `Access` | Only Server access mode is functional. If Server mode is already selected this option is hidden. Otherwise change to Server mode to prevent errors. |
| `Basic Auth` | Enable basic authentication to the Prometheus data source. |
| `User` | User name for basic authentication. |
| `Password` | Password for basic authentication. |

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useRef } from 'react';
import { SIGV4ConnectionConfig } from '@grafana/aws-sdk';
import { DataSourcePluginOptionsEditorProps, DataSourceSettings } from '@grafana/data';
@ -16,6 +16,8 @@ export type Props = DataSourcePluginOptionsEditorProps<PromOptions>;
export const ConfigEditor = (props: Props) => {
const { options, onOptionsChange } = props;
const alertmanagers = getAllAlertmanagerDataSources();
// use ref so this is evaluated only first time it renders and the select does not disappear suddenly.
const showAccessOptions = useRef(props.options.access === 'direct');
const azureAuthSettings = {
azureAuthSupported: config.azureAuthEnabled,
@ -28,15 +30,15 @@ export const ConfigEditor = (props: Props) => {
return (
<>
{options.access === 'direct' && (
<Alert title="Deprecation Notice" severity="warning">
Browser access mode in the Prometheus datasource is deprecated and will be removed in a future release.
<Alert title="Error" severity="error">
Browser access mode in the Prometheus datasource is no longer available. Switch to server access mode.
</Alert>
)}
<DataSourceHttpSettings
defaultUrl="http://localhost:9090"
dataSourceConfig={options}
showAccessOptions={true}
showAccessOptions={showAccessOptions.current}
onChange={onOptionsChange}
sigV4AuthToggleEnabled={config.sigV4AuthEnabled}
azureAuthSettings={azureAuthSettings}

View File

@ -1,5 +1,5 @@
import { cloneDeep } from 'lodash';
import { of, throwError } from 'rxjs';
import { lastValueFrom, of, throwError } from 'rxjs';
import {
CoreApp,
@ -100,6 +100,57 @@ describe('PrometheusDatasource', () => {
expect(response[0].state).toBe(LoadingState.Done);
});
});
it('throws if using direct access', async () => {
const instanceSettings = {
url: 'proxied',
directUrl: 'direct',
user: 'test',
password: 'mupp',
access: 'direct',
jsonData: {
customQueryParameters: '',
} as any,
} as unknown as DataSourceInstanceSettings<PromOptions>;
const range = { from: time({ seconds: 63 }), to: time({ seconds: 183 }) };
const directDs = new PrometheusDatasource(instanceSettings, templateSrvStub as any, timeSrvStub as any);
await expect(
lastValueFrom(directDs.query(createDataRequest([{}, {}], { app: CoreApp.Dashboard })))
).rejects.toMatchObject({ message: expect.stringMatching('Browser access') });
// Cannot test because some other tests need "./metric_find_query" to be mocked and that prevents this to be
// tested. Checked manually that this ends up with throwing
// await expect(directDs.metricFindQuery('label_names(foo)')).rejects.toBeDefined();
jest.spyOn(console, 'error').mockImplementation(() => {});
await expect(directDs.testDatasource()).resolves.toMatchObject({
message: expect.stringMatching('Browser access'),
status: 'error',
});
await expect(
directDs.annotationQuery({
range: { ...range, raw: range },
rangeRaw: range,
// Should be DataModel but cannot import that here from the main app. Needs to be moved to package first.
dashboard: {},
annotation: {
expr: 'metric',
name: 'test',
enable: true,
iconColor: '',
},
})
).rejects.toMatchObject({
message: expect.stringMatching('Browser access'),
});
await expect(directDs.getTagKeys()).rejects.toMatchObject({
message: expect.stringMatching('Browser access'),
});
await expect(directDs.getTagValues()).rejects.toMatchObject({
message: expect.stringMatching('Browser access'),
});
});
});
describe('Datasource metadata requests', () => {
@ -683,7 +734,7 @@ const HOUR = 60 * MINUTE;
const time = ({ hours = 0, seconds = 0, minutes = 0 }) => dateTime(hours * HOUR + minutes * MINUTE + seconds * SECOND);
describe('PrometheusDatasource', () => {
describe('PrometheusDatasource2', () => {
const instanceSettings = {
url: 'proxied',
directUrl: 'direct',

View File

@ -22,6 +22,7 @@ import {
TimeRange,
DataFrame,
dateTime,
AnnotationQueryRequest,
QueryFixAction,
} from '@grafana/data';
import {
@ -161,6 +162,13 @@ export class PrometheusDatasource
data: Record<string, string> | null,
overrides: Partial<BackendSrvRequest> = {}
): Observable<FetchResponse<T>> {
if (this.access === 'direct') {
const error = new Error(
'Browser access mode in the Prometheus datasource is no longer available. Switch to server access mode.'
);
return throwError(() => error);
}
data = data || {};
for (const [key, value] of this.customQueryParameters) {
if (data[key] == null) {
@ -698,7 +706,14 @@ export class PrometheusDatasource
};
}
async annotationQuery(options: any): Promise<AnnotationEvent[]> {
async annotationQuery(options: AnnotationQueryRequest<PromQuery>): Promise<AnnotationEvent[]> {
if (this.access === 'direct') {
const error = new Error(
'Browser access mode in the Prometheus datasource is no longer available. Switch to server access mode.'
);
return Promise.reject(error);
}
const annotation = options.annotation;
const { expr = '' } = annotation;
@ -738,7 +753,7 @@ export class PrometheusDatasource
);
}
processAnnotationResponse = (options: any, data: BackendDataSourceResponse) => {
processAnnotationResponse = (options: AnnotationQueryRequest<PromQuery>, data: BackendDataSourceResponse) => {
const frames: DataFrame[] = toDataQueryResponse({ data: data }).data;
if (!frames || !frames.length) {
return [];