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:
co-authored by
Haris Rozajac
Oscar Kilhed
Stephanie Hingtgen
parent
09942c08db
commit
e463781077
@@ -158,6 +158,8 @@ FieldConfigSource: {
|
||||
defaults: FieldConfig
|
||||
// Overrides are the options applied to specific fields overriding the defaults.
|
||||
overrides: [...{
|
||||
// Describes config override rules created when interacting with Grafana.
|
||||
"__systemRef"?: string
|
||||
matcher: MatcherConfig
|
||||
properties: [...DynamicConfigValue]
|
||||
}]
|
||||
@@ -251,7 +253,8 @@ MatcherConfig: {
|
||||
}
|
||||
|
||||
Threshold: {
|
||||
value: number
|
||||
// Value null means -Infinity
|
||||
value: number | null
|
||||
color: string
|
||||
}
|
||||
|
||||
|
||||
@@ -551,8 +551,9 @@ const (
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardThreshold struct {
|
||||
Value float64 `json:"value"`
|
||||
Color string `json:"color"`
|
||||
// Value null means -Infinity
|
||||
Value *float64 `json:"value"`
|
||||
Color string `json:"color"`
|
||||
}
|
||||
|
||||
// NewDashboardThreshold creates a new DashboardThreshold object.
|
||||
@@ -1865,6 +1866,8 @@ func NewDashboardSpec() *DashboardSpec {
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardV2alpha1FieldConfigSourceOverrides struct {
|
||||
// Describes config override rules created when interacting with Grafana.
|
||||
SystemRef *string `json:"__systemRef,omitempty"`
|
||||
Matcher DashboardMatcherConfig `json:"matcher"`
|
||||
Properties []DashboardDynamicConfigValue `json:"properties"`
|
||||
}
|
||||
|
||||
@@ -4430,9 +4430,9 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardThreshold(ref common.ReferenceC
|
||||
Properties: map[string]spec.Schema{
|
||||
"value": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: 0,
|
||||
Type: []string{"number"},
|
||||
Format: "double",
|
||||
Description: "Value null means -Infinity",
|
||||
Type: []string{"number"},
|
||||
Format: "double",
|
||||
},
|
||||
},
|
||||
"color": {
|
||||
@@ -4677,6 +4677,13 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1FieldConfigSourceOverri
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"__systemRef": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Describes config override rules created when interacting with Grafana.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"matcher": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
|
||||
+1
@@ -67,6 +67,7 @@ API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/ap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardStringOrArrayOfString,String
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardStringOrFloat64,Float64
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardStringOrFloat64,String
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardV2alpha1FieldConfigSourceOverrides,SystemRef
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,RangeMap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,RegexMap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,SpecialValueMap
|
||||
|
||||
@@ -160,6 +160,8 @@ FieldConfigSource: {
|
||||
defaults: FieldConfig
|
||||
// Overrides are the options applied to specific fields overriding the defaults.
|
||||
overrides: [...{
|
||||
// Describes config override rules created when interacting with Grafana.
|
||||
"__systemRef"?: string
|
||||
matcher: MatcherConfig
|
||||
properties: [...DynamicConfigValue]
|
||||
}]
|
||||
@@ -253,7 +255,8 @@ MatcherConfig: {
|
||||
}
|
||||
|
||||
Threshold: {
|
||||
value: number
|
||||
// Value null means -Infinity
|
||||
value: number | null
|
||||
color: string
|
||||
}
|
||||
|
||||
@@ -479,7 +482,7 @@ DataQueryKind: {
|
||||
|
||||
PanelQuerySpec: {
|
||||
query: DataQueryKind
|
||||
refId: string
|
||||
refId: string | *"A"
|
||||
hidden: bool
|
||||
}
|
||||
|
||||
@@ -880,7 +883,7 @@ IntervalVariableSpec: {
|
||||
auto: bool | *false
|
||||
auto_min: string | *""
|
||||
auto_count: int | *0
|
||||
refresh: VariableRefresh
|
||||
refresh: "onTimeRangeChanged"
|
||||
label?: string
|
||||
hide: VariableHide
|
||||
skipUrlSync: bool | *false
|
||||
|
||||
@@ -209,6 +209,7 @@ type DashboardPanelQuerySpec struct {
|
||||
func NewDashboardPanelQuerySpec() *DashboardPanelQuerySpec {
|
||||
return &DashboardPanelQuerySpec{
|
||||
Query: *NewDashboardDataQueryKind(),
|
||||
RefId: "A",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,8 +555,9 @@ const (
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardThreshold struct {
|
||||
Value float64 `json:"value"`
|
||||
Color string `json:"color"`
|
||||
// Value null means -Infinity
|
||||
Value *float64 `json:"value"`
|
||||
Color string `json:"color"`
|
||||
}
|
||||
|
||||
// NewDashboardThreshold creates a new DashboardThreshold object.
|
||||
@@ -1615,7 +1617,7 @@ type DashboardIntervalVariableSpec struct {
|
||||
Auto bool `json:"auto"`
|
||||
AutoMin string `json:"auto_min"`
|
||||
AutoCount int64 `json:"auto_count"`
|
||||
Refresh DashboardVariableRefresh `json:"refresh"`
|
||||
Refresh string `json:"refresh"`
|
||||
Label *string `json:"label,omitempty"`
|
||||
Hide DashboardVariableHide `json:"hide"`
|
||||
SkipUrlSync bool `json:"skipUrlSync"`
|
||||
@@ -1639,7 +1641,7 @@ func NewDashboardIntervalVariableSpec() *DashboardIntervalVariableSpec {
|
||||
Auto: false,
|
||||
AutoMin: "",
|
||||
AutoCount: 0,
|
||||
Refresh: DashboardVariableRefreshNever,
|
||||
Refresh: "onTimeRangeChanged",
|
||||
Hide: DashboardVariableHideDontHide,
|
||||
SkipUrlSync: false,
|
||||
}
|
||||
@@ -1926,6 +1928,8 @@ func NewDashboardV2beta1DataQueryKindDatasource() *DashboardV2beta1DataQueryKind
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardV2beta1FieldConfigSourceOverrides struct {
|
||||
// Describes config override rules created when interacting with Grafana.
|
||||
SystemRef *string `json:"__systemRef,omitempty"`
|
||||
Matcher DashboardMatcherConfig `json:"matcher"`
|
||||
Properties []DashboardDynamicConfigValue `json:"properties"`
|
||||
}
|
||||
|
||||
@@ -4549,9 +4549,9 @@ func schema_pkg_apis_dashboard_v2beta1_DashboardThreshold(ref common.ReferenceCa
|
||||
Properties: map[string]spec.Schema{
|
||||
"value": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: 0,
|
||||
Type: []string{"number"},
|
||||
Format: "double",
|
||||
Description: "Value null means -Infinity",
|
||||
Type: []string{"number"},
|
||||
Format: "double",
|
||||
},
|
||||
},
|
||||
"color": {
|
||||
@@ -4832,6 +4832,13 @@ func schema_pkg_apis_dashboard_v2beta1_DashboardV2beta1FieldConfigSourceOverride
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"__systemRef": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Describes config override rules created when interacting with Grafana.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"matcher": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
|
||||
+1
@@ -68,6 +68,7 @@ API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/ap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardStringOrArrayOfString,String
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardStringOrFloat64,Float64
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardStringOrFloat64,String
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardV2beta1FieldConfigSourceOverrides,SystemRef
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,RangeMap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,RegexMap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,SpecialValueMap
|
||||
|
||||
Reference in New Issue
Block a user