From a404dba29db73c76b33dd0838064981ab62b5102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 4 Mar 2022 08:58:13 +0100 Subject: [PATCH] Datasource: Fixes changing default data source causes inconsistency between panel data source and query data source (#46167) * Datasource: Fixes changing default data source causes inconsistency between panel data source and query data source * Fix unit tests --- .../dashboard/state/DashboardMigrator.test.ts | 34 +++++++++++++++++++ .../dashboard/state/DashboardMigrator.ts | 34 +++++++++++++++++++ .../dashboard/state/DashboardModel.ts | 1 + 3 files changed, 69 insertions(+) diff --git a/public/app/features/dashboard/state/DashboardMigrator.test.ts b/public/app/features/dashboard/state/DashboardMigrator.test.ts index 5dc6eef6bc3..c54ce916e2e 100644 --- a/public/app/features/dashboard/state/DashboardMigrator.test.ts +++ b/public/app/features/dashboard/state/DashboardMigrator.test.ts @@ -17,6 +17,13 @@ const dataSources = { prom: mockDataSource({ name: 'prom', type: 'prometheus', + isDefault: true, + }), + notDefault: mockDataSource({ + name: 'prom-not-default', + uid: 'prom-not-default-uid', + type: 'prometheus', + isDefault: false, }), [MIXED_DATASOURCE_NAME]: mockDataSource({ name: MIXED_DATASOURCE_NAME, @@ -1840,6 +1847,33 @@ describe('DashboardModel', () => { }); }); + describe('when fixing query and panel data source refs out of sync due to default data source change', () => { + let model: DashboardModel; + + beforeEach(() => { + model = new DashboardModel({ + templating: { + list: [], + }, + panels: [ + { + id: 2, + datasource: null, + targets: [ + { + datasource: 'prom-not-default', + }, + ], + }, + ], + }); + }); + + it('should not update panel datasource to that of query level ds', () => { + expect(model.panels[0].datasource?.uid).toEqual('prom-not-default-uid'); + }); + }); + describe('when migrating time series axis visibility', () => { test('preserves x axis visibility', () => { const model = new DashboardModel({ diff --git a/public/app/features/dashboard/state/DashboardMigrator.ts b/public/app/features/dashboard/state/DashboardMigrator.ts index 86380edcf57..3946a9eda08 100644 --- a/public/app/features/dashboard/state/DashboardMigrator.ts +++ b/public/app/features/dashboard/state/DashboardMigrator.ts @@ -67,6 +67,40 @@ export class DashboardMigrator { this.dashboard = dashboardModel; } + /** + * When changing default datasource which is stored as null Grafana get's into a mixed state where queries have + * data source uid & type set that is different from the now new default + */ + syncQueryDataSources() { + const dataSourceSrv = getDataSourceSrv(); + // This only happens in some unit tests that does not set a DataSourceSrv + if (!dataSourceSrv) { + return; + } + + const defaultDS = getDataSourceSrv().getInstanceSettings(null); + // if default ds is mixed then skip this + if (!defaultDS || defaultDS.meta.mixed) { + return; + } + + for (const panel of this.dashboard.panels) { + // only interested in panels that use default (null) data source + if (panel.datasource) { + continue; + } + + for (const target of panel.targets) { + // If query level data source is different from panel + if (target.datasource && target.datasource.uid !== defaultDS?.uid) { + // set panel level data source to data source on the query as this is more likely the correct one + // But impossible to say, and this changes the behavior of of what default means ahead of the big change to default + panel.datasource = target.datasource; + } + } + } + } + updateSchema(old: any) { let i, j, k, n; const oldVersion = this.dashboard.schemaVersion; diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index d088820646d..b810dfe715c 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -1071,6 +1071,7 @@ export class DashboardModel implements TimeModel { private updateSchema(old: any) { const migrator = new DashboardMigrator(this); migrator.updateSchema(old); + migrator.syncQueryDataSources(); } resetOriginalTime() {