Schema: convert dashboards from v1beta1 to v2beta1 (#109037)

- Implement full conversion pipeline from v1beta1 → v2beta1
- Ensure frontend–backend parity for all dashboard serialization paths
- Add automatic data loss detection for conversions (panels, queries, annotations, links, variables)
- Extract atomic conversion functions for v0 → v1beta1 → v2alpha1 → v2beta1
- Introduce conversion metrics and detailed logging for loss tracking
- Normalize datasource resolution, defaults, and annotation processing
- Improve panel layout serialization and y-coordinate normalization
- Fix inconsistencies in nested panels and collapsed row behavior
- Refine variable handling:
  - Filter refId from variable query specs
  - Default variable refresh to 'never' (matches frontend)
  - Fix constant and interval variable handling for missing queries
- Unify schema defaults (enable, hide, iconColor, editable, liveNow)
- Fix pluginId usage (UID vs type) and datasource references
- Fix metrics.go bug swallowing errors (return nil → return err)
- Add tests for version-specific conversion error handling
- Add data loss detection tests using source/target version comparison
- Clean up lint issues, legacy code, and redundant files
- Update OpenAPI snapshots and migrated dashboards
- Improve backend migrator to reuse datasource provider and match frontend logic

Co-authored-by: Haris Rozajac <haris.rozajac12@gmail.com>
Co-authored-by: Oscar Kilhed <oscar.kilhed@grafana.com>
Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com>
This commit is contained in:
Ivan Ortega Alba
2025-11-12 11:43:46 +01:00
committed by GitHub
co-authored by Haris Rozajac Oscar Kilhed Stephanie Hingtgen
parent 09942c08db
commit e463781077
273 changed files with 75003 additions and 588 deletions
@@ -40,13 +40,7 @@
]
},
"annotations": {
"list": [
{
"name": "Annotations & Alerts",
"datasource": "grafana",
"enable": true
}
]
"list": []
},
"time": {
"from": "now-6h",
@@ -43,7 +43,10 @@
"list": [
{
"name": "Annotations & Alerts",
"datasource": "grafana",
"datasource": {
"type": "grafana",
"uid": "grafana"
},
"enable": true
}
]
@@ -110,7 +110,9 @@
"enable": true,
"iconColor": "purple",
"datasource": {
"uid": "prometheus"
"uid": "default-ds-uid",
"type": "prometheus",
"apiVersion": "v1"
}
}
]
@@ -34,6 +34,8 @@
{
"name": "Unknown Datasource Annotation - Tests unknown datasource preserved as UID",
"datasource": {
"type": "prometheus",
"apiVersion": "v1",
"uid": "unknown-datasource-name"
}
}
@@ -119,7 +121,9 @@
{
"refId": "B",
"datasource": {
"uid": "existing-target-uid"
"uid": "existing-target-uid",
"type": "elasticsearch",
"apiVersion": "v2"
}
}
]
@@ -137,7 +141,8 @@
"refId": "A",
"datasource": {
"uid": "existing-target-uid",
"type": "elasticsearch"
"type": "elasticsearch",
"apiVersion": "v2"
}
}
]
@@ -167,7 +172,9 @@
{
"refId": "A",
"datasource": {
"uid": "existing-target-uid"
"uid": "existing-target-uid",
"type": "elasticsearch",
"apiVersion": "v2"
}
},
{
@@ -188,7 +195,9 @@
{
"refId": "A",
"datasource": {
"uid": "existing-target-uid"
"uid": "existing-target-uid",
"type": "elasticsearch",
"apiVersion": "v2"
}
}
]
@@ -257,7 +266,9 @@
{
"refId": "A",
"datasource": {
"uid": "existing-target-uid"
"uid": "existing-target-uid",
"type": "elasticsearch",
"apiVersion": "v2"
}
}
]
@@ -0,0 +1,31 @@
{
"title": "v42 Migration Test - Harky Must",
"schemaVersion": 41,
"panels": [
{
"id": 1,
"title": "Panel with hideFrom.viz = true",
"type": "timeseries",
"fieldConfig": {
"defaults": {},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "Field1"
},
"properties": [
{
"id": "custom.hideFrom",
"value": {
"viz": true
}
}
]
}
]
}
}
]
}
@@ -49,14 +49,22 @@
]
},
{
"__systemRef": "hideSeriesFrom",
"matcher": {
"id": "__systemRef",
"options": "hiddenSeries"
"id": "byNames",
"options": {
"mode": "exclude",
"names": ["foo"],
"prefix": "All except:",
"readOnly": true
}
},
"properties": [
{
"id": "custom.hideFrom",
"value": {
"legend": false,
"tooltip": false,
"viz": true
}
}
@@ -103,6 +111,10 @@
"defaults": {},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "Time"
},
"properties": [
{
"id": "unit",
@@ -123,13 +135,18 @@
"defaults": {},
"overrides": [
{
"matcher": {
"id": "byValue",
"options": {
"op": "gte",
"reducer": "allIsZero",
"value": 0
}
},
"properties": [
{
"id": "custom.hideFrom",
"value": {
"viz": false,
"tooltip": false
}
"id": "unit",
"value": "short"
}
]
}
@@ -144,12 +161,17 @@
"defaults": {},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "{__name__=\"ALERTS\", alertname=\"k6CloudServiceErrorsLogged\"}"
},
"properties": [
{
"id": "custom.hideFrom",
"value": {
"viz": true,
"tooltip": false
"legend": false,
"tooltip": false,
"viz": true
}
}
]
@@ -12,14 +12,20 @@
"annotations": [
{
"name": "deployment",
"datasource": "prometheus",
"datasource": {
"uid": "default-ds-uid",
"type": "prometheus"
},
"enable": true,
"iconColor": "red",
"query": "ALERTS{alertname=\"DeploymentStarted\"}"
},
{
"name": "alerts",
"datasource": "loki",
"datasource": {
"uid": "loki-uid",
"type": "loki"
},
"enable": false,
"iconColor": "yellow",
"query": "{job=\"alertmanager\"}"
@@ -32,12 +38,14 @@
{
"name": "environment",
"type": "filter",
"allFormat": null
"allFormat": null,
"query": "label_values(up, instance)"
},
{
"name": "service",
"datasource": "prometheus",
"allFormat": "glob"
"allFormat": "glob",
"query": "label_values(up, instance)"
},
{
"name": "region",