mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DataSourceRef: Fixes migrations for mixed data source panels & queries and adds unit tests for data source ref migration (#41245)
* DataSourceRef: Fixes migrations for mixed data source panels & queries and adds unit tests for data source ref migration * Fixing tests and migration logic a bit more * use helper functions * simplify migration logic * Fixing test Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
parent
59c97bb1b2
commit
b2447d3956
@ -50,5 +50,5 @@ export interface DataQuery {
|
|||||||
* For mixed data sources the selected datasource is on the query level.
|
* For mixed data sources the selected datasource is on the query level.
|
||||||
* For non mixed scenarios this is undefined.
|
* For non mixed scenarios this is undefined.
|
||||||
*/
|
*/
|
||||||
datasource?: DataSourceRef;
|
datasource?: DataSourceRef | null;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,12 @@ export function getDataSourceRef(ds: DataSourceInstanceSettings): DataSourceRef
|
|||||||
return { uid: ds.uid, type: ds.type };
|
return { uid: ds.uid, type: ds.type };
|
||||||
}
|
}
|
||||||
|
|
||||||
function isDataSourceRef(ref: DataSourceRef | string | null): ref is DataSourceRef {
|
/**
|
||||||
|
* Returns true if the argument is a DataSourceRef
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export function isDataSourceRef(ref: DataSourceRef | string | null): ref is DataSourceRef {
|
||||||
return typeof ref === 'object' && (typeof ref?.uid === 'string' || typeof ref?.uid === 'undefined');
|
return typeof ref === 'object' && (typeof ref?.uid === 'string' || typeof ref?.uid === 'undefined');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,12 +267,8 @@ describe('given dashboard with repeated panels', () => {
|
|||||||
expect(element.kind).toBe(LibraryElementKind.Panel);
|
expect(element.kind).toBe(LibraryElementKind.Panel);
|
||||||
expect(element.model).toEqual({
|
expect(element.model).toEqual({
|
||||||
id: 17,
|
id: 17,
|
||||||
datasource: '${DS_OTHER2}',
|
datasource: { type: 'other2', uid: '$ds' },
|
||||||
type: 'graph',
|
type: 'graph',
|
||||||
fieldConfig: {
|
|
||||||
defaults: {},
|
|
||||||
overrides: [],
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -7,9 +7,26 @@ import { DataLinkBuiltInVars, MappingType } from '@grafana/data';
|
|||||||
import { VariableHide } from '../../variables/types';
|
import { VariableHide } from '../../variables/types';
|
||||||
import { config } from 'app/core/config';
|
import { config } from 'app/core/config';
|
||||||
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
|
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
|
||||||
|
import { setDataSourceSrv } from '@grafana/runtime';
|
||||||
|
import { mockDataSource, MockDataSourceSrv } from 'app/features/alerting/unified/mocks';
|
||||||
|
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
||||||
|
|
||||||
jest.mock('app/core/services/context_srv', () => ({}));
|
jest.mock('app/core/services/context_srv', () => ({}));
|
||||||
|
|
||||||
|
const dataSources = {
|
||||||
|
prom: mockDataSource({
|
||||||
|
name: 'prom',
|
||||||
|
type: 'prometheus',
|
||||||
|
}),
|
||||||
|
[MIXED_DATASOURCE_NAME]: mockDataSource({
|
||||||
|
name: MIXED_DATASOURCE_NAME,
|
||||||
|
type: 'mixed',
|
||||||
|
uid: MIXED_DATASOURCE_NAME,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
setDataSourceSrv(new MockDataSourceSrv(dataSources));
|
||||||
|
|
||||||
describe('DashboardModel', () => {
|
describe('DashboardModel', () => {
|
||||||
describe('when creating dashboard with old schema', () => {
|
describe('when creating dashboard with old schema', () => {
|
||||||
let model: any;
|
let model: any;
|
||||||
@ -1749,6 +1766,65 @@ describe('DashboardModel', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when migrating datasource to refs', () => {
|
||||||
|
let model: DashboardModel;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
model = new DashboardModel({
|
||||||
|
templating: {
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
type: 'query',
|
||||||
|
name: 'var',
|
||||||
|
options: [{ text: 'A', value: 'A' }],
|
||||||
|
refresh: 0,
|
||||||
|
datasource: 'prom',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
panels: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
datasource: 'prom',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
datasource: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
datasource: MIXED_DATASOURCE_NAME,
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
datasource: 'prom',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update variable datasource props to refs', () => {
|
||||||
|
expect(model.templating.list[0].datasource).toEqual({ type: 'prometheus', uid: 'mock-ds-2' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update panel datasource props to refs for named data source', () => {
|
||||||
|
expect(model.panels[0].datasource).toEqual({ type: 'prometheus', uid: 'mock-ds-2' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update panel datasource props to refs for default data source', () => {
|
||||||
|
expect(model.panels[1].datasource).toEqual(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update panel datasource props to refs for mixed data source', () => {
|
||||||
|
expect(model.panels[2].datasource).toEqual({ type: 'mixed', uid: MIXED_DATASOURCE_NAME });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update target datasource props to refs', () => {
|
||||||
|
expect(model.panels[2].targets[0].datasource).toEqual({ type: 'prometheus', uid: 'mock-ds-2' });
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function createRow(options: any, panelDescriptions: any[]) {
|
function createRow(options: any, panelDescriptions: any[]) {
|
||||||
|
@ -23,6 +23,8 @@ import {
|
|||||||
DataTransformerConfig,
|
DataTransformerConfig,
|
||||||
AnnotationQuery,
|
AnnotationQuery,
|
||||||
DataQuery,
|
DataQuery,
|
||||||
|
getDataSourceRef,
|
||||||
|
isDataSourceRef,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
// Constants
|
// Constants
|
||||||
import {
|
import {
|
||||||
@ -40,7 +42,6 @@ import { config } from 'app/core/config';
|
|||||||
import { plugin as statPanelPlugin } from 'app/plugins/panel/stat/module';
|
import { plugin as statPanelPlugin } from 'app/plugins/panel/stat/module';
|
||||||
import { plugin as gaugePanelPlugin } from 'app/plugins/panel/gauge/module';
|
import { plugin as gaugePanelPlugin } from 'app/plugins/panel/gauge/module';
|
||||||
import { getStandardFieldConfigs, getStandardOptionEditors } from '@grafana/ui';
|
import { getStandardFieldConfigs, getStandardOptionEditors } from '@grafana/ui';
|
||||||
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
|
||||||
import { getDataSourceSrv } from '@grafana/runtime';
|
import { getDataSourceSrv } from '@grafana/runtime';
|
||||||
import { labelsToFieldsTransformer } from '../../../../../packages/grafana-data/src/transformations/transformers/labelsToFields';
|
import { labelsToFieldsTransformer } from '../../../../../packages/grafana-data/src/transformations/transformers/labelsToFields';
|
||||||
import { mergeTransformer } from '../../../../../packages/grafana-data/src/transformations/transformers/merge';
|
import { mergeTransformer } from '../../../../../packages/grafana-data/src/transformations/transformers/merge';
|
||||||
@ -704,34 +705,21 @@ export class DashboardMigrator {
|
|||||||
if (variable.type !== 'query') {
|
if (variable.type !== 'query') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let name = (variable as any).datasource as string;
|
variable.datasource = migrateDatasourceNameToRef(variable.datasource);
|
||||||
if (name) {
|
|
||||||
variable.datasource = migrateDatasourceNameToRef(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutate panel models
|
// Mutate panel models
|
||||||
for (const panel of this.dashboard.panels) {
|
for (const panel of this.dashboard.panels) {
|
||||||
let name = (panel as any).datasource as string;
|
panel.datasource = migrateDatasourceNameToRef(panel.datasource);
|
||||||
if (!name) {
|
|
||||||
panel.datasource = null; // use default
|
if (!panel.targets) {
|
||||||
} else if (name === MIXED_DATASOURCE_NAME) {
|
continue;
|
||||||
panel.datasource = { type: MIXED_DATASOURCE_NAME };
|
|
||||||
for (const target of panel.targets) {
|
|
||||||
name = (target as any).datasource as string;
|
|
||||||
panel.datasource = migrateDatasourceNameToRef(name);
|
|
||||||
}
|
|
||||||
continue; // do not cleanup targets
|
|
||||||
} else {
|
|
||||||
panel.datasource = migrateDatasourceNameToRef(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup query datasource references
|
|
||||||
if (!panel.targets) {
|
|
||||||
panel.targets = [];
|
|
||||||
} else {
|
|
||||||
for (const target of panel.targets) {
|
for (const target of panel.targets) {
|
||||||
delete target.datasource;
|
const targetRef = migrateDatasourceNameToRef(target.datasource);
|
||||||
|
if (targetRef != null) {
|
||||||
|
target.datasource = targetRef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1051,17 +1039,21 @@ function migrateSinglestat(panel: PanelModel) {
|
|||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function migrateDatasourceNameToRef(name: string): DataSourceRef | null {
|
export function migrateDatasourceNameToRef(nameOrRef?: string | DataSourceRef | null): DataSourceRef | null {
|
||||||
if (!name || name === 'default') {
|
if (nameOrRef == null || nameOrRef === 'default') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ds = getDataSourceSrv().getInstanceSettings(name);
|
if (isDataSourceRef(nameOrRef)) {
|
||||||
if (!ds) {
|
return nameOrRef;
|
||||||
return { uid: name }; // not found
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { type: ds.meta.id, uid: ds.uid };
|
const ds = getDataSourceSrv().getInstanceSettings(nameOrRef);
|
||||||
|
if (!ds) {
|
||||||
|
return { uid: nameOrRef as string }; // not found
|
||||||
|
}
|
||||||
|
|
||||||
|
return getDataSourceRef(ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mutates transformations appending a new transformer after the existing one
|
// mutates transformations appending a new transformer after the existing one
|
||||||
@ -1085,7 +1077,7 @@ function upgradeValueMappingsForPanel(panel: PanelModel) {
|
|||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldConfig.defaults) {
|
if (fieldConfig.defaults && fieldConfig.defaults.mappings) {
|
||||||
fieldConfig.defaults.mappings = upgradeValueMappings(
|
fieldConfig.defaults.mappings = upgradeValueMappings(
|
||||||
fieldConfig.defaults.mappings,
|
fieldConfig.defaults.mappings,
|
||||||
fieldConfig.defaults.thresholds
|
fieldConfig.defaults.thresholds
|
||||||
|
Loading…
Reference in New Issue
Block a user