Dashboard V0->V1 Migration: Schema migration v36 (#100757)
--------- Co-authored-by: Todd Treece <360020+toddtreece@users.noreply.github.com> Co-authored-by: Haris Rozajac <haris.rozajac12@gmail.com> Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com>
This commit is contained in:
co-authored by
Todd Treece
Haris Rozajac
Stephanie Hingtgen
parent
6767adb4a6
commit
59c2f15433
@@ -1,20 +1,38 @@
|
||||
package schemaversion
|
||||
|
||||
import "strconv"
|
||||
|
||||
type SchemaVersionMigrationFunc func(map[string]interface{}) error
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
MIN_VERSION = 36
|
||||
MIN_VERSION = 35
|
||||
LATEST_VERSION = 41
|
||||
)
|
||||
|
||||
var Migrations = map[int]SchemaVersionMigrationFunc{
|
||||
37: V37,
|
||||
38: V38,
|
||||
39: V39,
|
||||
40: V40,
|
||||
41: V41,
|
||||
type SchemaVersionMigrationFunc func(map[string]interface{}) error
|
||||
|
||||
type DataSourceInfo struct {
|
||||
Default bool
|
||||
UID string
|
||||
Name string
|
||||
Type string
|
||||
ID int64
|
||||
APIVersion string
|
||||
}
|
||||
|
||||
type DataSourceInfoProvider interface {
|
||||
GetDataSourceInfo() []DataSourceInfo
|
||||
}
|
||||
|
||||
func GetMigrations(dsInfoProvider DataSourceInfoProvider) map[int]SchemaVersionMigrationFunc {
|
||||
return map[int]SchemaVersionMigrationFunc{
|
||||
36: V36(dsInfoProvider),
|
||||
37: V37,
|
||||
38: V38,
|
||||
39: V39,
|
||||
40: V40,
|
||||
41: V41,
|
||||
}
|
||||
}
|
||||
|
||||
func GetSchemaVersion(dash map[string]interface{}) int {
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
package schemaversion
|
||||
|
||||
// V36 migrates dashboard datasource references from string names to UIDs.
|
||||
// This migration converts datasource references in annotations, template variables, and panels
|
||||
// from the old format (string name or UID) to the new format (object with uid, type, apiVersion).
|
||||
// This matches the frontend migration in DashboardMigrator.ts.
|
||||
func V36(dsInfo DataSourceInfoProvider) SchemaVersionMigrationFunc {
|
||||
datasources := dsInfo.GetDataSourceInfo()
|
||||
return func(dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = int(36)
|
||||
|
||||
migrateAnnotations(dashboard, datasources)
|
||||
migrateTemplateVariables(dashboard, datasources)
|
||||
migratePanels(dashboard, datasources)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// getDataSourceRef creates a datasource reference object with uid, type and optional apiVersion
|
||||
func getDataSourceRef(ds *DataSourceInfo) map[string]interface{} {
|
||||
if ds == nil {
|
||||
return nil
|
||||
}
|
||||
ref := map[string]interface{}{
|
||||
"uid": ds.UID,
|
||||
"type": ds.Type,
|
||||
}
|
||||
if ds.APIVersion != "" {
|
||||
ref["apiVersion"] = ds.APIVersion
|
||||
}
|
||||
return ref
|
||||
}
|
||||
|
||||
// getDefaultDSInstanceSettings returns the default datasource if one exists
|
||||
func getDefaultDSInstanceSettings(datasources []DataSourceInfo) *DataSourceInfo {
|
||||
for _, ds := range datasources {
|
||||
if ds.Default {
|
||||
return &DataSourceInfo{
|
||||
UID: ds.UID,
|
||||
Type: ds.Type,
|
||||
Name: ds.Name,
|
||||
APIVersion: ds.APIVersion,
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getInstanceSettings looks up a datasource by name or uid reference
|
||||
func getInstanceSettings(nameOrRef interface{}, datasources []DataSourceInfo) *DataSourceInfo {
|
||||
if nameOrRef == nil || nameOrRef == "default" {
|
||||
return getDefaultDSInstanceSettings(datasources)
|
||||
}
|
||||
|
||||
for _, ds := range datasources {
|
||||
if str, ok := nameOrRef.(string); ok {
|
||||
if str == ds.Name || str == ds.UID {
|
||||
return &DataSourceInfo{
|
||||
UID: ds.UID,
|
||||
Type: ds.Type,
|
||||
Name: ds.Name,
|
||||
APIVersion: ds.APIVersion,
|
||||
}
|
||||
}
|
||||
}
|
||||
if ref, ok := nameOrRef.(map[string]interface{}); ok {
|
||||
if uid, hasUID := ref["uid"]; hasUID {
|
||||
if uid == ds.UID {
|
||||
return &DataSourceInfo{
|
||||
UID: ds.UID,
|
||||
Type: ds.Type,
|
||||
Name: ds.Name,
|
||||
APIVersion: ds.APIVersion,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// migrateDatasourceNameToRef converts a datasource name/uid string to a reference object
|
||||
// Matches the frontend migrateDatasourceNameToRef function in DashboardMigrator.ts
|
||||
func migrateDatasourceNameToRef(nameOrRef interface{}, options map[string]bool, datasources []DataSourceInfo) map[string]interface{} {
|
||||
if options["returnDefaultAsNull"] && (nameOrRef == nil || nameOrRef == "default") {
|
||||
return nil
|
||||
}
|
||||
|
||||
if dsRef, ok := nameOrRef.(map[string]interface{}); ok {
|
||||
if _, hasUID := dsRef["uid"]; hasUID {
|
||||
return dsRef
|
||||
}
|
||||
}
|
||||
|
||||
ds := getInstanceSettings(nameOrRef, datasources)
|
||||
if ds != nil {
|
||||
return getDataSourceRef(ds)
|
||||
}
|
||||
|
||||
if dsName, ok := nameOrRef.(string); ok && dsName != "" {
|
||||
return map[string]interface{}{
|
||||
"uid": dsName,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// migrateAnnotations updates datasource references in dashboard annotations
|
||||
func migrateAnnotations(dashboard map[string]interface{}, datasources []DataSourceInfo) {
|
||||
annotations, ok := dashboard["annotations"].(map[string]interface{})
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
list, ok := annotations["list"].([]interface{})
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
for _, query := range list {
|
||||
queryMap, ok := query.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if ds, exists := queryMap["datasource"]; exists {
|
||||
queryMap["datasource"] = migrateDatasourceNameToRef(ds, map[string]bool{"returnDefaultAsNull": false}, datasources)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// migrateTemplateVariables updates datasource references in dashboard variables
|
||||
func migrateTemplateVariables(dashboard map[string]interface{}, datasources []DataSourceInfo) {
|
||||
templating, ok := dashboard["templating"].(map[string]interface{})
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
list, ok := templating["list"].([]interface{})
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
for _, variable := range list {
|
||||
varMap, ok := variable.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if varType, ok := varMap["type"].(string); ok && varType == "query" {
|
||||
if ds, exists := varMap["datasource"]; exists {
|
||||
varMap["datasource"] = migrateDatasourceNameToRef(ds, map[string]bool{"returnDefaultAsNull": false}, datasources)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// migratePanels updates datasource references in dashboard panels
|
||||
func migratePanels(dashboard map[string]interface{}, datasources []DataSourceInfo) {
|
||||
if panels, ok := dashboard["panels"].([]interface{}); ok {
|
||||
for _, panel := range panels {
|
||||
if panelMap, ok := panel.(map[string]interface{}); ok {
|
||||
migratePanelDatasources(panelMap, datasources)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// migratePanelDatasources updates datasource references in a single panel and its targets
|
||||
func migratePanelDatasources(panelMap map[string]interface{}, datasources []DataSourceInfo) {
|
||||
if targets, hasTargets := panelMap["targets"].([]interface{}); hasTargets && len(targets) > 0 {
|
||||
panelDataSourceWasDefault := false
|
||||
|
||||
// Handle panel datasource
|
||||
if ds, exists := panelMap["datasource"]; exists {
|
||||
if ds == nil {
|
||||
defaultDS := getDefaultDSInstanceSettings(datasources)
|
||||
panelMap["datasource"] = getDataSourceRef(defaultDS)
|
||||
panelDataSourceWasDefault = true
|
||||
} else {
|
||||
panelMap["datasource"] = migrateDatasourceNameToRef(ds, map[string]bool{"returnDefaultAsNull": true}, datasources)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle target datasources
|
||||
for _, target := range targets {
|
||||
if targetMap, ok := target.(map[string]interface{}); ok {
|
||||
ds, exists := targetMap["datasource"]
|
||||
|
||||
// Check if target datasource is null or has no uid
|
||||
isNullOrNoUID := !exists || ds == nil
|
||||
if !isNullOrNoUID {
|
||||
if dsMap, ok := ds.(map[string]interface{}); ok {
|
||||
if uid, hasUID := dsMap["uid"]; !hasUID || uid == nil {
|
||||
isNullOrNoUID = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isNullOrNoUID {
|
||||
// If panel doesn't have mixed datasource, use panel's datasource
|
||||
if panelDS, ok := panelMap["datasource"].(map[string]interface{}); ok {
|
||||
if uid, hasUID := panelDS["uid"].(string); hasUID && uid != "-- Mixed --" {
|
||||
targetMap["datasource"] = panelDS
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Migrate existing target datasource
|
||||
targetDS := migrateDatasourceNameToRef(ds, map[string]bool{"returnDefaultAsNull": false}, datasources)
|
||||
targetMap["datasource"] = targetDS
|
||||
}
|
||||
|
||||
// Update panel datasource if it was default and target is not an expression
|
||||
if panelDataSourceWasDefault {
|
||||
if targetDS, ok := targetMap["datasource"].(map[string]interface{}); ok {
|
||||
if uid, ok := targetDS["uid"].(string); ok && uid != "__expr__" {
|
||||
panelMap["datasource"] = targetDS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,571 @@
|
||||
package schemaversion_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/testutil"
|
||||
)
|
||||
|
||||
func TestV36(t *testing.T) {
|
||||
// Pass the mock provider to V36
|
||||
migration := schemaversion.V36(testutil.GetTestProvider())
|
||||
|
||||
tests := []migrationTestCase{
|
||||
{
|
||||
name: "dashboard with no datasources",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "panel with null datasource should get default datasource",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": nil,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "panel with mixed datasources should preserve target datasources",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": "-- Mixed --",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "Elasticsearch",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"datasource": "other-ds",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": "-- Mixed --",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "panel with specific datasource should apply to targets without datasource",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "Default",
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": nil,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with annotations using default datasource",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "Default",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with annotations using non-default datasource by UID",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "other-ds",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with annotations using non-default datasource by name",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "Elasticsearch",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with template variables using default datasource",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"datasource": nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with template variables using non-default datasource by UID",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"datasource": "other-ds",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with template variables using non-default datasource by name",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"datasource": "Elasticsearch",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with panels using default datasource",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "Default",
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "Default",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with panels using non-default datasource by UID",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "other-ds",
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "other-ds",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with panels using non-default datasource by name",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "Elasticsearch",
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "Elasticsearch",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with mixed panel and target datasources",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "Default",
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "Elasticsearch",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"datasource": "other-ds",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "panel with null datasource and expression queries should get default datasource",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": nil,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"refId": "A",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"refId": "B",
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": "__expr__",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"refId": "A",
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds",
|
||||
"apiVersion": "v1",
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"refId": "B",
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": "__expr__",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "panel with null datasource should inherit from query datasource",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 35,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": nil,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": "Elasticsearch",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 36,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "elasticsearch",
|
||||
"uid": "other-ds",
|
||||
"apiVersion": "v2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
runMigrationTests(t, tests, migration)
|
||||
}
|
||||
Reference in New Issue
Block a user