From 0398face05aac33ed42453570b919e9a125c32ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 12 Mar 2016 10:13:49 +0100 Subject: [PATCH] feat(plugins): dashboard import for data sources is working! #4298 --- pkg/api/dashboard_snapshot.go | 2 - pkg/api/dtos/models.go | 4 +- pkg/components/simplejson/simplejson_go11.go | 2 - pkg/models/dashboard_snapshot.go | 14 +- pkg/plugins/dashboard_importer.go | 55 +++--- pkg/plugins/dashboard_importer_test.go | 15 +- pkg/services/sqlstore/dashboard.go | 4 +- .../sqlstore/dashboard_snapshot_test.go | 7 +- pkg/services/sqlstore/dashboard_test.go | 17 +- .../app/features/dashboard/dashnav/dashnav.ts | 4 +- .../plugins/import_list/import_list.html | 6 +- .../plugins/import_list/import_list.ts | 2 +- .../features/plugins/partials/ds_edit.html | 2 +- .../graphite/dashboards/carbon_metrics.json | 176 ++++++++++++++++++ .../graphite/dashboards/carbon_stats.json | 22 --- .../plugins/datasource/graphite/plugin.json | 2 +- tests/test-app/dashboards/connections.json | 4 + .../dashboards/connections_result.json | 20 ++ 18 files changed, 278 insertions(+), 80 deletions(-) create mode 100644 public/app/plugins/datasource/graphite/dashboards/carbon_metrics.json delete mode 100644 public/app/plugins/datasource/graphite/dashboards/carbon_stats.json create mode 100644 tests/test-app/dashboards/connections_result.json diff --git a/pkg/api/dashboard_snapshot.go b/pkg/api/dashboard_snapshot.go index 8ed848a7b11..3c369ca5b7f 100644 --- a/pkg/api/dashboard_snapshot.go +++ b/pkg/api/dashboard_snapshot.go @@ -53,7 +53,6 @@ func CreateDashboardSnapshot(c *middleware.Context, cmd m.CreateDashboardSnapsho } func GetDashboardSnapshot(c *middleware.Context) { - key := c.Params(":key") query := &m.GetDashboardSnapshotQuery{Key: key} @@ -136,5 +135,4 @@ func SearchDashboardSnapshots(c *middleware.Context) Response { } return Json(200, dtos) - //return Json(200, searchQuery.Result) } diff --git a/pkg/api/dtos/models.go b/pkg/api/dtos/models.go index d5534ea6ed4..26295dd3d3c 100644 --- a/pkg/api/dtos/models.go +++ b/pkg/api/dtos/models.go @@ -53,8 +53,8 @@ type DashboardMeta struct { } type DashboardFullWithMeta struct { - Meta DashboardMeta `json:"meta"` - Dashboard map[string]interface{} `json:"dashboard"` + Meta DashboardMeta `json:"meta"` + Dashboard *simplejson.Json `json:"dashboard"` } type DataSource struct { diff --git a/pkg/components/simplejson/simplejson_go11.go b/pkg/components/simplejson/simplejson_go11.go index 3a88b29e449..1c479532cf0 100644 --- a/pkg/components/simplejson/simplejson_go11.go +++ b/pkg/components/simplejson/simplejson_go11.go @@ -6,7 +6,6 @@ import ( "bytes" "encoding/json" "errors" - "fmt" "io" "reflect" "strconv" @@ -14,7 +13,6 @@ import ( // Implements the json.Unmarshaler interface. func (j *Json) UnmarshalJSON(p []byte) error { - fmt.Printf("UnmarshalJSON") dec := json.NewDecoder(bytes.NewBuffer(p)) dec.UseNumber() return dec.Decode(&j.data) diff --git a/pkg/models/dashboard_snapshot.go b/pkg/models/dashboard_snapshot.go index 9bfbd06c1ef..f920e91f2e4 100644 --- a/pkg/models/dashboard_snapshot.go +++ b/pkg/models/dashboard_snapshot.go @@ -1,6 +1,10 @@ package models -import "time" +import ( + "time" + + "github.com/grafana/grafana/pkg/components/simplejson" +) // DashboardSnapshot model type DashboardSnapshot struct { @@ -17,7 +21,7 @@ type DashboardSnapshot struct { Created time.Time Updated time.Time - Dashboard map[string]interface{} + Dashboard *simplejson.Json } // DashboardSnapshotDTO without dashboard map @@ -40,9 +44,9 @@ type DashboardSnapshotDTO struct { // COMMANDS type CreateDashboardSnapshotCommand struct { - Dashboard map[string]interface{} `json:"dashboard" binding:"Required"` - Name string `json:"name" binding:"Required"` - Expires int64 `json:"expires"` + Dashboard *simplejson.Json `json:"dashboard" binding:"Required"` + Name string `json:"name" binding:"Required"` + Expires int64 `json:"expires"` // these are passed when storing an external snapshot ref External bool `json:"external"` diff --git a/pkg/plugins/dashboard_importer.go b/pkg/plugins/dashboard_importer.go index 2a640e814e9..b5dc286f6d1 100644 --- a/pkg/plugins/dashboard_importer.go +++ b/pkg/plugins/dashboard_importer.go @@ -1,8 +1,8 @@ package plugins import ( + "encoding/json" "fmt" - "reflect" "regexp" "github.com/grafana/grafana/pkg/bus" @@ -127,32 +127,45 @@ func (this *DashTemplateEvaluator) Eval() (*simplejson.Json, error) { log.Info("Import: dashboard has no __import section") } - this.EvalObject(this.template, this.result) - return this.result, nil + return simplejson.NewFromAny(this.evalObject(this.template)), nil } -func (this *DashTemplateEvaluator) EvalObject(source *simplejson.Json, writer *simplejson.Json) { +func (this *DashTemplateEvaluator) evalValue(source *simplejson.Json) interface{} { + + sourceValue := source.Interface() + + switch v := sourceValue.(type) { + case string: + interpolated := this.varRegex.ReplaceAllStringFunc(v, func(match string) string { + return this.variables[match] + }) + return interpolated + case bool: + return v + case json.Number: + return v + case map[string]interface{}: + return this.evalObject(source) + case []interface{}: + array := make([]interface{}, 0) + for _, item := range v { + array = append(array, this.evalValue(simplejson.NewFromAny(item))) + } + return array + } + + return nil +} + +func (this *DashTemplateEvaluator) evalObject(source *simplejson.Json) interface{} { + result := make(map[string]interface{}) for key, value := range source.MustMap() { if key == "__inputs" { continue } - - switch v := value.(type) { - case string: - interpolated := this.varRegex.ReplaceAllStringFunc(v, func(match string) string { - return this.variables[match] - }) - writer.Set(key, interpolated) - case map[string]interface{}: - childSource := simplejson.NewFromAny(value) - childWriter := simplejson.New() - writer.Set(key, childWriter.Interface()) - this.EvalObject(childSource, childWriter) - case []interface{}: - default: - log.Info("type: %v", reflect.TypeOf(value)) - log.Error(3, "Unknown json type key: %v , type: %v", key, value) - } + result[key] = this.evalValue(simplejson.NewFromAny(value)) } + + return result } diff --git a/pkg/plugins/dashboard_importer_test.go b/pkg/plugins/dashboard_importer_test.go index 3e4c307cbb9..9b5605277d4 100644 --- a/pkg/plugins/dashboard_importer_test.go +++ b/pkg/plugins/dashboard_importer_test.go @@ -1,6 +1,7 @@ package plugins import ( + "io/ioutil" "testing" "github.com/grafana/grafana/pkg/bus" @@ -34,7 +35,7 @@ func TestDashboardImport(t *testing.T) { OrgId: 1, UserId: 1, Inputs: []ImportDashboardInput{ - {Name: "*", Type: "datasource"}, + {Name: "*", Type: "datasource", Value: "graphite"}, }, } @@ -44,11 +45,15 @@ func TestDashboardImport(t *testing.T) { Convey("should install dashboard", func() { So(importedDash, ShouldNotBeNil) - dashStr, _ := importedDash.Data.EncodePretty() - So(string(dashStr), ShouldEqual, "") + resultStr, _ := importedDash.Data.EncodePretty() + expectedBytes, _ := ioutil.ReadFile("../../tests/test-app/dashboards/connections_result.json") + expectedJson, _ := simplejson.NewJson(expectedBytes) + expectedStr, _ := expectedJson.EncodePretty() - // So(panel["datasource"], ShouldEqual, "graphite") - // So(importedDash.Data["__inputs"], ShouldBeNil) + So(string(resultStr), ShouldEqual, string(expectedStr)) + + panel := importedDash.Data.Get("rows").GetIndex(0).Get("panels").GetIndex(0) + So(panel.Get("datasource").MustString(), ShouldEqual, "graphite") }) }) diff --git a/pkg/services/sqlstore/dashboard.go b/pkg/services/sqlstore/dashboard.go index a33ef10d725..396d507cfd2 100644 --- a/pkg/services/sqlstore/dashboard.go +++ b/pkg/services/sqlstore/dashboard.go @@ -69,7 +69,7 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error { affectedRows, err = sess.Insert(dash) } else { dash.Version += 1 - dash.Data["version"] = dash.Version + dash.Data.Set("version", dash.Version) affectedRows, err = sess.Id(dash.Id).Update(dash) } @@ -108,7 +108,7 @@ func GetDashboard(query *m.GetDashboardQuery) error { return m.ErrDashboardNotFound } - dashboard.Data["id"] = dashboard.Id + dashboard.Data.Set("id", dashboard.Id) query.Result = &dashboard return nil diff --git a/pkg/services/sqlstore/dashboard_snapshot_test.go b/pkg/services/sqlstore/dashboard_snapshot_test.go index 5301f0f1cc9..50375088b4b 100644 --- a/pkg/services/sqlstore/dashboard_snapshot_test.go +++ b/pkg/services/sqlstore/dashboard_snapshot_test.go @@ -5,6 +5,7 @@ import ( . "github.com/smartystreets/goconvey/convey" + "github.com/grafana/grafana/pkg/components/simplejson" m "github.com/grafana/grafana/pkg/models" ) @@ -16,9 +17,9 @@ func TestDashboardSnapshotDBAccess(t *testing.T) { Convey("Given saved snaphot", func() { cmd := m.CreateDashboardSnapshotCommand{ Key: "hej", - Dashboard: map[string]interface{}{ + Dashboard: simplejson.NewFromAny(map[string]interface{}{ "hello": "mupp", - }, + }), } err := CreateDashboardSnapshot(&cmd) So(err, ShouldBeNil) @@ -29,7 +30,7 @@ func TestDashboardSnapshotDBAccess(t *testing.T) { So(err, ShouldBeNil) So(query.Result, ShouldNotBeNil) - So(query.Result.Dashboard["hello"], ShouldEqual, "mupp") + So(query.Result.Dashboard.Get("hello").MustString(), ShouldEqual, "mupp") }) }) diff --git a/pkg/services/sqlstore/dashboard_test.go b/pkg/services/sqlstore/dashboard_test.go index 2d35a0742de..609639f7788 100644 --- a/pkg/services/sqlstore/dashboard_test.go +++ b/pkg/services/sqlstore/dashboard_test.go @@ -5,6 +5,7 @@ import ( . "github.com/smartystreets/goconvey/convey" + "github.com/grafana/grafana/pkg/components/simplejson" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/search" ) @@ -12,11 +13,11 @@ import ( func insertTestDashboard(title string, orgId int64, tags ...interface{}) *m.Dashboard { cmd := m.SaveDashboardCommand{ OrgId: orgId, - Dashboard: map[string]interface{}{ + Dashboard: simplejson.NewFromAny(map[string]interface{}{ "id": nil, "title": title, "tags": tags, - }, + }), } err := SaveDashboard(&cmd) @@ -58,11 +59,11 @@ func TestDashboardDataAccess(t *testing.T) { cmd := m.SaveDashboardCommand{ OrgId: 1, Overwrite: true, - Dashboard: map[string]interface{}{ + Dashboard: simplejson.NewFromAny(map[string]interface{}{ "id": float64(123412321), "title": "Expect error", "tags": []interface{}{}, - }, + }), } err := SaveDashboard(&cmd) @@ -76,11 +77,11 @@ func TestDashboardDataAccess(t *testing.T) { cmd := m.SaveDashboardCommand{ OrgId: 2, Overwrite: true, - Dashboard: map[string]interface{}{ + Dashboard: simplejson.NewFromAny(map[string]interface{}{ "id": float64(query.Result.Id), "title": "Expect error", "tags": []interface{}{}, - }, + }), } err := SaveDashboard(&cmd) @@ -135,11 +136,11 @@ func TestDashboardDataAccess(t *testing.T) { Convey("Should not be able to save dashboard with same name", func() { cmd := m.SaveDashboardCommand{ OrgId: 1, - Dashboard: map[string]interface{}{ + Dashboard: simplejson.NewFromAny(map[string]interface{}{ "id": nil, "title": "test dash 23", "tags": []interface{}{}, - }, + }), } err := SaveDashboard(&cmd) diff --git a/public/app/features/dashboard/dashnav/dashnav.ts b/public/app/features/dashboard/dashnav/dashnav.ts index dcc2f40d0dc..2d5b66cb13c 100644 --- a/public/app/features/dashboard/dashnav/dashnav.ts +++ b/public/app/features/dashboard/dashnav/dashnav.ts @@ -137,8 +137,8 @@ export class DashNavCtrl { $scope.deleteDashboard = function() { $scope.appEvent('confirm-modal', { - title: 'Delete dashboard', - text: 'Do you want to delete dashboard?', + title: 'Delete', + text: 'Do you want to delete this dashboard?', text2: $scope.dashboard.title, icon: 'fa-trash', yesText: 'Delete', diff --git a/public/app/features/plugins/import_list/import_list.html b/public/app/features/plugins/import_list/import_list.html index d6c1bb914ce..f9dc4ff28d0 100644 --- a/public/app/features/plugins/import_list/import_list.html +++ b/public/app/features/plugins/import_list/import_list.html @@ -21,13 +21,13 @@ diff --git a/public/app/features/plugins/import_list/import_list.ts b/public/app/features/plugins/import_list/import_list.ts index 004fde69bd1..19f847a58d0 100644 --- a/public/app/features/plugins/import_list/import_list.ts +++ b/public/app/features/plugins/import_list/import_list.ts @@ -34,7 +34,7 @@ export class DashImportListCtrl { }); } - this.backendSrv.post(`/api/plugins/dashboards/install`, installCmd).then(res => { + this.backendSrv.post(`/api/plugins/dashboards/import`, installCmd).then(res => { this.$rootScope.appEvent('alert-success', ['Dashboard Installed', dash.title]); _.extend(dash, res); }); diff --git a/public/app/features/plugins/partials/ds_edit.html b/public/app/features/plugins/partials/ds_edit.html index ff2f981e58b..3305bfd67af 100644 --- a/public/app/features/plugins/partials/ds_edit.html +++ b/public/app/features/plugins/partials/ds_edit.html @@ -74,7 +74,7 @@
- +
diff --git a/public/app/plugins/datasource/graphite/dashboards/carbon_metrics.json b/public/app/plugins/datasource/graphite/dashboards/carbon_metrics.json new file mode 100644 index 00000000000..b9f2db18927 --- /dev/null +++ b/public/app/plugins/datasource/graphite/dashboards/carbon_metrics.json @@ -0,0 +1,176 @@ +{ + "__inputs": { + "graphite": { + "type": "datasource", + "pluginId": "graphite", + "description": "Graphite datasource" + } + }, + + "revision": "1.0", + "title": "Graphite Carbon Metrics", + "tags": ["graphite", "carbon"], + "style": "dark", + "timezone": "browser", + "editable": true, + "hideControls": false, + "sharedCrosshair": false, + "rows": [ + { + "collapsable": true, + "collapse": false, + "editable": true, + "height": "350px", + "notice": false, + "panels": [ + { + "aliasColors": {}, + "annotate": { + "enable": false + }, + "bars": false, + "datasource": "$__graphite", + "editable": true, + "fill": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "max": null, + "min": 0, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null, + "threshold1": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2": null, + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "id": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "loadingEditor": false, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "resolution": 100, + "scale": 1, + "seriesOverrides": [ + { + "alias": "Points Per Update", + "yaxis": 2 + }, + { + "alias": "CPU", + "yaxis": 2 + } + ], + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "alias(sumSeries(carbon.agents.*.updateOperations),\"Updates\") " + }, + { + "refId": "B", + "target": "alias(sumSeries(carbon.agents.*.metricsReceived),'Metrics Received')" + }, + { + "refId": "C", + "target": "alias(sumSeries(carbon.agents.*.committedPoints),'Committed Points')" + }, + { + "refId": "D", + "target": "alias(sumSeries(carbon.agents.*.pointsPerUpdate),'Points Per Update')" + }, + { + "refId": "E", + "target": "alias(averageSeries(carbon.agents.*.cpuUsage),'CPU')" + }, + { + "refId": "F", + "target": "alias(sumSeries(carbon.agents.*.creates),'Creates')" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Graphite Carbon Metrics", + "tooltip": { + "query_as_alias": true, + "shared": false, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "zerofill": true + } + ], + "title": "Row1" + } + ], + "time": { + "from": "now-3h", + "to": "now" + }, + "timepicker": { + "collapse": false, + "enable": true, + "notice": false, + "now": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "status": "Stable", + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ], + "type": "timepicker" + }, + "templating": { + "enable": false, + "list": [] + }, + "annotations": { + "enable": false, + "list": [] + }, + "refresh": false, + "schemaVersion": 8, + "version": 2, + "links": [] +} diff --git a/public/app/plugins/datasource/graphite/dashboards/carbon_stats.json b/public/app/plugins/datasource/graphite/dashboards/carbon_stats.json deleted file mode 100644 index 3cdfb0049c9..00000000000 --- a/public/app/plugins/datasource/graphite/dashboards/carbon_stats.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "__inputs": { - "graphite": { - "type": "datasource", - "pluginId": "graphite", - "description": "Graphite datasource" - } - }, - - "title": "Carbon Cache Stats", - "version": 1, - "rows": [ - { - "panels": [ - { - "type": "graph", - "datasource": "$__graphite" - } - ] - } - ] -} diff --git a/public/app/plugins/datasource/graphite/plugin.json b/public/app/plugins/datasource/graphite/plugin.json index f7715f9c5b9..a1c35094701 100644 --- a/public/app/plugins/datasource/graphite/plugin.json +++ b/public/app/plugins/datasource/graphite/plugin.json @@ -4,7 +4,7 @@ "id": "graphite", "includes": [ - {"type": "dashboard", "name": "Carbon Cache Stats", "path": "dashboards/carbon_stats.json"} + {"type": "dashboard", "name": "Graphite Carbon Metrics", "path": "dashboards/carbon_metrics.json"} ], "metrics": true, diff --git a/tests/test-app/dashboards/connections.json b/tests/test-app/dashboards/connections.json index feb90cae71d..2f5102fba3e 100644 --- a/tests/test-app/dashboards/connections.json +++ b/tests/test-app/dashboards/connections.json @@ -10,6 +10,10 @@ "title": "Nginx Connections", "revision": "1.5", "schemaVersion": 11, + "tags": ["tag1", "tag2"], + "number_array": [1,2,3,10.33], + "boolean_true": true, + "boolean_false": false, "rows": [ { diff --git a/tests/test-app/dashboards/connections_result.json b/tests/test-app/dashboards/connections_result.json new file mode 100644 index 00000000000..1c662f6c269 --- /dev/null +++ b/tests/test-app/dashboards/connections_result.json @@ -0,0 +1,20 @@ +{ + "revision": "1.5", + "tags": ["tag1", "tag2"], + "boolean_false": false, + "boolean_true": true, + "number_array": [1,2,3,10.33], + "rows": [ + { + "panels": [ + { + "datasource": "graphite", + "type": "graph" + } + ] + } + ], + "schemaVersion": 11, + "title": "Nginx Connections", + "version": 0 +}