Dashboard Migrations: V32 no-op migration + V31 LabelsToFields-Merge Migration (#107947)
* Dashboard Migrations: V31 LabelsToFields-Merge Migration * Dashboard Migrations: V32 No-op migration
This commit is contained in:
@@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
MIN_VERSION = 32
|
||||
MIN_VERSION = 30
|
||||
LATEST_VERSION = 41
|
||||
)
|
||||
|
||||
@@ -26,6 +26,8 @@ type DataSourceInfoProvider interface {
|
||||
|
||||
func GetMigrations(dsInfoProvider DataSourceInfoProvider) map[int]SchemaVersionMigrationFunc {
|
||||
return map[int]SchemaVersionMigrationFunc{
|
||||
31: V31,
|
||||
32: V32,
|
||||
33: V33(dsInfoProvider),
|
||||
34: V34,
|
||||
35: V35,
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
package schemaversion
|
||||
|
||||
// V31 adds a merge transformer after any labelsToFields transformer in panel transformations.
|
||||
//
|
||||
// This migration addresses data processing workflow optimization by automatically inserting
|
||||
// a merge transformation after the labelsToFields transformation. When the labelsToFields
|
||||
// transformer converts time series labels to individual fields, it can result in multiple
|
||||
// data frames that need to be consolidated for proper visualization and analysis.
|
||||
//
|
||||
// The migration works by:
|
||||
// 1. Iterating through all panels in the dashboard, including nested panels in collapsed rows
|
||||
// 2. Examining the transformations array within each panel
|
||||
// 3. Identifying transformations with id 'labelsToFields'
|
||||
// 4. Inserting a merge transformation with empty options immediately after each labelsToFields transformation
|
||||
// 5. Preserving the original labelsToFields options (mode, keepLabels, valueLabel, etc.) without modification
|
||||
// 6. Using empty options for merge transformations to enable optimal default consolidation behavior
|
||||
// 7. Preserving the original order and configuration of all other transformations
|
||||
//
|
||||
// The migration handles complex scenarios including:
|
||||
// - Multiple labelsToFields transformations within a single panel
|
||||
// - Panels with mixed transformation types
|
||||
// - Nested panels within collapsed row panels
|
||||
// - Panels with no transformations (left unchanged)
|
||||
// - Panels with transformations but no labelsToFields (left unchanged)
|
||||
//
|
||||
// Example transformation:
|
||||
//
|
||||
// Before migration:
|
||||
//
|
||||
// panel: {
|
||||
// "transformations": [
|
||||
// { "id": "organize", "options": {} },
|
||||
// { "id": "labelsToFields", "options": {} },
|
||||
// { "id": "calculateField", "options": {} },
|
||||
// { "id": "labelsToFields", "options": { "mode": "rows", "keepLabels": ["job", "instance"] } },
|
||||
// ]
|
||||
// }
|
||||
//
|
||||
// After migration:
|
||||
//
|
||||
// panel: {
|
||||
// "transformations": [
|
||||
// { "id": "organize", "options": {} },
|
||||
// { "id": "labelsToFields", "options": {} },
|
||||
// { "id": "merge", "options": {} },
|
||||
// { "id": "calculateField", "options": {} },
|
||||
// { "id": "labelsToFields", "options": { "mode": "rows", "keepLabels": ["job", "instance"] } },
|
||||
// { "id": "merge", "options": {} }
|
||||
// ]
|
||||
// }
|
||||
func V31(dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = int(31)
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Process all panels, including nested ones
|
||||
processPanelsV31(panels)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// processPanelsV31 recursively processes panels, including nested panels within rows
|
||||
func processPanelsV31(panels []interface{}) {
|
||||
for _, panel := range panels {
|
||||
p, ok := panel.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Process nested panels if this is a row panel
|
||||
if p["type"] == "row" {
|
||||
nestedPanels, hasNested := p["panels"].([]interface{})
|
||||
if !hasNested {
|
||||
continue
|
||||
}
|
||||
processPanelsV31(nestedPanels)
|
||||
continue
|
||||
}
|
||||
|
||||
transformations, ok := p["transformations"].([]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if we have any labelsToFields transformations
|
||||
hasLabelsToFields := false
|
||||
for _, transformation := range transformations {
|
||||
t, ok := transformation.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if t["id"] == "labelsToFields" {
|
||||
hasLabelsToFields = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasLabelsToFields {
|
||||
continue
|
||||
}
|
||||
|
||||
// Create new transformations array with merge transformations added
|
||||
newTransformations := []interface{}{}
|
||||
|
||||
for _, transformation := range transformations {
|
||||
t, ok := transformation.(map[string]interface{})
|
||||
if !ok {
|
||||
newTransformations = append(newTransformations, transformation)
|
||||
continue
|
||||
}
|
||||
|
||||
// Add the current transformation (preserving all original options)
|
||||
newTransformations = append(newTransformations, transformation)
|
||||
|
||||
// If this is a labelsToFields transformation, add a merge transformation after it
|
||||
// with empty options to enable optimal default consolidation behavior
|
||||
if t["id"] == "labelsToFields" {
|
||||
mergeTransformation := map[string]interface{}{
|
||||
"id": "merge",
|
||||
"options": map[string]interface{}{},
|
||||
}
|
||||
newTransformations = append(newTransformations, mergeTransformation)
|
||||
}
|
||||
}
|
||||
|
||||
// Update the panel with the new transformations
|
||||
p["transformations"] = newTransformations
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
package schemaversion_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
|
||||
)
|
||||
|
||||
func TestV31(t *testing.T) {
|
||||
tests := []migrationTestCase{
|
||||
{
|
||||
name: "panel with basic labelsToFields transformation gets merge transformation added",
|
||||
input: map[string]interface{}{
|
||||
"title": "V31 LabelsToFields Migration Test Dashboard",
|
||||
"schemaVersion": 30,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with basic labelsToFields",
|
||||
"id": 1,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "labelsToFields",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V31 LabelsToFields Migration Test Dashboard",
|
||||
"schemaVersion": 31,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with basic labelsToFields",
|
||||
"id": 1,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "labelsToFields",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "merge",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "panel with labelsToFields options preserved during migration",
|
||||
input: map[string]interface{}{
|
||||
"title": "V31 LabelsToFields Options Preservation Test Dashboard",
|
||||
"schemaVersion": 30,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with labelsToFields options",
|
||||
"id": 1,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "labelsToFields",
|
||||
"options": map[string]interface{}{
|
||||
"mode": "rows",
|
||||
"keepLabels": []interface{}{"job", "instance"},
|
||||
"valueLabel": "value",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V31 LabelsToFields Options Preservation Test Dashboard",
|
||||
"schemaVersion": 31,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with labelsToFields options",
|
||||
"id": 1,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "labelsToFields",
|
||||
"options": map[string]interface{}{
|
||||
"mode": "rows",
|
||||
"keepLabels": []interface{}{"job", "instance"},
|
||||
"valueLabel": "value",
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "merge",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "panel with multiple labelsToFields transformations",
|
||||
input: map[string]interface{}{
|
||||
"title": "V31 Multiple LabelsToFields Migration Test Dashboard",
|
||||
"schemaVersion": 30,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with multiple labelsToFields",
|
||||
"id": 1,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "organize",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "labelsToFields",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "calculateField",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "labelsToFields",
|
||||
"options": map[string]interface{}{
|
||||
"mode": "rows",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V31 Multiple LabelsToFields Migration Test Dashboard",
|
||||
"schemaVersion": 31,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with multiple labelsToFields",
|
||||
"id": 1,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "organize",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "labelsToFields",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "merge",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "calculateField",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "labelsToFields",
|
||||
"options": map[string]interface{}{
|
||||
"mode": "rows",
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "merge",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "panel with no transformations remains unchanged",
|
||||
input: map[string]interface{}{
|
||||
"title": "V31 No Transformations Test Dashboard",
|
||||
"schemaVersion": 30,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with no transformations",
|
||||
"id": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V31 No Transformations Test Dashboard",
|
||||
"schemaVersion": 31,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with no transformations",
|
||||
"id": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "panel with transformations but no labelsToFields remains unchanged",
|
||||
input: map[string]interface{}{
|
||||
"title": "V31 Other Transformations Test Dashboard",
|
||||
"schemaVersion": 30,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with other transformations",
|
||||
"id": 1,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "organize",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "reduce",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V31 Other Transformations Test Dashboard",
|
||||
"schemaVersion": 31,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with other transformations",
|
||||
"id": 1,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "organize",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "reduce",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nested panels in row with labelsToFields transformation",
|
||||
input: map[string]interface{}{
|
||||
"title": "V31 Nested Panels Test Dashboard",
|
||||
"schemaVersion": 30,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "row",
|
||||
"title": "Row with nested panels",
|
||||
"id": 1,
|
||||
"collapsed": false,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Nested panel with labelsToFields",
|
||||
"id": 2,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "labelsToFields",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Nested panel without labelsToFields",
|
||||
"id": 3,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "organize",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V31 Nested Panels Test Dashboard",
|
||||
"schemaVersion": 31,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "row",
|
||||
"title": "Row with nested panels",
|
||||
"id": 1,
|
||||
"collapsed": false,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Nested panel with labelsToFields",
|
||||
"id": 2,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "labelsToFields",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": "merge",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Nested panel without labelsToFields",
|
||||
"id": 3,
|
||||
"transformations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": "organize",
|
||||
"options": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with no panels",
|
||||
input: map[string]interface{}{
|
||||
"title": "V31 No Panels Test Dashboard",
|
||||
"schemaVersion": 30,
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V31 No Panels Test Dashboard",
|
||||
"schemaVersion": 31,
|
||||
},
|
||||
},
|
||||
}
|
||||
runMigrationTests(t, tests, schemaversion.V31)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package schemaversion
|
||||
|
||||
// V32 is a no-op migration that serves as a placeholder for consistency.
|
||||
//
|
||||
// The migration performs no modifications to the dashboard structure and simply
|
||||
// updates the schema version number.
|
||||
// Example (no changes made):
|
||||
//
|
||||
// Before migration:
|
||||
//
|
||||
// dashboard: {
|
||||
// "title": "My Dashboard",
|
||||
// "schemaVersion": 31,
|
||||
// "panels": [...]
|
||||
// }
|
||||
//
|
||||
// After migration:
|
||||
//
|
||||
// dashboard: {
|
||||
// "title": "My Dashboard",
|
||||
// "schemaVersion": 32,
|
||||
// "panels": [...] // unchanged
|
||||
// }
|
||||
func V32(dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = int(32)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package schemaversion_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
|
||||
)
|
||||
|
||||
func TestV32(t *testing.T) {
|
||||
tests := []migrationTestCase{
|
||||
{
|
||||
name: "v32 no-op migration updates schema version only",
|
||||
input: map[string]interface{}{
|
||||
"title": "V32 No-Op Migration Test Dashboard",
|
||||
"schemaVersion": 31,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel remains unchanged",
|
||||
"id": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V32 No-Op Migration Test Dashboard",
|
||||
"schemaVersion": 32,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "timeseries",
|
||||
"title": "Panel remains unchanged",
|
||||
"id": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
runMigrationTests(t, tests, schemaversion.V32)
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
{
|
||||
"title": "V31 LabelsToFields Merge Migration Test Dashboard",
|
||||
"schemaVersion": 30,
|
||||
"panels": [
|
||||
{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with basic labelsToFields transformation",
|
||||
"id": 1,
|
||||
"transformations": [
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with labelsToFields options preserved",
|
||||
"id": 9,
|
||||
"transformations": [
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {
|
||||
"mode": "rows",
|
||||
"keepLabels": ["job", "instance", "region"],
|
||||
"valueLabel": "value"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with multiple labelsToFields transformations",
|
||||
"id": 2,
|
||||
"transformations": [
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "calculateField",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {
|
||||
"mode": "rows"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with no transformations",
|
||||
"id": 3
|
||||
},
|
||||
{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with other transformations only",
|
||||
"id": 4,
|
||||
"transformations": [
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "reduce",
|
||||
"options": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "row",
|
||||
"title": "Row with nested panels",
|
||||
"id": 5,
|
||||
"collapsed": false,
|
||||
"panels": [
|
||||
{
|
||||
"type": "timeseries",
|
||||
"title": "Nested panel with labelsToFields",
|
||||
"id": 6,
|
||||
"transformations": [
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "timeseries",
|
||||
"title": "Nested panel without labelsToFields",
|
||||
"id": 7,
|
||||
"transformations": [
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with labelsToFields and existing merge",
|
||||
"id": 8,
|
||||
"transformations": [
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "merge",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "reduce",
|
||||
"options": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"title": "V32 No-Op Migration Test Dashboard",
|
||||
"schemaVersion": 31,
|
||||
"panels": [
|
||||
{
|
||||
"type": "timeseries",
|
||||
"title": "Panel with transformations remains unchanged",
|
||||
"id": 1,
|
||||
"transformations": [
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {
|
||||
"mode": "rows",
|
||||
"keepLabels": ["job", "instance"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "merge",
|
||||
"options": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "graph",
|
||||
"title": "Graph panel remains unchanged",
|
||||
"id": 2,
|
||||
"yAxes": [
|
||||
{
|
||||
"show": true,
|
||||
"min": null,
|
||||
"max": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "row",
|
||||
"title": "Row with nested panels",
|
||||
"id": 3,
|
||||
"collapsed": false,
|
||||
"panels": [
|
||||
{
|
||||
"type": "stat",
|
||||
"title": "Nested stat panel",
|
||||
"id": 4,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "bytes"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"name": "environment",
|
||||
"type": "query",
|
||||
"datasource": "prometheus",
|
||||
"options": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"name": "Deployments",
|
||||
"datasource": "grafana",
|
||||
"enable": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
|
||||
}
|
||||
}
|
||||
+290
@@ -0,0 +1,290 @@
|
||||
{
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 1,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Panel with basic labelsToFields transformation",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "merge",
|
||||
"options": {}
|
||||
}
|
||||
],
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 9,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Panel with labelsToFields options preserved",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {
|
||||
"keepLabels": [
|
||||
"job",
|
||||
"instance",
|
||||
"region"
|
||||
],
|
||||
"mode": "rows",
|
||||
"valueLabel": "value"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "merge",
|
||||
"options": {}
|
||||
}
|
||||
],
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 2,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Panel with multiple labelsToFields transformations",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "merge",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "calculateField",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {
|
||||
"mode": "rows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "merge",
|
||||
"options": {}
|
||||
}
|
||||
],
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 3,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Panel with no transformations",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 4,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Panel with other transformations only",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "reduce",
|
||||
"options": {}
|
||||
}
|
||||
],
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 5,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 6,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Nested panel with labelsToFields",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "merge",
|
||||
"options": {}
|
||||
}
|
||||
],
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 7,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Nested panel without labelsToFields",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {}
|
||||
}
|
||||
],
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Row with nested panels",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 8,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Panel with labelsToFields and existing merge",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "merge",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "merge",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "reduce",
|
||||
"options": {}
|
||||
}
|
||||
],
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
"schemaVersion": 41,
|
||||
"title": "V31 LabelsToFields Merge Migration Test Dashboard"
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "grafana"
|
||||
},
|
||||
"enable": true,
|
||||
"name": "Deployments"
|
||||
}
|
||||
]
|
||||
},
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 1,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Panel with transformations remains unchanged",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "labelsToFields",
|
||||
"options": {
|
||||
"keepLabels": [
|
||||
"job",
|
||||
"instance"
|
||||
],
|
||||
"mode": "rows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "merge",
|
||||
"options": {}
|
||||
}
|
||||
],
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 2,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Graph panel remains unchanged",
|
||||
"type": "graph",
|
||||
"yAxes": [
|
||||
{
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 3,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "bytes"
|
||||
}
|
||||
},
|
||||
"id": 4,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Nested stat panel",
|
||||
"type": "stat"
|
||||
}
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Row with nested panels",
|
||||
"type": "row"
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
"schemaVersion": 41,
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"name": "environment",
|
||||
"options": [],
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
]
|
||||
},
|
||||
"title": "V32 No-Op Migration Test Dashboard"
|
||||
}
|
||||
Reference in New Issue
Block a user