Public Dashboards Bug: Permissions error on panel when using mixed datasource with Enterprise (#51930)
Fixes pubdash bug for enterprise when pubdash panel uses a mixed datasource
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
|||||||
PUBLIC_DATASOURCE,
|
PUBLIC_DATASOURCE,
|
||||||
PublicDashboardDataSource,
|
PublicDashboardDataSource,
|
||||||
} from '../../../../public/app/features/dashboard/services/PublicDashboardDataSource';
|
} from '../../../../public/app/features/dashboard/services/PublicDashboardDataSource';
|
||||||
|
import { MIXED_DATASOURCE_NAME } from '../../../../public/app/plugins/datasource/mixed/MixedDataSource';
|
||||||
|
|
||||||
import { DataSourceWithBackend } from './DataSourceWithBackend';
|
import { DataSourceWithBackend } from './DataSourceWithBackend';
|
||||||
|
|
||||||
@@ -75,4 +76,26 @@ describe('PublicDashboardDatasource', () => {
|
|||||||
let ds = new PublicDashboardDataSource(datasource);
|
let ds = new PublicDashboardDataSource(datasource);
|
||||||
expect(ds.uid).toBe('abc123');
|
expect(ds.uid).toBe('abc123');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('isMixedDatasource returns true when datasource is mixed', () => {
|
||||||
|
const datasource = new DataSourceWithBackend({ id: 1, uid: MIXED_DATASOURCE_NAME } as DataSourceInstanceSettings);
|
||||||
|
let ds = new PublicDashboardDataSource(datasource);
|
||||||
|
expect(ds.meta.mixed).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('isMixedDatasource returns false when datasource is not mixed', () => {
|
||||||
|
const datasource = new DataSourceWithBackend({ id: 1, uid: 'abc123' } as DataSourceInstanceSettings);
|
||||||
|
let ds = new PublicDashboardDataSource(datasource);
|
||||||
|
expect(ds.meta.mixed).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('isMixedDatasource returns false when datasource is a string', () => {
|
||||||
|
let ds = new PublicDashboardDataSource('abc123');
|
||||||
|
expect(ds.meta.mixed).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('isMixedDatasource returns false when datasource is null', () => {
|
||||||
|
let ds = new PublicDashboardDataSource(null);
|
||||||
|
expect(ds.meta.mixed).toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,9 +11,22 @@ func GetUniqueDashboardDatasourceUids(dashboard *simplejson.Json) []string {
|
|||||||
for _, panelObj := range dashboard.Get("panels").MustArray() {
|
for _, panelObj := range dashboard.Get("panels").MustArray() {
|
||||||
panel := simplejson.NewFromAny(panelObj)
|
panel := simplejson.NewFromAny(panelObj)
|
||||||
uid := panel.Get("datasource").Get("uid").MustString()
|
uid := panel.Get("datasource").Get("uid").MustString()
|
||||||
if _, ok := exists[uid]; !ok {
|
|
||||||
datasourceUids = append(datasourceUids, uid)
|
// if uid is for a mixed datasource, get the datasource uids from the targets
|
||||||
exists[uid] = true
|
if uid == "-- Mixed --" {
|
||||||
|
for _, target := range panel.Get("targets").MustArray() {
|
||||||
|
target := simplejson.NewFromAny(target)
|
||||||
|
datasourceUid := target.Get("datasource").Get("uid").MustString()
|
||||||
|
if _, ok := exists[datasourceUid]; !ok {
|
||||||
|
datasourceUids = append(datasourceUids, datasourceUid)
|
||||||
|
exists[datasourceUid] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, ok := exists[uid]; !ok {
|
||||||
|
datasourceUids = append(datasourceUids, uid)
|
||||||
|
exists[uid] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,79 @@ const (
|
|||||||
"schemaVersion": 35
|
"schemaVersion": 35
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
dashboardWithMixedDatasource = `
|
||||||
|
{
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "-- Mixed --"
|
||||||
|
},
|
||||||
|
"id": 1,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "abc123"
|
||||||
|
},
|
||||||
|
"exemplar": true,
|
||||||
|
"expr": "go_goroutines{job=\"$job\"}",
|
||||||
|
"interval": "",
|
||||||
|
"legendFormat": "",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Panel Title",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "_yxMP8Ynk"
|
||||||
|
},
|
||||||
|
"id": 2,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "_yxMP8Ynk"
|
||||||
|
},
|
||||||
|
"exemplar": true,
|
||||||
|
"expr": "go_goroutines{job=\"$job\"}",
|
||||||
|
"interval": "",
|
||||||
|
"legendFormat": "",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Panel Title",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "_yxMP8Ynk"
|
||||||
|
},
|
||||||
|
"id": 3,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "_yxMP8Ynk"
|
||||||
|
},
|
||||||
|
"exemplar": true,
|
||||||
|
"expr": "go_goroutines{job=\"$job\"}",
|
||||||
|
"interval": "",
|
||||||
|
"legendFormat": "",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Panel Title",
|
||||||
|
"type": "timeseries"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"schemaVersion": 35
|
||||||
|
}`
|
||||||
|
|
||||||
dashboardWithDuplicateDatasources = `
|
dashboardWithDuplicateDatasources = `
|
||||||
{
|
{
|
||||||
"panels": [
|
"panels": [
|
||||||
@@ -163,6 +236,16 @@ func TestGetUniqueDashboardDatasourceUids(t *testing.T) {
|
|||||||
require.Equal(t, "_yxMP8Ynk", uids[1])
|
require.Equal(t, "_yxMP8Ynk", uids[1])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("can get unique datasource ids from dashboard with a mixed datasource", func(t *testing.T) {
|
||||||
|
json, err := simplejson.NewJson([]byte(dashboardWithMixedDatasource))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
uids := GetUniqueDashboardDatasourceUids(json)
|
||||||
|
require.Len(t, uids, 2)
|
||||||
|
require.Equal(t, "abc123", uids[0])
|
||||||
|
require.Equal(t, "_yxMP8Ynk", uids[1])
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("can get no datasource uids from empty dashboard", func(t *testing.T) {
|
t.Run("can get no datasource uids from empty dashboard", func(t *testing.T) {
|
||||||
json, err := simplejson.NewJson([]byte(`{"panels": {}}`))
|
json, err := simplejson.NewJson([]byte(`{"panels": {}}`))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@@ -5,20 +5,27 @@ import {
|
|||||||
DataQueryRequest,
|
DataQueryRequest,
|
||||||
DataQueryResponse,
|
DataQueryResponse,
|
||||||
DataSourceApi,
|
DataSourceApi,
|
||||||
|
DataSourcePluginMeta,
|
||||||
DataSourceRef,
|
DataSourceRef,
|
||||||
PluginMeta,
|
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { BackendDataSourceResponse, getBackendSrv, toDataQueryResponse } from '@grafana/runtime';
|
import { BackendDataSourceResponse, getBackendSrv, toDataQueryResponse } from '@grafana/runtime';
|
||||||
|
|
||||||
|
import { MIXED_DATASOURCE_NAME } from '../../../plugins/datasource/mixed/MixedDataSource';
|
||||||
|
|
||||||
export const PUBLIC_DATASOURCE = '-- Public --';
|
export const PUBLIC_DATASOURCE = '-- Public --';
|
||||||
|
|
||||||
export class PublicDashboardDataSource extends DataSourceApi<any> {
|
export class PublicDashboardDataSource extends DataSourceApi<any> {
|
||||||
constructor(datasource: DataSourceRef | string | DataSourceApi | null) {
|
constructor(datasource: DataSourceRef | string | DataSourceApi | null) {
|
||||||
|
let meta = {} as DataSourcePluginMeta;
|
||||||
|
if (PublicDashboardDataSource.isMixedDatasource(datasource)) {
|
||||||
|
meta.mixed = true;
|
||||||
|
}
|
||||||
|
|
||||||
super({
|
super({
|
||||||
name: 'public-ds',
|
name: 'public-ds',
|
||||||
id: 0,
|
id: 0,
|
||||||
type: 'public-ds',
|
type: 'public-ds',
|
||||||
meta: {} as PluginMeta,
|
meta,
|
||||||
uid: PublicDashboardDataSource.resolveUid(datasource),
|
uid: PublicDashboardDataSource.resolveUid(datasource),
|
||||||
jsonData: {},
|
jsonData: {},
|
||||||
access: 'proxy',
|
access: 'proxy',
|
||||||
@@ -38,6 +45,14 @@ export class PublicDashboardDataSource extends DataSourceApi<any> {
|
|||||||
return datasource?.uid ?? PUBLIC_DATASOURCE;
|
return datasource?.uid ?? PUBLIC_DATASOURCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static isMixedDatasource(datasource: DataSourceRef | string | DataSourceApi | null): boolean {
|
||||||
|
if (typeof datasource === 'string' || datasource === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return datasource?.uid === MIXED_DATASOURCE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ideally final -- any other implementation may not work as expected
|
* Ideally final -- any other implementation may not work as expected
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user