mirror of https://github.com/grafana/grafana
Dashboard Migrations: V29 query variable refresh property and options (#108088)
* Dashboard Migrations: V31 LabelsToFields-Merge Migration * Dashboard Migrations: V32 No-op migration * simplify * Refactor to reduce nesting * Dashboard Migrations: V30 value mappings and tooltip options * Do not automigrate since graph is migrated in v27 * Refactor to reduce nesting * Add test case for invalid mapping * migrate to v29 --------- Co-authored-by: Ivan Ortega <ivanortegaalba@gmail.com>adela/expose_hidden_fields^2
parent
1200b684c6
commit
2f8ec01c6c
@ -0,0 +1,59 @@ |
||||
package schemaversion |
||||
|
||||
// V29 migrates query variables to ensure their refresh property is set to 1 (on dashboard load)
|
||||
// if it is not 1 or 2, and clears their options array if present.
|
||||
//
|
||||
// Example before migration:
|
||||
//
|
||||
// "templating": {
|
||||
// "list": [
|
||||
// { "type": "query", "refresh": 0, "options": [{ "text": "A", "value": "A" }] },
|
||||
// { "type": "query", "refresh": 2, "options": [{ "text": "B", "value": "B" }] },
|
||||
// { "type": "query", "options": [{ "text": "C", "value": "C" }] }
|
||||
// ]
|
||||
// }
|
||||
//
|
||||
// Example after migration:
|
||||
//
|
||||
// "templating": {
|
||||
// "list": [
|
||||
// { "type": "query", "refresh": 1, "options": [] },
|
||||
// { "type": "query", "refresh": 2, "options": [] },
|
||||
// { "type": "query", "refresh": 1, "options": [] }
|
||||
// ]
|
||||
// }
|
||||
func V29(dashboard map[string]interface{}) error { |
||||
dashboard["schemaVersion"] = 29 |
||||
|
||||
templating, ok := dashboard["templating"].(map[string]interface{}) |
||||
if !ok { |
||||
return nil |
||||
} |
||||
list, ok := templating["list"].([]interface{}) |
||||
if !ok { |
||||
return nil |
||||
} |
||||
for _, v := range list { |
||||
variable, ok := v.(map[string]interface{}) |
||||
if !ok { |
||||
continue |
||||
} |
||||
if variable["type"] != "query" { |
||||
continue |
||||
} |
||||
// Set refresh to 1 if not 1 or 2
|
||||
refresh, hasRefresh := variable["refresh"] |
||||
refreshInt := 0 |
||||
if r, ok := refresh.(int); ok { |
||||
refreshInt = r |
||||
} |
||||
if !hasRefresh || (refreshInt != 1 && refreshInt != 2) { |
||||
variable["refresh"] = 1 |
||||
} |
||||
// Clear options if present
|
||||
if _, hasOptions := variable["options"]; hasOptions { |
||||
variable["options"] = []interface{}{} |
||||
} |
||||
} |
||||
return nil |
||||
} |
@ -0,0 +1,127 @@ |
||||
package schemaversion_test |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion" |
||||
) |
||||
|
||||
func TestV29(t *testing.T) { |
||||
tests := []migrationTestCase{ |
||||
{ |
||||
name: "query variables get migrated with refresh and options", |
||||
input: map[string]interface{}{ |
||||
"title": "V29 Query Variables Migration Test Dashboard", |
||||
"schemaVersion": 28, |
||||
"templating": map[string]interface{}{ |
||||
"list": []interface{}{ |
||||
map[string]interface{}{"type": "query", "name": "never_refresh_with_options", "options": []interface{}{map[string]interface{}{"text": "A", "value": "A"}}, "refresh": 0}, |
||||
map[string]interface{}{"type": "query", "name": "never_refresh_without_options", "options": []interface{}{}, "refresh": 0}, |
||||
map[string]interface{}{"type": "query", "name": "dashboard_refresh_with_options", "options": []interface{}{map[string]interface{}{"text": "A", "value": "A"}}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "dashboard_refresh_without_options", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "timerange_refresh_with_options", "options": []interface{}{map[string]interface{}{"text": "A", "value": "A"}}, "refresh": 2}, |
||||
map[string]interface{}{"type": "query", "name": "timerange_refresh_without_options", "options": []interface{}{}, "refresh": 2}, |
||||
map[string]interface{}{"type": "query", "name": "no_refresh_with_options", "options": []interface{}{map[string]interface{}{"text": "A", "value": "A"}}}, |
||||
map[string]interface{}{"type": "query", "name": "no_refresh_without_options", "options": []interface{}{}}, |
||||
map[string]interface{}{"type": "query", "name": "unknown_refresh_with_options", "options": []interface{}{map[string]interface{}{"text": "A", "value": "A"}}, "refresh": 2001}, |
||||
map[string]interface{}{"type": "query", "name": "unknown_refresh_without_options", "options": []interface{}{}, "refresh": 2001}, |
||||
map[string]interface{}{"type": "custom", "name": "custom", "options": []interface{}{map[string]interface{}{"text": "custom", "value": "custom"}}}, |
||||
map[string]interface{}{"type": "textbox", "name": "textbox", "options": []interface{}{map[string]interface{}{"text": "Hello", "value": "World"}}}, |
||||
map[string]interface{}{"type": "datasource", "name": "datasource", "options": []interface{}{map[string]interface{}{"text": "ds", "value": "ds"}}}, |
||||
map[string]interface{}{"type": "interval", "name": "interval", "options": []interface{}{map[string]interface{}{"text": "1m", "value": "1m"}}}, |
||||
}, |
||||
}, |
||||
}, |
||||
expected: map[string]interface{}{ |
||||
"title": "V29 Query Variables Migration Test Dashboard", |
||||
"schemaVersion": 29, |
||||
"templating": map[string]interface{}{ |
||||
"list": []interface{}{ |
||||
map[string]interface{}{"type": "query", "name": "never_refresh_with_options", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "never_refresh_without_options", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "dashboard_refresh_with_options", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "dashboard_refresh_without_options", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "timerange_refresh_with_options", "options": []interface{}{}, "refresh": 2}, |
||||
map[string]interface{}{"type": "query", "name": "timerange_refresh_without_options", "options": []interface{}{}, "refresh": 2}, |
||||
map[string]interface{}{"type": "query", "name": "no_refresh_with_options", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "no_refresh_without_options", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "unknown_refresh_with_options", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "unknown_refresh_without_options", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "custom", "name": "custom", "options": []interface{}{map[string]interface{}{"text": "custom", "value": "custom"}}}, |
||||
map[string]interface{}{"type": "textbox", "name": "textbox", "options": []interface{}{map[string]interface{}{"text": "Hello", "value": "World"}}}, |
||||
map[string]interface{}{"type": "datasource", "name": "datasource", "options": []interface{}{map[string]interface{}{"text": "ds", "value": "ds"}}}, |
||||
map[string]interface{}{"type": "interval", "name": "interval", "options": []interface{}{map[string]interface{}{"text": "1m", "value": "1m"}}}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
name: "non-query variables remain unchanged", |
||||
input: map[string]interface{}{ |
||||
"title": "V29 Non-Query Variables Test Dashboard", |
||||
"schemaVersion": 28, |
||||
"templating": map[string]interface{}{ |
||||
"list": []interface{}{ |
||||
map[string]interface{}{"type": "custom", "name": "custom", "options": []interface{}{map[string]interface{}{"text": "custom", "value": "custom"}}}, |
||||
map[string]interface{}{"type": "textbox", "name": "textbox", "options": []interface{}{map[string]interface{}{"text": "Hello", "value": "World"}}}, |
||||
map[string]interface{}{"type": "datasource", "name": "datasource", "options": []interface{}{map[string]interface{}{"text": "ds", "value": "ds"}}}, |
||||
map[string]interface{}{"type": "interval", "name": "interval", "options": []interface{}{map[string]interface{}{"text": "1m", "value": "1m"}}}, |
||||
}, |
||||
}, |
||||
}, |
||||
expected: map[string]interface{}{ |
||||
"title": "V29 Non-Query Variables Test Dashboard", |
||||
"schemaVersion": 29, |
||||
"templating": map[string]interface{}{ |
||||
"list": []interface{}{ |
||||
map[string]interface{}{"type": "custom", "name": "custom", "options": []interface{}{map[string]interface{}{"text": "custom", "value": "custom"}}}, |
||||
map[string]interface{}{"type": "textbox", "name": "textbox", "options": []interface{}{map[string]interface{}{"text": "Hello", "value": "World"}}}, |
||||
map[string]interface{}{"type": "datasource", "name": "datasource", "options": []interface{}{map[string]interface{}{"text": "ds", "value": "ds"}}}, |
||||
map[string]interface{}{"type": "interval", "name": "interval", "options": []interface{}{map[string]interface{}{"text": "1m", "value": "1m"}}}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
name: "all query variables should have options removed", |
||||
input: map[string]interface{}{ |
||||
"title": "V29 Query Variables Options Removal Test Dashboard", |
||||
"schemaVersion": 28, |
||||
"templating": map[string]interface{}{ |
||||
"list": []interface{}{ |
||||
map[string]interface{}{"type": "query", "name": "query1", "options": []interface{}{map[string]interface{}{"text": "A", "value": "A"}}}, |
||||
map[string]interface{}{"type": "query", "name": "query2", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "query3", "options": []interface{}{map[string]interface{}{"text": "B", "value": "B"}, map[string]interface{}{"text": "C", "value": "C"}}, "refresh": 2}, |
||||
map[string]interface{}{"type": "query", "name": "query4", "options": []interface{}{map[string]interface{}{"text": "D", "value": "D"}}, "refresh": 0}, |
||||
map[string]interface{}{"type": "query", "name": "query5", "options": []interface{}{map[string]interface{}{"text": "E", "value": "E"}}, "refresh": 2001}, |
||||
map[string]interface{}{"type": "query", "name": "query6", "options": []interface{}{}}, |
||||
map[string]interface{}{"type": "query", "name": "query7", "options": []interface{}{map[string]interface{}{"text": "F", "value": "F"}}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "query8", "options": []interface{}{map[string]interface{}{"text": "G", "value": "G"}}, "refresh": 2}, |
||||
map[string]interface{}{"type": "query", "name": "query9", "options": []interface{}{map[string]interface{}{"text": "H", "value": "H"}}}, |
||||
map[string]interface{}{"type": "query", "name": "query10", "options": []interface{}{map[string]interface{}{"text": "I", "value": "I"}}, "refresh": 999}, |
||||
}, |
||||
}, |
||||
}, |
||||
expected: map[string]interface{}{ |
||||
"title": "V29 Query Variables Options Removal Test Dashboard", |
||||
"schemaVersion": 29, |
||||
"templating": map[string]interface{}{ |
||||
"list": []interface{}{ |
||||
map[string]interface{}{"type": "query", "name": "query1", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "query2", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "query3", "options": []interface{}{}, "refresh": 2}, |
||||
map[string]interface{}{"type": "query", "name": "query4", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "query5", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "query6", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "query7", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "query8", "options": []interface{}{}, "refresh": 2}, |
||||
map[string]interface{}{"type": "query", "name": "query9", "options": []interface{}{}, "refresh": 1}, |
||||
map[string]interface{}{"type": "query", "name": "query10", "options": []interface{}{}, "refresh": 1}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
runMigrationTests(t, tests, schemaversion.V29) |
||||
} |
@ -0,0 +1,137 @@ |
||||
{ |
||||
"title": "V29 Query Variables Refresh and Options Migration Test Dashboard", |
||||
"schemaVersion": 28, |
||||
"templating": { |
||||
"list": [ |
||||
{ |
||||
"name": "never_refresh_with_options", |
||||
"type": "query", |
||||
"datasource": "prometheus", |
||||
"options": [ |
||||
{"text": "A", "value": "A"}, |
||||
{"text": "B", "value": "B"} |
||||
], |
||||
"refresh": 0 |
||||
}, |
||||
{ |
||||
"name": "never_refresh_without_options", |
||||
"type": "query", |
||||
"datasource": "prometheus", |
||||
"options": [], |
||||
"refresh": 0 |
||||
}, |
||||
{ |
||||
"name": "dashboard_refresh_with_options", |
||||
"type": "query", |
||||
"datasource": "prometheus", |
||||
"options": [ |
||||
{"text": "C", "value": "C"} |
||||
], |
||||
"refresh": 1 |
||||
}, |
||||
{ |
||||
"name": "dashboard_refresh_without_options", |
||||
"type": "query", |
||||
"datasource": "prometheus", |
||||
"options": [], |
||||
"refresh": 1 |
||||
}, |
||||
{ |
||||
"name": "timerange_refresh_with_options", |
||||
"type": "query", |
||||
"datasource": "prometheus", |
||||
"options": [ |
||||
{"text": "D", "value": "D"}, |
||||
{"text": "E", "value": "E"} |
||||
], |
||||
"refresh": 2 |
||||
}, |
||||
{ |
||||
"name": "timerange_refresh_without_options", |
||||
"type": "query", |
||||
"datasource": "prometheus", |
||||
"options": [], |
||||
"refresh": 2 |
||||
}, |
||||
{ |
||||
"name": "no_refresh_with_options", |
||||
"type": "query", |
||||
"datasource": "prometheus", |
||||
"options": [ |
||||
{"text": "F", "value": "F"} |
||||
] |
||||
}, |
||||
{ |
||||
"name": "no_refresh_without_options", |
||||
"type": "query", |
||||
"datasource": "prometheus", |
||||
"options": [] |
||||
}, |
||||
{ |
||||
"name": "unknown_refresh_with_options", |
||||
"type": "query", |
||||
"datasource": "prometheus", |
||||
"options": [ |
||||
{"text": "G", "value": "G"} |
||||
], |
||||
"refresh": 2001 |
||||
}, |
||||
{ |
||||
"name": "unknown_refresh_without_options", |
||||
"type": "query", |
||||
"datasource": "prometheus", |
||||
"options": [], |
||||
"refresh": 2001 |
||||
}, |
||||
{ |
||||
"name": "custom_variable", |
||||
"type": "custom", |
||||
"options": [ |
||||
{"text": "custom", "value": "custom"} |
||||
] |
||||
}, |
||||
{ |
||||
"name": "textbox_variable", |
||||
"type": "textbox", |
||||
"options": [ |
||||
{"text": "Hello", "value": "World"} |
||||
] |
||||
}, |
||||
{ |
||||
"name": "datasource_variable", |
||||
"type": "datasource", |
||||
"options": [ |
||||
{"text": "ds", "value": "ds"} |
||||
] |
||||
}, |
||||
{ |
||||
"name": "interval_variable", |
||||
"type": "interval", |
||||
"options": [ |
||||
{"text": "1m", "value": "1m"} |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"panels": [ |
||||
{ |
||||
"id": 1, |
||||
"title": "Test Panel", |
||||
"type": "timeseries", |
||||
"datasource": "prometheus", |
||||
"targets": [ |
||||
{ |
||||
"refId": "A", |
||||
"expr": "up" |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"time": { |
||||
"from": "now-6h", |
||||
"to": "now" |
||||
}, |
||||
"timepicker": { |
||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"] |
||||
} |
||||
} |
@ -0,0 +1,176 @@ |
||||
{ |
||||
"panels": [ |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"id": 1, |
||||
"targets": [ |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"expr": "up", |
||||
"refId": "A" |
||||
} |
||||
], |
||||
"title": "Test Panel", |
||||
"type": "timeseries" |
||||
} |
||||
], |
||||
"refresh": "", |
||||
"schemaVersion": 41, |
||||
"templating": { |
||||
"list": [ |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"name": "never_refresh_with_options", |
||||
"options": [], |
||||
"refresh": 1, |
||||
"type": "query" |
||||
}, |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"name": "never_refresh_without_options", |
||||
"options": [], |
||||
"refresh": 1, |
||||
"type": "query" |
||||
}, |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"name": "dashboard_refresh_with_options", |
||||
"options": [], |
||||
"refresh": 1, |
||||
"type": "query" |
||||
}, |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"name": "dashboard_refresh_without_options", |
||||
"options": [], |
||||
"refresh": 1, |
||||
"type": "query" |
||||
}, |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"name": "timerange_refresh_with_options", |
||||
"options": [], |
||||
"refresh": 1, |
||||
"type": "query" |
||||
}, |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"name": "timerange_refresh_without_options", |
||||
"options": [], |
||||
"refresh": 1, |
||||
"type": "query" |
||||
}, |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"name": "no_refresh_with_options", |
||||
"options": [], |
||||
"refresh": 1, |
||||
"type": "query" |
||||
}, |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"name": "no_refresh_without_options", |
||||
"options": [], |
||||
"refresh": 1, |
||||
"type": "query" |
||||
}, |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"name": "unknown_refresh_with_options", |
||||
"options": [], |
||||
"refresh": 1, |
||||
"type": "query" |
||||
}, |
||||
{ |
||||
"datasource": { |
||||
"uid": "prometheus" |
||||
}, |
||||
"name": "unknown_refresh_without_options", |
||||
"options": [], |
||||
"refresh": 1, |
||||
"type": "query" |
||||
}, |
||||
{ |
||||
"name": "custom_variable", |
||||
"options": [ |
||||
{ |
||||
"text": "custom", |
||||
"value": "custom" |
||||
} |
||||
], |
||||
"type": "custom" |
||||
}, |
||||
{ |
||||
"name": "textbox_variable", |
||||
"options": [ |
||||
{ |
||||
"text": "Hello", |
||||
"value": "World" |
||||
} |
||||
], |
||||
"type": "textbox" |
||||
}, |
||||
{ |
||||
"name": "datasource_variable", |
||||
"options": [ |
||||
{ |
||||
"text": "ds", |
||||
"value": "ds" |
||||
} |
||||
], |
||||
"type": "datasource" |
||||
}, |
||||
{ |
||||
"name": "interval_variable", |
||||
"options": [ |
||||
{ |
||||
"text": "1m", |
||||
"value": "1m" |
||||
} |
||||
], |
||||
"type": "interval" |
||||
} |
||||
] |
||||
}, |
||||
"time": { |
||||
"from": "now-6h", |
||||
"to": "now" |
||||
}, |
||||
"timepicker": { |
||||
"refresh_intervals": [ |
||||
"5s", |
||||
"10s", |
||||
"30s", |
||||
"1m", |
||||
"5m", |
||||
"15m", |
||||
"30m", |
||||
"1h", |
||||
"2h", |
||||
"1d" |
||||
] |
||||
}, |
||||
"title": "V29 Query Variables Refresh and Options Migration Test Dashboard" |
||||
} |
Loading…
Reference in new issue