UpdateDatasource: Add apiVersion if enabled (#90038)

This commit is contained in:
Andres Martinez Gotor 2024-07-08 13:02:48 +02:00 committed by GitHub
parent 06de37e6cd
commit 61b95783d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 84 additions and 0 deletions

View File

@ -647,6 +647,7 @@ export interface DataSourceSettings<T extends DataSourceJsonData = DataSourceJso
readOnly: boolean; readOnly: boolean;
withCredentials: boolean; withCredentials: boolean;
version?: number; version?: number;
apiVersion?: string;
} }
/** /**

View File

@ -0,0 +1,35 @@
import { getBackendSrv } from '@grafana/runtime';
import { DatasourceAPIVersions } from './client';
jest.mock('@grafana/runtime', () => ({
getBackendSrv: jest.fn().mockReturnValue({
get: jest.fn(),
}),
config: {},
}));
describe('DatasourceAPIVersions', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('get', async () => {
const getMock = jest.fn().mockResolvedValue({
groups: [
{ name: 'testdata.datasource.grafana.app', preferredVersion: { version: 'v1' } },
{ name: 'prometheus.datasource.grafana.app', preferredVersion: { version: 'v2' } },
{ name: 'myorg-myplugin.datasource.grafana.app', preferredVersion: { version: 'v3' } },
],
});
getBackendSrv().get = getMock;
const apiVersions = new DatasourceAPIVersions();
expect(await apiVersions.get('testdata')).toBe('v1');
expect(await apiVersions.get('grafana-testdata-datasource')).toBe('v1');
expect(await apiVersions.get('prometheus')).toBe('v2');
expect(await apiVersions.get('graphite')).toBeUndefined();
expect(await apiVersions.get('myorg-myplugin-datasource')).toBe('v3');
expect(getMock).toHaveBeenCalledTimes(1);
expect(getMock).toHaveBeenCalledWith('/apis');
});
});

View File

@ -14,6 +14,7 @@ import {
AnnoKeyOriginPath, AnnoKeyOriginPath,
AnnoKeyOriginHash, AnnoKeyOriginHash,
AnnoKeyOriginName, AnnoKeyOriginName,
K8sAPIGroupList,
} from './types'; } from './types';
export interface GroupVersionResource { export interface GroupVersionResource {
@ -110,3 +111,34 @@ function setOriginAsUI(meta: Partial<ObjectMeta>) {
meta.annotations[AnnoKeyOriginPath] = window.location.pathname; meta.annotations[AnnoKeyOriginPath] = window.location.pathname;
meta.annotations[AnnoKeyOriginHash] = config.buildInfo.versionString; meta.annotations[AnnoKeyOriginHash] = config.buildInfo.versionString;
} }
export class DatasourceAPIVersions {
private apiVersions?: { [pluginID: string]: string };
async get(pluginID: string): Promise<string | undefined> {
if (this.apiVersions) {
return this.apiVersions[pluginID];
}
const apis = await getBackendSrv().get<K8sAPIGroupList>('/apis');
const apiVersions: { [pluginID: string]: string } = {};
apis.groups.forEach((group) => {
if (group.name.includes('datasource.grafana.app')) {
const id = group.name.split('.')[0];
apiVersions[id] = group.preferredVersion.version;
// workaround for plugins that don't append '-datasource' for the group name
// e.g. org-plugin-datasource uses org-plugin.datasource.grafana.app
if (!id.endsWith('-datasource')) {
if (!id.includes('-')) {
// workaroud for Grafana plugins that don't include the org either
// e.g. testdata uses testdata.datasource.grafana.app
apiVersions[`grafana-${id}-datasource`] = group.preferredVersion.version;
} else {
apiVersions[`${id}-datasource`] = group.preferredVersion.version;
}
}
}
});
this.apiVersions = apiVersions;
return apiVersions[pluginID];
}
}

View File

@ -150,3 +150,13 @@ export interface ResourceClient<T = object, K = string> {
update(obj: ResourceForCreate<T, K>): Promise<Resource<T, K>>; update(obj: ResourceForCreate<T, K>): Promise<Resource<T, K>>;
delete(name: string): Promise<MetaStatus>; delete(name: string): Promise<MetaStatus>;
} }
export interface K8sAPIGroup {
name: string;
versions: Array<{ groupVersion: string; version: string }>;
preferredVersion: { groupVersion: string; version: string };
}
export interface K8sAPIGroupList {
kind: 'APIGroupList';
groups: K8sAPIGroup[];
}

View File

@ -18,6 +18,7 @@ import {
import { updateNavIndex } from 'app/core/actions'; import { updateNavIndex } from 'app/core/actions';
import { appEvents, contextSrv } from 'app/core/core'; import { appEvents, contextSrv } from 'app/core/core';
import { getBackendSrv } from 'app/core/services/backend_srv'; import { getBackendSrv } from 'app/core/services/backend_srv';
import { DatasourceAPIVersions } from 'app/features/apiserver/client';
import { ROUTES as CONNECTIONS_ROUTES } from 'app/features/connections/constants'; import { ROUTES as CONNECTIONS_ROUTES } from 'app/features/connections/constants';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { getPluginSettings } from 'app/features/plugins/pluginSettings'; import { getPluginSettings } from 'app/features/plugins/pluginSettings';
@ -264,6 +265,8 @@ export function loadDataSourcePlugins(): ThunkResult<void> {
}; };
} }
const dsApiVersions = new DatasourceAPIVersions();
export function updateDataSource(dataSource: DataSourceSettings) { export function updateDataSource(dataSource: DataSourceSettings) {
return async ( return async (
dispatch: ( dispatch: (
@ -271,6 +274,9 @@ export function updateDataSource(dataSource: DataSourceSettings) {
) => DataSourceSettings ) => DataSourceSettings
) => { ) => {
try { try {
if (config.featureToggles.grafanaAPIServerWithExperimentalAPIs) {
dataSource.apiVersion = await dsApiVersions.get(dataSource.type);
}
await api.updateDataSource(dataSource); await api.updateDataSource(dataSource);
} catch (err) { } catch (err) {
const formattedError = parseHealthCheckError(err); const formattedError = parseHealthCheckError(err);