From 37f7ba5c68d90742d02a96096b344ed14f1a3518 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Wed, 7 Dec 2016 15:17:27 -0800 Subject: [PATCH 01/25] shorten TCPKeepAlive length --- server/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/server.go b/server/server.go index d4d6cf5f3..951b6eef3 100644 --- a/server/server.go +++ b/server/server.go @@ -81,7 +81,7 @@ func (s *Server) Serve() error { httpServer := &graceful.Server{Server: new(http.Server)} httpServer.SetKeepAlivesEnabled(true) - httpServer.TCPKeepAlive = 1 * time.Minute + httpServer.TCPKeepAlive = 5 * time.Second httpServer.Handler = s.handler if !s.ReportingDisabled { From fa8edf94c5f73c74505493e838272015686f20fd Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Wed, 7 Dec 2016 15:17:42 -0800 Subject: [PATCH 02/25] add swagger documentation for dashboard routes --- server/swagger.json | 268 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 267 insertions(+), 1 deletion(-) diff --git a/server/swagger.json b/server/swagger.json index 5e6bab731..14239dcaa 100644 --- a/server/swagger.json +++ b/server/swagger.json @@ -1594,7 +1594,180 @@ } } } - } + }, + "/dashboards": { + "get": { + "tags": [ + "dashboards" + ], + "summary": "List of all dashboards", + "responses": { + "200": { + "description": "An array of dashboards", + "schema": { + "$ref": "#/definitions/Dashboards" + } + }, + "default": { + "description": "Unexpected internal service error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + }, + "post": { + "tags": [ + "dashboards" + ], + "summary": "Create new dashboard", + "parameters": [ + { + "name": "dashboard", + "in": "body", + "description": "Configuration options for new dashboard", + "schema": { + "$ref": "#/definitions/Dashboard" + } + } + ], + "responses": { + "201": { + "description": "Successfully created new dashboard", + "headers": { + "Location": { + "type": "string", + "format": "url", + "description": "Location of the newly created dashboard resource." + } + }, + "schema": { + "$ref": "#/definitions/Dashboard" + } + }, + "default": { + "description": "A processing or an unexpected error.", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, + "/dashboards/{id}": { + "get": { + "tags": [ + "dashboards" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "type": "integer", + "description": "ID of the dashboard", + "required": true + } + ], + "summary": "Specific dashboard", + "description": "Dashboards contain visual display information as well as links to queries", + "responses": { + "200": { + "description": "Returns the specified dashboard with links to queries.", + "schema": { + "$ref": "#/definitions/Dashboard" + } + }, + "404": { + "description": "Unknown dashboard id", + "schema": { + "$ref": "#/definitions/Error" + } + }, + "default": { + "description": "Unexpected internal service error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + }, + "delete": { + "tags": [ + "dashboards" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "type": "integer", + "description": "ID of the layout", + "required": true + } + ], + "summary": "Deletes the specified dashboard", + "responses": { + "204": { + "description": "Dashboard has been removed." + }, + "404": { + "description": "Unknown dashboard id", + "schema": { + "$ref": "#/definitions/Error" + } + }, + "default": { + "description": "Unexpected internal service error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + }, + "put": { + "tags": [ + "layouts" + ], + "summary": "Replace dashboard information.", + "parameters": [ + { + "name": "id", + "in": "path", + "type": "integer", + "description": "ID of a dashboard", + "required": true + }, + { + "name": "config", + "in": "body", + "description": "dashboard configuration update parameters", + "schema": { + "$ref": "#/definitions/Dashboard" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Dashboard has been replaced and the new dashboard is returned.", + "schema": { + "$ref": "#/definitions/Dashboard" + } + }, + "404": { + "description": "Happens when trying to access a non-existent dashboard.", + "schema": { + "$ref": "#/definitions/Error" + } + }, + "default": { + "description": "A processing or an unexpected error.", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, }, "definitions": { "Kapacitors": { @@ -2120,6 +2293,94 @@ } } }, + "Dashboards": { + "description": "a list of dashboards", + "type": "object", + "properties": { + "dashboards": { + "type": "array", + "items": { + "$ref": "#/definitions/Dashboard" + } + } + } + }, + "Dashboard": { + "type": "object", + "properties": { + "id": { + "description": "the unique dashboard id", + "type": "integer", + "format": "int64" + }, + "cells": { + "description": "a list of dashboard visualizations", + "type": "array", + "items": { + "description": "cell visualization information", + "type": "object", + "required": [ + "queries" + ], + "properties": { + "x": { + "description": "X-coordinate of Cell in the Dashboard", + "type": "integer", + "format": "int32" + }, + "y": { + "description": "Y-coordinate of Cell in the Dashboard", + "type": "integer", + "format": "int32" + }, + "w": { + "description": "Width of Cell in the Dashboard", + "type": "integer", + "format": "int32" + }, + "h": { + "description": "Height of Cell in the Dashboard", + "type": "integer", + "format": "int32" + }, + "queries": { + "description": "Time-series data queries for Cell.", + "type": "array", + "items": { + "description": "links to the queries to visualize", + "type": "string", + "format": "url" + } + }, + "type": { + "description": "Cell visualization type", + "type": "string", + "enum": [ + "single-stat", + "line", + "line-plus-single-stat" + ], + "default": "line" + } + } + } + }, + "name": { + "description": "the user-facing name of the dashboard", + "type": "string" + }, + "links": { + "type": "object", + "properties": { + "self": { + "type": "string", + "description": "Self link mapping to this resource", + "format": "url" + } + } + } + } + }, "Routes": { "type": "object", "properties": { @@ -2147,6 +2408,11 @@ "description": "Location of the application mappings endpoint", "type": "string", "format": "url" + }, + "dashboards": { + "description": "location of the dashboards endpoint", + "type": "string", + "format": "url" } } }, From 9a2e49b4d26ca98249a31bd21464664f81c14ff5 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Wed, 7 Dec 2016 15:18:04 -0800 Subject: [PATCH 03/25] add routes and stubs for dashboard API endpoints --- server/dashboards.go | 28 ++++++++++++++++++++++++++++ server/mux.go | 8 ++++++++ 2 files changed, 36 insertions(+) create mode 100644 server/dashboards.go diff --git a/server/dashboards.go b/server/dashboards.go new file mode 100644 index 000000000..cd468e70d --- /dev/null +++ b/server/dashboards.go @@ -0,0 +1,28 @@ +package server + +import "net/http" + +// Dashboards returns all dashboards within the store +func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) { + +} + +// DashboardID returns a single specified dashboard +func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) { + +} + +// NewDashboard creates and returns a new dashboard object +func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) { + +} + +// RemoveDashboard deletes a dashboard +func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) { + +} + +// UpdateDashboard updates a dashboard +func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) { + +} diff --git a/server/mux.go b/server/mux.go index da04de6ed..1849900e5 100644 --- a/server/mux.go +++ b/server/mux.go @@ -109,6 +109,14 @@ func NewMux(opts MuxOpts, service Service) http.Handler { router.PATCH("/chronograf/v1/users/:id/explorations/:eid", service.UpdateExploration) router.DELETE("/chronograf/v1/users/:id/explorations/:eid", service.RemoveExploration) + // Dashboards + router.GET("/chronograf/v1/dashboards", service.Dashboards) + router.POST("/chronograf/v1/dashboards", service.NewDashboard) + + router.GET("/chronograf/v1/dashboards/:id", service.DashboardID) + router.DELETE("/chronograf/v1/dashboard/:id", service.RemoveDashboard) + router.PUT("/chronograf/v1/dashboard/:id", service.UpdateDashboard) + /* Authentication */ if opts.UseAuth { auth := AuthAPI(opts, router) From 7599369eed47c3c43cd109a014e12cb9ecf9f98e Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Wed, 7 Dec 2016 16:31:22 -0800 Subject: [PATCH 04/25] add dashboards interface/structs --- chronograf.go | 33 +++++++++++++++++++++++++++++++++ server/dashboards.go | 19 +++++++++++++++++++ server/routes.go | 22 ++++++++++++---------- server/service.go | 1 + 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/chronograf.go b/chronograf.go index 1991f7387..036b6a4ba 100644 --- a/chronograf.go +++ b/chronograf.go @@ -223,6 +223,39 @@ type UsersStore interface { FindByEmail(ctx context.Context, Email string) (*User, error) } +// DashboardID is the dashboard ID +type DashboardID int + +// Dashboard represents all visual and query data for a dashboard +type Dashboard struct { + ID DashboardID `json:"id"` + Cells []DashboardCell `json:"cells"` + Name string `json:"name"` +} + +// DashboardCell holds visual and query information for a cell +type DashboardCell struct { + X int32 `json:"x"` + Y int32 `json:"y"` + W int32 `json:"w"` + H int32 `json:"h"` + Name string `json:"name"` + Queries []string `json:"queries"` + Type string `json:"type"` +} + +// DashboardStore is the storage and retrieval of dashboards +type DashboardStore interface { + // Create a new Dashboard in the DashboardStore + Add(context.Context, *Dashboard) (*Dashboard, error) + // Delete the Dashboard from the DashboardStore + Delete(context.Context, *Dashboard) error + // Get retrieves a dashboard if `ID` exists. + Get(ctx context.Context, ID DashboardID) (*Dashboard, error) + // Update replaces the dashboard information + Update(context.Context, *Dashboard) error +} + // ExplorationID is a unique ID for an Exploration. type ExplorationID int diff --git a/server/dashboards.go b/server/dashboards.go index cd468e70d..76bfb25b5 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -2,6 +2,25 @@ package server import "net/http" +type dashboardLinks struct { + Self string `json:"self"` // Self link mapping to this resource +} + +type dashboardResponse struct { + *chronograf.Dashboard + Links dashboardLinks `json:"links"` +} + +func newDashboardResponse(d *chronograf.Dashboard) dashboardResponse { + base := "/chronograf/v1/dashboards" + return dashboardResponse{ + Dashboard: d, + Links: dashboardLinks{ + Self: fmt.Sprintf("%s/%d", base, d.ID), + } + } +} + // Dashboards returns all dashboards within the store func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) { diff --git a/server/routes.go b/server/routes.go index 4c256e794..e91df3e47 100644 --- a/server/routes.go +++ b/server/routes.go @@ -7,21 +7,23 @@ import ( ) type getRoutesResponse struct { - Layouts string `json:"layouts"` // Location of the layouts endpoint - Mappings string `json:"mappings"` // Location of the application mappings endpoint - Sources string `json:"sources"` // Location of the sources endpoint - Users string `json:"users"` // Location of the users endpoint - Me string `json:"me"` // Location of the me endpoint + Layouts string `json:"layouts"` // Location of the layouts endpoint + Mappings string `json:"mappings"` // Location of the application mappings endpoint + Sources string `json:"sources"` // Location of the sources endpoint + Users string `json:"users"` // Location of the users endpoint + Me string `json:"me"` // Location of the me endpoint + Dashboards string `json:"dashboards"` // Location of the dashboards endpoint } // AllRoutes returns all top level routes within chronograf func AllRoutes(logger chronograf.Logger) http.HandlerFunc { routes := getRoutesResponse{ - Sources: "/chronograf/v1/sources", - Layouts: "/chronograf/v1/layouts", - Users: "/chronograf/v1/users", - Me: "/chronograf/v1/me", - Mappings: "/chronograf/v1/mappings", + Sources: "/chronograf/v1/sources", + Layouts: "/chronograf/v1/layouts", + Users: "/chronograf/v1/users", + Me: "/chronograf/v1/me", + Mappings: "/chronograf/v1/mappings", + Dashboards: "/chronograf/v1/dashboards", } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/server/service.go b/server/service.go index f4e87e351..0a7363d53 100644 --- a/server/service.go +++ b/server/service.go @@ -10,6 +10,7 @@ type Service struct { LayoutStore chronograf.LayoutStore AlertRulesStore chronograf.AlertRulesStore UsersStore chronograf.UsersStore + DashboardsStore chronograf.DashboardsStore TimeSeries chronograf.TimeSeries Logger chronograf.Logger UseAuth bool From 70e64b6bafec0e296b249f4f79eb928a2d09e298 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 8 Dec 2016 19:28:40 -0800 Subject: [PATCH 05/25] WIP --- bolt/client.go | 2 ++ bolt/dashboards.go | 36 ++++++++++++++++++++++++++++++++++++ bolt/internal/internal.go | 6 ++++++ chronograf.go | 4 ++-- server/dashboards_test.go | 15 +++++++++++++++ 5 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 bolt/dashboards.go create mode 100644 server/dashboards_test.go diff --git a/bolt/client.go b/bolt/client.go index 7f8c7f5e9..730b74d72 100644 --- a/bolt/client.go +++ b/bolt/client.go @@ -21,6 +21,7 @@ type Client struct { LayoutStore *LayoutStore UsersStore *UsersStore AlertsStore *AlertsStore + DashboardsStore *DashboardsStore } func NewClient() *Client { @@ -34,6 +35,7 @@ func NewClient() *Client { client: c, IDs: &uuid.V4{}, } + c.DashboardsStore = &DashboardsStore{client: c} return c } diff --git a/bolt/dashboards.go b/bolt/dashboards.go new file mode 100644 index 000000000..8a8f170b2 --- /dev/null +++ b/bolt/dashboards.go @@ -0,0 +1,36 @@ +package bolt + +import ( + "context" + + "github.com/boltdb/bolt" + "github.com/influxdata/chronograf" + "github.com/influxdata/chronograf/bolt/internal" +) + +var _ chronograf.DashboardsStore = &DashboardsStore{} + +type DashboardsStore struct { + client *Client +} + +func (s *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, error) { + var srcs []chronograf.Dashboard + if err := s.client.db.View(func(tx *bolt.Tx) error { + if err := tx.Bucket(DashboardBucket).ForEach(func(k, v []byte) error { + var src chonograf.Dashboard + if err := internal.UnmarshalDashboard(v, &src); err != nil { + return err + } + srcs = append(srcs, src) + return nil + }); err != nil { + return err + } + return nil + }); err != nil { + return nil, err + } + + return srcs, nil +} diff --git a/bolt/internal/internal.go b/bolt/internal/internal.go index c6a2691e5..a705a69af 100644 --- a/bolt/internal/internal.go +++ b/bolt/internal/internal.go @@ -188,6 +188,12 @@ func UnmarshalLayout(data []byte, l *chronograf.Layout) error { return nil } +func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { + return proto.Marshal(&Dashboard{ + + }) +} + // ScopedAlert contains the source and the kapacitor id type ScopedAlert struct { chronograf.AlertRule diff --git a/chronograf.go b/chronograf.go index 036b6a4ba..4118ef888 100644 --- a/chronograf.go +++ b/chronograf.go @@ -244,8 +244,8 @@ type DashboardCell struct { Type string `json:"type"` } -// DashboardStore is the storage and retrieval of dashboards -type DashboardStore interface { +// DashboardsStore is the storage and retrieval of dashboards +type DashboardsStore interface { // Create a new Dashboard in the DashboardStore Add(context.Context, *Dashboard) (*Dashboard, error) // Delete the Dashboard from the DashboardStore diff --git a/server/dashboards_test.go b/server/dashboards_test.go new file mode 100644 index 000000000..52d3a3fbe --- /dev/null +++ b/server/dashboards_test.go @@ -0,0 +1,15 @@ +package handlers +// +// import ( +// "net/http" +// "testing" +// ) +// +// func TestDashboards(t *testing.T) { +// +// _, err := http.NewRequest("GET", "/chronograf/v1/dashbords", nil) +// if err != nil { +// t.Fatal(err) +// } +// +// } From 42af276f7a91bfe6ace2b08949d4e29e8f9d013d Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Tue, 13 Dec 2016 02:25:26 -0800 Subject: [PATCH 06/25] add marshal/unmarshal for dashboards --- bolt/internal/internal.go | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/bolt/internal/internal.go b/bolt/internal/internal.go index a705a69af..f847897cb 100644 --- a/bolt/internal/internal.go +++ b/bolt/internal/internal.go @@ -188,12 +188,43 @@ func UnmarshalLayout(data []byte, l *chronograf.Layout) error { return nil } +// MarshalDashboard encodes a dashboard to binary protobuf format. func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { - return proto.Marshal(&Dashboard{ + cells := make([]*DashboardCell, len(l.Cells)) + for i, c := range l.Cells { + cells[i] = &DashboardCell{ + X: c.X, + Y: c.Y, + W: c.W, + H: c.H, + Name: c.Name, + Queries: c.Queries, + Type: c.Type, + } + } + + return proto.Marshal(&Dashboard{ + ID: d.ID, + Cells: cells, + Name: d.Name, }) } +// UnmarshalDashboard decodes a layout from binary protobuf data. +func UnmarshalDashboard(data []byte, d *chonograf.Dashboard) error { + var pb Dashboard + if err := proto.Unmarshal(data, &pb); err != nil { + return err + } + + d.ID = pb.ID + d.Cells = pb.Cells + d.Name = pb.Name + + return nil +} + // ScopedAlert contains the source and the kapacitor id type ScopedAlert struct { chronograf.AlertRule From 07fa7a6df1122fdce587bb8ddd083f85138074d1 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Tue, 13 Dec 2016 02:44:19 -0800 Subject: [PATCH 07/25] add and get methods for dashboard --- bolt/dashboards.go | 43 +++++++++++++++++++++++++++++++++++++++++++ chronograf.go | 1 + 2 files changed, 44 insertions(+) diff --git a/bolt/dashboards.go b/bolt/dashboards.go index 8a8f170b2..bfd0dcde9 100644 --- a/bolt/dashboards.go +++ b/bolt/dashboards.go @@ -10,10 +10,13 @@ import ( var _ chronograf.DashboardsStore = &DashboardsStore{} +var DashboardBucket = []byte("Dashoard") + type DashboardsStore struct { client *Client } +// All returns all known dashboards func (s *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, error) { var srcs []chronograf.Dashboard if err := s.client.db.View(func(tx *bolt.Tx) error { @@ -34,3 +37,43 @@ func (s *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, erro return srcs, nil } + +// Add creates a new Dashboard in the DashboardsStore +func (d *DashboardsStore) Add(ctx context.Context, src chronograf.Dashboard) (chronograf.Dashboard, error) { + if err := d.client.db.Update(func(tx *bolt.Tx) error { + b := tx.Bucket(DashboardBucket) + id, err := d.IDs.Generate() + if err != nil { + return err + } + + src.ID = id + if v, err := internal.MarshalDashboard(src); err != nil { + return err + } else if err := b.Put([]byte(src.ID), v); err != nil { + return err + } + return nil + }); err != nil { + return chronograf.Dashboard{}, err + } + + return src, nil +} + +// Get returns a Dashboard if the id exists. +func (d *DashboardsStore) Get(ctx context.Context, id int) (chronograf.Dashboard, error) { + var src chronograf.Dashboard + if err := d.client.db.View(func(tx *bolt.Tx) error { + if v := tx.Bucket(LayoutBucket).Get([]byte(id)); v == nil { + return chronograf.ErrDashboardNotFound + } else if err := internal.UnmarshalDashboard(v, &src); err != nil { + return err + } + return nil + }); err != nil { + return chronograf.Dashboard{}, err + } + + return src, nil +} diff --git a/chronograf.go b/chronograf.go index 4118ef888..0c03f9de5 100644 --- a/chronograf.go +++ b/chronograf.go @@ -13,6 +13,7 @@ const ( ErrSourceNotFound = Error("source not found") ErrServerNotFound = Error("server not found") ErrLayoutNotFound = Error("layout not found") + ErrDashboardNotFound = Error("dashboard not found") ErrUserNotFound = Error("user not found") ErrLayoutInvalid = Error("layout is invalid") ErrAlertNotFound = Error("alert not found") From 4cd1037ce09dfa3dd735e47a3a78969562770040 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Tue, 13 Dec 2016 03:07:24 -0800 Subject: [PATCH 08/25] update internal.pb.go --- bolt/internal/internal.go | 10 +-- bolt/internal/internal.pb.go | 136 ++++++++++++++++++++++------------- bolt/internal/internal.proto | 18 ++++- server/dashboards_test.go | 15 ---- 4 files changed, 110 insertions(+), 69 deletions(-) delete mode 100644 server/dashboards_test.go diff --git a/bolt/internal/internal.go b/bolt/internal/internal.go index f847897cb..21ffd85af 100644 --- a/bolt/internal/internal.go +++ b/bolt/internal/internal.go @@ -190,10 +190,10 @@ func UnmarshalLayout(data []byte, l *chronograf.Layout) error { // MarshalDashboard encodes a dashboard to binary protobuf format. func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { - cells := make([]*DashboardCell, len(l.Cells)) - for i, c := range l.Cells { + cells := make([]*chronograf.DashboardCell, len(d.Cells)) + for i, c := range d.Cells { - cells[i] = &DashboardCell{ + cells[i] = &chronograf.DashboardCell{ X: c.X, Y: c.Y, W: c.W, @@ -205,14 +205,14 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { } return proto.Marshal(&Dashboard{ - ID: d.ID, + ID: int64(d.ID), Cells: cells, Name: d.Name, }) } // UnmarshalDashboard decodes a layout from binary protobuf data. -func UnmarshalDashboard(data []byte, d *chonograf.Dashboard) error { +func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error { var pb Dashboard if err := proto.Unmarshal(data, &pb); err != nil { return err diff --git a/bolt/internal/internal.pb.go b/bolt/internal/internal.pb.go index 35f695189..ee42d9213 100644 --- a/bolt/internal/internal.pb.go +++ b/bolt/internal/internal.pb.go @@ -11,6 +11,8 @@ It is generated from these files: It has these top-level messages: Exploration Source + Dashboard + DashboardCell Server Layout Cell @@ -67,6 +69,39 @@ func (m *Source) String() string { return proto.CompactTextString(m) func (*Source) ProtoMessage() {} func (*Source) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{1} } +type Dashboard struct { + ID int64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"` + Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"` + Cells []*DashboardCell `protobuf:"bytes,3,rep,name=cells" json:"cells,omitempty"` +} + +func (m *Dashboard) Reset() { *m = Dashboard{} } +func (m *Dashboard) String() string { return proto.CompactTextString(m) } +func (*Dashboard) ProtoMessage() {} +func (*Dashboard) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{2} } + +func (m *Dashboard) GetCells() []*DashboardCell { + if m != nil { + return m.Cells + } + return nil +} + +type DashboardCell struct { + X int32 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"` + Y int32 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"` + W int32 `protobuf:"varint,3,opt,name=w,proto3" json:"w,omitempty"` + H int32 `protobuf:"varint,4,opt,name=h,proto3" json:"h,omitempty"` + Queries []string `protobuf:"bytes,5,rep,name=queries" json:"queries,omitempty"` + Name string `protobuf:"bytes,7,opt,name=name,proto3" json:"name,omitempty"` + Type string `protobuf:"bytes,10,opt,name=type,proto3" json:"type,omitempty"` +} + +func (m *DashboardCell) Reset() { *m = DashboardCell{} } +func (m *DashboardCell) String() string { return proto.CompactTextString(m) } +func (*DashboardCell) ProtoMessage() {} +func (*DashboardCell) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{3} } + type Server struct { ID int64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"` Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"` @@ -79,7 +114,7 @@ type Server struct { func (m *Server) Reset() { *m = Server{} } func (m *Server) String() string { return proto.CompactTextString(m) } func (*Server) ProtoMessage() {} -func (*Server) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{2} } +func (*Server) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{4} } type Layout struct { ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` @@ -92,7 +127,7 @@ type Layout struct { func (m *Layout) Reset() { *m = Layout{} } func (m *Layout) String() string { return proto.CompactTextString(m) } func (*Layout) ProtoMessage() {} -func (*Layout) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{3} } +func (*Layout) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{5} } func (m *Layout) GetCells() []*Cell { if m != nil { @@ -117,7 +152,7 @@ type Cell struct { func (m *Cell) Reset() { *m = Cell{} } func (m *Cell) String() string { return proto.CompactTextString(m) } func (*Cell) ProtoMessage() {} -func (*Cell) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{4} } +func (*Cell) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{6} } func (m *Cell) GetQueries() []*Query { if m != nil { @@ -139,7 +174,7 @@ type Query struct { func (m *Query) Reset() { *m = Query{} } func (m *Query) String() string { return proto.CompactTextString(m) } func (*Query) ProtoMessage() {} -func (*Query) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{5} } +func (*Query) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{7} } func (m *Query) GetRange() *Range { if m != nil { @@ -156,7 +191,7 @@ type Range struct { func (m *Range) Reset() { *m = Range{} } func (m *Range) String() string { return proto.CompactTextString(m) } func (*Range) ProtoMessage() {} -func (*Range) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{6} } +func (*Range) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{8} } type AlertRule struct { ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` @@ -168,7 +203,7 @@ type AlertRule struct { func (m *AlertRule) Reset() { *m = AlertRule{} } func (m *AlertRule) String() string { return proto.CompactTextString(m) } func (*AlertRule) ProtoMessage() {} -func (*AlertRule) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{7} } +func (*AlertRule) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{9} } type User struct { ID uint64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"` @@ -178,11 +213,13 @@ type User struct { func (m *User) Reset() { *m = User{} } func (m *User) String() string { return proto.CompactTextString(m) } func (*User) ProtoMessage() {} -func (*User) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{8} } +func (*User) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{10} } func init() { proto.RegisterType((*Exploration)(nil), "internal.Exploration") proto.RegisterType((*Source)(nil), "internal.Source") + proto.RegisterType((*Dashboard)(nil), "internal.Dashboard") + proto.RegisterType((*DashboardCell)(nil), "internal.DashboardCell") proto.RegisterType((*Server)(nil), "internal.Server") proto.RegisterType((*Layout)(nil), "internal.Layout") proto.RegisterType((*Cell)(nil), "internal.Cell") @@ -195,45 +232,48 @@ func init() { func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) } var fileDescriptorInternal = []byte{ - // 636 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x94, 0x5f, 0x6e, 0xd3, 0x4e, - 0x10, 0xc7, 0xb5, 0xb1, 0x9d, 0xc4, 0xd3, 0x9f, 0xfa, 0x43, 0xab, 0x0a, 0x59, 0x88, 0x07, 0xcb, - 0x02, 0x29, 0x48, 0xa8, 0x0f, 0xf4, 0x04, 0x69, 0x5d, 0xa1, 0x40, 0x29, 0x65, 0xdb, 0x88, 0x27, - 0x1e, 0xb6, 0xcd, 0xb4, 0xb5, 0xe4, 0xd8, 0x66, 0x6d, 0x93, 0xfa, 0x0e, 0x9c, 0x81, 0x43, 0xc0, - 0x05, 0xb8, 0x03, 0x17, 0x42, 0x33, 0xbb, 0x4e, 0x82, 0xf8, 0xa3, 0xbe, 0xcd, 0x77, 0x66, 0x3c, - 0xfe, 0xcc, 0x1f, 0x1b, 0x76, 0xb3, 0xa2, 0x41, 0x53, 0xe8, 0x7c, 0xbf, 0x32, 0x65, 0x53, 0xca, - 0x71, 0xaf, 0x93, 0x6f, 0x02, 0x76, 0x8e, 0xef, 0xaa, 0xbc, 0x34, 0xba, 0xc9, 0xca, 0x42, 0xee, - 0xc2, 0x60, 0x96, 0x46, 0x22, 0x16, 0x13, 0x4f, 0x0d, 0x66, 0xa9, 0x94, 0xe0, 0x9f, 0xea, 0x25, - 0x46, 0x83, 0x58, 0x4c, 0x42, 0xc5, 0xb6, 0x7c, 0x08, 0xc3, 0x79, 0x8d, 0x66, 0x96, 0x46, 0x1e, - 0xe7, 0x39, 0x45, 0xb9, 0xa9, 0x6e, 0x74, 0xe4, 0xdb, 0x5c, 0xb2, 0xe5, 0x63, 0x08, 0x8f, 0x0c, - 0xea, 0x06, 0x17, 0xd3, 0x26, 0x0a, 0x38, 0x7d, 0xe3, 0xa0, 0xe8, 0xbc, 0x5a, 0xb8, 0xe8, 0xd0, - 0x46, 0xd7, 0x0e, 0x19, 0xc1, 0x28, 0xc5, 0x6b, 0xdd, 0xe6, 0x4d, 0x34, 0x8a, 0xc5, 0x64, 0xac, - 0x7a, 0x99, 0x7c, 0x17, 0x30, 0x3c, 0x2f, 0x5b, 0x73, 0x85, 0xf7, 0x02, 0x96, 0xe0, 0x5f, 0x74, - 0x15, 0x32, 0x6e, 0xa8, 0xd8, 0x96, 0x8f, 0x60, 0x4c, 0xd8, 0x05, 0xe5, 0x5a, 0xe0, 0xb5, 0xa6, - 0xd8, 0x99, 0xae, 0xeb, 0x55, 0x69, 0x16, 0xcc, 0x1c, 0xaa, 0xb5, 0x96, 0x0f, 0xc0, 0x9b, 0xab, - 0x13, 0x86, 0x0d, 0x15, 0x99, 0x7f, 0xc7, 0xa4, 0x3a, 0x17, 0x98, 0xe3, 0x8d, 0xd1, 0xd7, 0xd1, - 0xd8, 0xd6, 0xe9, 0x75, 0xf2, 0x99, 0x5a, 0x40, 0xf3, 0x09, 0xcd, 0xbd, 0x5a, 0xd8, 0xc6, 0xf5, - 0xfe, 0x81, 0xeb, 0xff, 0x19, 0x37, 0xd8, 0xe0, 0xee, 0x41, 0x70, 0x6e, 0xae, 0x66, 0xa9, 0x9b, - 0xb7, 0x15, 0xc9, 0x17, 0x01, 0xc3, 0x13, 0xdd, 0x95, 0x6d, 0xb3, 0x85, 0x13, 0x32, 0x4e, 0x0c, - 0x3b, 0xd3, 0xaa, 0xca, 0xb3, 0x2b, 0xbe, 0x10, 0x47, 0xb5, 0xed, 0xa2, 0x8c, 0x37, 0xa8, 0xeb, - 0xd6, 0xe0, 0x12, 0x8b, 0xc6, 0xf1, 0x6d, 0xbb, 0xe4, 0x13, 0x08, 0x8e, 0x30, 0xcf, 0xeb, 0xc8, - 0x8f, 0xbd, 0xc9, 0xce, 0x8b, 0xdd, 0xfd, 0xf5, 0x41, 0x92, 0x5b, 0xd9, 0x20, 0x35, 0x32, 0x6d, - 0x9b, 0xf2, 0x3a, 0x2f, 0x57, 0x4c, 0x3c, 0x56, 0x6b, 0x9d, 0xfc, 0x10, 0xe0, 0x53, 0x96, 0xfc, - 0x0f, 0xc4, 0x1d, 0xd3, 0x05, 0x4a, 0xdc, 0x91, 0xea, 0x18, 0x29, 0x50, 0xa2, 0x23, 0xb5, 0xe2, - 0xd7, 0x07, 0x4a, 0xac, 0x48, 0xdd, 0xf2, 0x40, 0x02, 0x25, 0x6e, 0xe5, 0x33, 0x18, 0x7d, 0x6c, - 0xd1, 0x64, 0x58, 0x47, 0x01, 0x43, 0xfc, 0xbf, 0x81, 0x78, 0xd7, 0xa2, 0xe9, 0x54, 0x1f, 0xa7, - 0x07, 0x33, 0xb7, 0x61, 0x91, 0xd1, 0x3a, 0x78, 0xec, 0x23, 0xbb, 0x0e, 0x1e, 0x79, 0x04, 0xa3, - 0xce, 0xe8, 0xe2, 0x06, 0xeb, 0x68, 0x1c, 0x7b, 0x13, 0x4f, 0xf5, 0x92, 0x23, 0xb9, 0xbe, 0xc4, - 0xbc, 0x8e, 0xc2, 0xd8, 0x9b, 0x84, 0xaa, 0x97, 0x54, 0xa7, 0xa1, 0x2b, 0x04, 0x5b, 0x87, 0xec, - 0xe4, 0xab, 0x80, 0x80, 0x5f, 0x4e, 0xcf, 0x1d, 0x95, 0xcb, 0xa5, 0x2e, 0x16, 0x6e, 0xf4, 0xbd, - 0xa4, 0x7d, 0xa4, 0x87, 0x6e, 0xec, 0x83, 0xf4, 0x90, 0xb4, 0x3a, 0x73, 0x43, 0x1e, 0xa8, 0x33, - 0x9a, 0xda, 0x4b, 0x53, 0xb6, 0xd5, 0x61, 0x67, 0xc7, 0x1b, 0xaa, 0xb5, 0xa6, 0x4f, 0xf5, 0xfd, - 0x2d, 0x1a, 0xd7, 0x73, 0xa8, 0x9c, 0xa2, 0x23, 0x38, 0x21, 0x2a, 0xd7, 0xa5, 0x15, 0xf2, 0x29, - 0x04, 0x8a, 0xba, 0xe0, 0x56, 0x7f, 0x19, 0x10, 0xbb, 0x95, 0x8d, 0x26, 0x07, 0x2e, 0x8d, 0xaa, - 0xcc, 0xab, 0x0a, 0x8d, 0xbb, 0x5d, 0x2b, 0xb8, 0x76, 0xb9, 0x42, 0xc3, 0xc8, 0x9e, 0xb2, 0x22, - 0xf9, 0x00, 0xe1, 0x34, 0x47, 0xd3, 0xa8, 0x36, 0xc7, 0xdf, 0x4e, 0x4c, 0x82, 0xff, 0xea, 0xfc, - 0xed, 0x69, 0x7f, 0xf1, 0x64, 0x6f, 0xee, 0xd4, 0xdb, 0xba, 0x53, 0x6a, 0xe8, 0xb5, 0xae, 0xf4, - 0x2c, 0xe5, 0xc5, 0x7a, 0xca, 0xa9, 0xe4, 0x39, 0xf8, 0xf4, 0x3d, 0x6c, 0x55, 0xf6, 0xb9, 0xf2, - 0x1e, 0x04, 0xc7, 0x4b, 0x9d, 0xe5, 0xae, 0xb4, 0x15, 0x97, 0x43, 0xfe, 0x0d, 0x1e, 0xfc, 0x0c, - 0x00, 0x00, 0xff, 0xff, 0x92, 0x9e, 0x41, 0x68, 0x18, 0x05, 0x00, 0x00, + // 688 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x94, 0x51, 0x6e, 0xd3, 0x4c, + 0x10, 0xc7, 0xb5, 0xb1, 0x9d, 0xc4, 0x93, 0x7e, 0xfd, 0xd0, 0xaa, 0x02, 0x0b, 0xf1, 0x60, 0x59, + 0x20, 0x05, 0x09, 0xfa, 0xd0, 0x9e, 0x20, 0x8d, 0x2b, 0x14, 0x28, 0xa5, 0x6c, 0x1b, 0xf1, 0x04, + 0xd2, 0x36, 0xd9, 0x36, 0x96, 0x36, 0xb6, 0x59, 0xdb, 0xa4, 0x3e, 0x02, 0x12, 0x67, 0xe0, 0x10, + 0x70, 0x01, 0xee, 0xc0, 0x85, 0xd0, 0xec, 0xae, 0x9d, 0x54, 0x14, 0x14, 0x89, 0xb7, 0xfd, 0xed, + 0x8c, 0xc7, 0xff, 0x99, 0xff, 0xd8, 0xb0, 0x9b, 0xa4, 0xa5, 0x50, 0x29, 0x97, 0xfb, 0xb9, 0xca, + 0xca, 0x8c, 0xf6, 0x1b, 0x8e, 0xbe, 0x13, 0x18, 0x1c, 0xdf, 0xe4, 0x32, 0x53, 0xbc, 0x4c, 0xb2, + 0x94, 0xee, 0x42, 0x67, 0x12, 0x07, 0x24, 0x24, 0x43, 0x87, 0x75, 0x26, 0x31, 0xa5, 0xe0, 0x9e, + 0xf2, 0xa5, 0x08, 0x3a, 0x21, 0x19, 0xfa, 0x4c, 0x9f, 0xe9, 0x7d, 0xe8, 0x4e, 0x0b, 0xa1, 0x26, + 0x71, 0xe0, 0xe8, 0x3c, 0x4b, 0x98, 0x1b, 0xf3, 0x92, 0x07, 0xae, 0xc9, 0xc5, 0x33, 0x7d, 0x04, + 0xfe, 0x58, 0x09, 0x5e, 0x8a, 0xf9, 0xa8, 0x0c, 0x3c, 0x9d, 0xbe, 0xbe, 0xc0, 0xe8, 0x34, 0x9f, + 0xdb, 0x68, 0xd7, 0x44, 0xdb, 0x0b, 0x1a, 0x40, 0x2f, 0x16, 0x57, 0xbc, 0x92, 0x65, 0xd0, 0x0b, + 0xc9, 0xb0, 0xcf, 0x1a, 0x8c, 0x7e, 0x10, 0xe8, 0x9e, 0x67, 0x95, 0x9a, 0x89, 0xad, 0x04, 0x53, + 0x70, 0x2f, 0xea, 0x5c, 0x68, 0xb9, 0x3e, 0xd3, 0x67, 0xfa, 0x10, 0xfa, 0x28, 0x3b, 0xc5, 0x5c, + 0x23, 0xb8, 0x65, 0x8c, 0x9d, 0xf1, 0xa2, 0x58, 0x65, 0x6a, 0xae, 0x35, 0xfb, 0xac, 0x65, 0x7a, + 0x0f, 0x9c, 0x29, 0x3b, 0xd1, 0x62, 0x7d, 0x86, 0xc7, 0x3f, 0xcb, 0xc4, 0x3a, 0x17, 0x42, 0x8a, + 0x6b, 0xc5, 0xaf, 0x82, 0xbe, 0xa9, 0xd3, 0x70, 0xf4, 0x01, 0xfc, 0x98, 0x17, 0x8b, 0xcb, 0x8c, + 0xab, 0xf9, 0x56, 0x4d, 0x3c, 0x07, 0x6f, 0x26, 0xa4, 0x2c, 0x02, 0x27, 0x74, 0x86, 0x83, 0x83, + 0x07, 0xfb, 0xad, 0xa7, 0x6d, 0x9d, 0xb1, 0x90, 0x92, 0x99, 0xac, 0xe8, 0x33, 0x81, 0xff, 0x6e, + 0x05, 0xe8, 0x0e, 0x90, 0x1b, 0xfd, 0x0e, 0x8f, 0x91, 0x1b, 0xa4, 0x5a, 0xd7, 0xf7, 0x18, 0xa9, + 0x91, 0x56, 0x7a, 0x3c, 0x1e, 0x23, 0x2b, 0xa4, 0x85, 0x1e, 0x8a, 0xc7, 0xc8, 0x02, 0xfb, 0xfb, + 0x58, 0x09, 0x95, 0x88, 0x22, 0xf0, 0x42, 0x67, 0xe8, 0xb3, 0x06, 0x51, 0xa6, 0x9e, 0x5f, 0xcf, + 0xc8, 0x4c, 0xed, 0xac, 0x4b, 0x9c, 0x35, 0x98, 0x3b, 0x3c, 0x47, 0x5f, 0xd0, 0x2e, 0xa1, 0x3e, + 0x09, 0xb5, 0x55, 0xa7, 0x9b, 0xd6, 0x38, 0x7f, 0xb1, 0xc6, 0xbd, 0xdb, 0x1a, 0x6f, 0x6d, 0xcd, + 0x1e, 0x78, 0xe7, 0x6a, 0x36, 0x89, 0xed, 0x6e, 0x19, 0x88, 0xbe, 0x12, 0xe8, 0x9e, 0xf0, 0x3a, + 0xab, 0xca, 0x0d, 0x39, 0xbe, 0x96, 0x13, 0xc2, 0x60, 0x94, 0xe7, 0x32, 0x99, 0xe9, 0xaf, 0xc1, + 0xaa, 0xda, 0xbc, 0xc2, 0x8c, 0xd7, 0x82, 0x17, 0x95, 0x12, 0x4b, 0x91, 0x96, 0x56, 0xdf, 0xe6, + 0x15, 0x7d, 0x0c, 0xde, 0x58, 0x1b, 0xe5, 0x6a, 0xa3, 0x76, 0xd7, 0x46, 0x19, 0x7f, 0x74, 0x10, + 0x1b, 0x19, 0x55, 0x65, 0x76, 0x25, 0xb3, 0x95, 0x56, 0xdc, 0x67, 0x2d, 0x47, 0x3f, 0x09, 0xb8, + 0xff, 0x64, 0xd9, 0xd3, 0xdb, 0x96, 0x0d, 0x0e, 0xfe, 0x5f, 0x8b, 0x78, 0x5b, 0x09, 0x55, 0xaf, + 0x3d, 0xdc, 0x01, 0x92, 0xd8, 0x6d, 0x26, 0xc9, 0x9d, 0x8e, 0x06, 0xd0, 0xab, 0x15, 0x4f, 0xaf, + 0x45, 0x11, 0xf4, 0x43, 0x67, 0xe8, 0xb0, 0x06, 0x75, 0x44, 0xf2, 0x4b, 0x21, 0x8b, 0xc0, 0x37, + 0x9b, 0x61, 0xf1, 0xce, 0x2d, 0xf8, 0x46, 0xc0, 0xd3, 0x2f, 0xc7, 0xe7, 0xc6, 0xd9, 0x72, 0xc9, + 0xd3, 0xb9, 0x1d, 0x7d, 0x83, 0xe8, 0x47, 0x7c, 0x64, 0xc7, 0xde, 0x89, 0x8f, 0x90, 0xd9, 0x99, + 0x1d, 0x72, 0x87, 0x9d, 0xe1, 0xd4, 0x5e, 0xa8, 0xac, 0xca, 0x8f, 0x6a, 0x33, 0x5e, 0x9f, 0xb5, + 0x8c, 0xbf, 0xa5, 0x77, 0x0b, 0xa1, 0xda, 0x35, 0xb5, 0x84, 0x4b, 0x70, 0x82, 0xaa, 0x6c, 0x97, + 0x06, 0xe8, 0x13, 0xf0, 0x18, 0x76, 0xa1, 0x5b, 0xbd, 0x35, 0x20, 0x7d, 0xcd, 0x4c, 0x34, 0x3a, + 0xb4, 0x69, 0x58, 0x65, 0x9a, 0xe7, 0x42, 0xd9, 0xdd, 0x35, 0xa0, 0x6b, 0x67, 0x2b, 0xa1, 0xb4, + 0x64, 0x87, 0x19, 0x88, 0xde, 0x83, 0x3f, 0x92, 0x42, 0x95, 0xac, 0x92, 0xe2, 0xb7, 0x15, 0xa3, + 0xe0, 0xbe, 0x3c, 0x7f, 0x73, 0xda, 0x6c, 0x3c, 0x9e, 0xd7, 0x7b, 0xea, 0x6c, 0xec, 0x29, 0x36, + 0xf4, 0x8a, 0xe7, 0x7c, 0x12, 0x6b, 0x63, 0x1d, 0x66, 0x29, 0x7a, 0x06, 0x2e, 0x7e, 0x0f, 0x1b, + 0x95, 0x5d, 0x5d, 0x79, 0x0f, 0xbc, 0xe3, 0x25, 0x4f, 0xa4, 0x2d, 0x6d, 0xe0, 0xb2, 0xab, 0x7f, + 0xf9, 0x87, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xf6, 0x0c, 0x35, 0x69, 0x04, 0x06, 0x00, 0x00, } diff --git a/bolt/internal/internal.proto b/bolt/internal/internal.proto index 5874f0838..269c54241 100644 --- a/bolt/internal/internal.proto +++ b/bolt/internal/internal.proto @@ -22,6 +22,22 @@ message Source { string Telegraf = 8; // Telegraf is the db telegraf is written to. By default it is "telegraf" } +message Dashboard { + int64 ID = 1; // ID is the unique ID of the dashboard + string Name = 2; // Name is the user-defined name of the dashboard + repeated DashboardCell cells = 3; // a representation of all visual data required for rendering the dashboard +} + +message DashboardCell { + int32 x = 1; // X-coordinate of Cell in the Dashboard + int32 y = 2; // Y-coordinate of Cell in the Dashboard + int32 w = 3; // Width of Cell in the Dashboard + int32 h = 4; // Height of Cell in the Dashboard + repeated string queries = 5; // Time-series data queries for Dashboard + string name = 7; // User-facing name for this Dashboard + string type = 10; // Dashboard visualization type +} + message Server { int64 ID = 1; // ID is the unique ID of the server string Name = 2; // Name is the user-defined name for the server @@ -59,7 +75,7 @@ message Query { repeated string GroupBys= 4; // GroupBys define the groups to combine in the query repeated string Wheres = 5; // Wheres define the restrictions on the query string Label = 6; // Label is the name of the Y-Axis - Range Range = 7; // Range is the upper and lower bound of the Y-Axis + Range Range = 7; // Range is the upper and lower bound of the Y-Axis } message Range { diff --git a/server/dashboards_test.go b/server/dashboards_test.go deleted file mode 100644 index 52d3a3fbe..000000000 --- a/server/dashboards_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package handlers -// -// import ( -// "net/http" -// "testing" -// ) -// -// func TestDashboards(t *testing.T) { -// -// _, err := http.NewRequest("GET", "/chronograf/v1/dashbords", nil) -// if err != nil { -// t.Fatal(err) -// } -// -// } From aeefafdc29c3a605bd9e020f2a6f6fa92ca10e82 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Tue, 13 Dec 2016 16:19:42 -0800 Subject: [PATCH 09/25] fix issues in dashboards internal --- bolt/internal/internal.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/bolt/internal/internal.go b/bolt/internal/internal.go index 21ffd85af..0390ea9b0 100644 --- a/bolt/internal/internal.go +++ b/bolt/internal/internal.go @@ -190,10 +190,10 @@ func UnmarshalLayout(data []byte, l *chronograf.Layout) error { // MarshalDashboard encodes a dashboard to binary protobuf format. func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { - cells := make([]*chronograf.DashboardCell, len(d.Cells)) + cells := make([]*DashboardCell, len(d.Cells)) for i, c := range d.Cells { - cells[i] = &chronograf.DashboardCell{ + cells[i] = &DashboardCell{ X: c.X, Y: c.Y, W: c.W, @@ -218,8 +218,21 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error { return err } - d.ID = pb.ID - d.Cells = pb.Cells + cells := make([]chronograf.DashboardCell, len(d.Cells)) + for i, c := range d.Cells { + cells[i] = chronograf.DashboardCell{ + X: c.X, + Y: c.Y, + W: c.W, + H: c.H, + Name: c.Name, + Queries: c.Queries, + Type: c.Type, + } + } + + d.ID = chronograf.DashboardID(pb.ID) + d.Cells = cells d.Name = pb.Name return nil From ccf93b4781ab10167d0fe09c62056448b0d1151e Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Tue, 13 Dec 2016 22:57:52 -0800 Subject: [PATCH 10/25] fix errors --- bolt/dashboards.go | 37 ++++++++++++++++++++++++++++--------- chronograf.go | 6 +++--- server/dashboards.go | 10 ++++++++++ 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/bolt/dashboards.go b/bolt/dashboards.go index bfd0dcde9..774852668 100644 --- a/bolt/dashboards.go +++ b/bolt/dashboards.go @@ -2,18 +2,21 @@ package bolt import ( "context" + "strconv" "github.com/boltdb/bolt" "github.com/influxdata/chronograf" "github.com/influxdata/chronograf/bolt/internal" ) +// Ensure DashboardsStore implements chronograf.DashboardsStore. var _ chronograf.DashboardsStore = &DashboardsStore{} var DashboardBucket = []byte("Dashoard") type DashboardsStore struct { client *Client + IDs chronograf.DashboardID } // All returns all known dashboards @@ -21,7 +24,7 @@ func (s *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, erro var srcs []chronograf.Dashboard if err := s.client.db.View(func(tx *bolt.Tx) error { if err := tx.Bucket(DashboardBucket).ForEach(func(k, v []byte) error { - var src chonograf.Dashboard + var src chronograf.Dashboard if err := internal.UnmarshalDashboard(v, &src); err != nil { return err } @@ -39,7 +42,7 @@ func (s *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, erro } // Add creates a new Dashboard in the DashboardsStore -func (d *DashboardsStore) Add(ctx context.Context, src chronograf.Dashboard) (chronograf.Dashboard, error) { +func (d *DashboardsStore) Add(ctx context.Context, src *chronograf.Dashboard) (*chronograf.Dashboard, error) { if err := d.client.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(DashboardBucket) id, err := d.IDs.Generate() @@ -48,32 +51,48 @@ func (d *DashboardsStore) Add(ctx context.Context, src chronograf.Dashboard) (ch } src.ID = id - if v, err := internal.MarshalDashboard(src); err != nil { + strID := strconv.Itoa(int(id)) + if v, err := internal.MarshalDashboard(*src); err != nil { return err - } else if err := b.Put([]byte(src.ID), v); err != nil { + } else if err := b.Put([]byte(strID), v); err != nil { return err } return nil }); err != nil { - return chronograf.Dashboard{}, err + return &chronograf.Dashboard{}, err } return src, nil } // Get returns a Dashboard if the id exists. -func (d *DashboardsStore) Get(ctx context.Context, id int) (chronograf.Dashboard, error) { +func (d *DashboardsStore) Get(ctx context.Context, id chronograf.DashboardID) (*chronograf.Dashboard, error) { var src chronograf.Dashboard if err := d.client.db.View(func(tx *bolt.Tx) error { - if v := tx.Bucket(LayoutBucket).Get([]byte(id)); v == nil { + strID := strconv.Itoa(int(id)) + if v := tx.Bucket(DashboardBucket).Get([]byte(strID)); v == nil { return chronograf.ErrDashboardNotFound } else if err := internal.UnmarshalDashboard(v, &src); err != nil { return err } return nil }); err != nil { - return chronograf.Dashboard{}, err + return &chronograf.Dashboard{}, err } - return src, nil + return &src, nil +} + +// Delete the dashboard from DashboardsStore +func (s *DashboardsStore) Delete(ctx context.Context, d chronograf.Dashboard) error { + if err := s.client.db.Update(func(tx *bolt.Tx) error { + if err := tx.Bucket(DashboardBucket).Delete(itob(int(d.ID))); err != nil { + return err + } + return nil + }); err != nil { + return err + } + + return nil } diff --git a/chronograf.go b/chronograf.go index 0c03f9de5..72a9eb67b 100644 --- a/chronograf.go +++ b/chronograf.go @@ -249,10 +249,10 @@ type DashboardCell struct { type DashboardsStore interface { // Create a new Dashboard in the DashboardStore Add(context.Context, *Dashboard) (*Dashboard, error) - // Delete the Dashboard from the DashboardStore - Delete(context.Context, *Dashboard) error + // Delete the Dashboard from the DashboardStore if `ID` exists. + Delete(context.Context, Dashboard) error // Get retrieves a dashboard if `ID` exists. - Get(ctx context.Context, ID DashboardID) (*Dashboard, error) + Get(ctx context.Context, id DashboardID) (*Dashboard, error) // Update replaces the dashboard information Update(context.Context, *Dashboard) error } diff --git a/server/dashboards.go b/server/dashboards.go index 76bfb25b5..2dd457d3a 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -11,6 +11,10 @@ type dashboardResponse struct { Links dashboardLinks `json:"links"` } +type getDashboardsResponse struct { + Dashboards []ldashboardResponse `json:"dashboards"` +} + func newDashboardResponse(d *chronograf.Dashboard) dashboardResponse { base := "/chronograf/v1/dashboards" return dashboardResponse{ @@ -23,7 +27,13 @@ func newDashboardResponse(d *chronograf.Dashboard) dashboardResponse { // Dashboards returns all dashboards within the store func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) { + dashboards, err := s.DashboardsStore.All(ctx) + if err != nil { + Error(w, http.StatusInternalServerError, "Error loading layouts", s.Logger) + return + } + encodeJSON(w, http.StatusOK, getDashboardsResponse{Dashboards: []dashboardResponse{}}, s.Logger) } // DashboardID returns a single specified dashboard From cd627b47ffab7ddaa30edd5ff03b567709d62dd4 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Tue, 13 Dec 2016 23:22:54 -0800 Subject: [PATCH 11/25] wow did it actually just compile? --- bolt/dashboards.go | 14 ++++++++------ chronograf.go | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/bolt/dashboards.go b/bolt/dashboards.go index 774852668..67b17c978 100644 --- a/bolt/dashboards.go +++ b/bolt/dashboards.go @@ -45,12 +45,9 @@ func (s *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, erro func (d *DashboardsStore) Add(ctx context.Context, src *chronograf.Dashboard) (*chronograf.Dashboard, error) { if err := d.client.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(DashboardBucket) - id, err := d.IDs.Generate() - if err != nil { - return err - } + id, _ := b.NextSequence() - src.ID = id + src.ID = chronograf.DashboardID(id) strID := strconv.Itoa(int(id)) if v, err := internal.MarshalDashboard(*src); err != nil { return err @@ -84,7 +81,7 @@ func (d *DashboardsStore) Get(ctx context.Context, id chronograf.DashboardID) (* } // Delete the dashboard from DashboardsStore -func (s *DashboardsStore) Delete(ctx context.Context, d chronograf.Dashboard) error { +func (s *DashboardsStore) Delete(ctx context.Context, d *chronograf.Dashboard) error { if err := s.client.db.Update(func(tx *bolt.Tx) error { if err := tx.Bucket(DashboardBucket).Delete(itob(int(d.ID))); err != nil { return err @@ -96,3 +93,8 @@ func (s *DashboardsStore) Delete(ctx context.Context, d chronograf.Dashboard) er return nil } + +// Update the dashboard in DashboardsStore +func (s *DashboardsStore) Update(ctx context.Context, d *chronograf.Dashboard) error { + return nil +} diff --git a/chronograf.go b/chronograf.go index 72a9eb67b..4e541eee0 100644 --- a/chronograf.go +++ b/chronograf.go @@ -250,7 +250,7 @@ type DashboardsStore interface { // Create a new Dashboard in the DashboardStore Add(context.Context, *Dashboard) (*Dashboard, error) // Delete the Dashboard from the DashboardStore if `ID` exists. - Delete(context.Context, Dashboard) error + Delete(context.Context, *Dashboard) error // Get retrieves a dashboard if `ID` exists. Get(ctx context.Context, id DashboardID) (*Dashboard, error) // Update replaces the dashboard information From 8f939f8fbf0748a2bbba3fb333510b679f6d219b Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Tue, 13 Dec 2016 23:56:26 -0800 Subject: [PATCH 12/25] omg it compiled --- bolt/dashboards.go | 4 ++-- chronograf.go | 1 + server/dashboards.go | 26 ++++++++++++++++++++------ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/bolt/dashboards.go b/bolt/dashboards.go index 67b17c978..81d3b95be 100644 --- a/bolt/dashboards.go +++ b/bolt/dashboards.go @@ -20,9 +20,9 @@ type DashboardsStore struct { } // All returns all known dashboards -func (s *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, error) { +func (d *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, error) { var srcs []chronograf.Dashboard - if err := s.client.db.View(func(tx *bolt.Tx) error { + if err := d.client.db.View(func(tx *bolt.Tx) error { if err := tx.Bucket(DashboardBucket).ForEach(func(k, v []byte) error { var src chronograf.Dashboard if err := internal.UnmarshalDashboard(v, &src); err != nil { diff --git a/chronograf.go b/chronograf.go index 4e541eee0..96a9de27e 100644 --- a/chronograf.go +++ b/chronograf.go @@ -247,6 +247,7 @@ type DashboardCell struct { // DashboardsStore is the storage and retrieval of dashboards type DashboardsStore interface { + All(context.Context) ([]Dashboard, error) // Create a new Dashboard in the DashboardStore Add(context.Context, *Dashboard) (*Dashboard, error) // Delete the Dashboard from the DashboardStore if `ID` exists. diff --git a/server/dashboards.go b/server/dashboards.go index 2dd457d3a..f0e307d76 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -1,39 +1,53 @@ package server -import "net/http" +import ( + "fmt" + "net/http" + + "github.com/influxdata/chronograf" +) type dashboardLinks struct { Self string `json:"self"` // Self link mapping to this resource } type dashboardResponse struct { - *chronograf.Dashboard + chronograf.Dashboard Links dashboardLinks `json:"links"` } type getDashboardsResponse struct { - Dashboards []ldashboardResponse `json:"dashboards"` + Dashboards []dashboardResponse `json:"dashboards"` } -func newDashboardResponse(d *chronograf.Dashboard) dashboardResponse { +func newDashboardResponse(d chronograf.Dashboard) dashboardResponse { base := "/chronograf/v1/dashboards" return dashboardResponse{ Dashboard: d, Links: dashboardLinks{ Self: fmt.Sprintf("%s/%d", base, d.ID), - } + }, } } // Dashboards returns all dashboards within the store func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() dashboards, err := s.DashboardsStore.All(ctx) if err != nil { Error(w, http.StatusInternalServerError, "Error loading layouts", s.Logger) return } - encodeJSON(w, http.StatusOK, getDashboardsResponse{Dashboards: []dashboardResponse{}}, s.Logger) + res := getDashboardsResponse{ + Dashboards: []dashboardResponse{}, + } + + for _, dashboard := range dashboards { + res.Dashboards = append(res.Dashboards, newDashboardResponse(dashboard)) + } + + encodeJSON(w, http.StatusOK, res, s.Logger) } // DashboardID returns a single specified dashboard From 43464f6008b3a0ad6248ee544b604d609c8ce5b2 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Wed, 14 Dec 2016 00:12:36 -0800 Subject: [PATCH 13/25] add update func to dashboards --- bolt/dashboards.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/bolt/dashboards.go b/bolt/dashboards.go index 81d3b95be..14f83b501 100644 --- a/bolt/dashboards.go +++ b/bolt/dashboards.go @@ -96,5 +96,23 @@ func (s *DashboardsStore) Delete(ctx context.Context, d *chronograf.Dashboard) e // Update the dashboard in DashboardsStore func (s *DashboardsStore) Update(ctx context.Context, d *chronograf.Dashboard) error { + if err := s.client.db.Update(func(tx *bolt.Tx) error { + // Get an existing dashboard with the same ID. + b := tx.Bucket(DashboardBucket) + strID := strconv.Itoa(int(d.ID)) + if v := b.Get([]byte(strID)); v == nil { + return chronograf.ErrDashboardNotFound + } + + if v, err := internal.MarshalDashboard(*d); err != nil { + return err + } else if err := b.Put([]byte(strID), v); err != nil { + return err + } + return nil + }); err != nil { + return err + } + return nil } From 7986ecce3ff531a3863744640eaad0151c8a0f0c Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Wed, 14 Dec 2016 09:37:47 -0800 Subject: [PATCH 14/25] add dashboard GET and DELETE handlers --- server/dashboards.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/server/dashboards.go b/server/dashboards.go index f0e307d76..807710982 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -52,9 +52,28 @@ func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) { // DashboardID returns a single specified dashboard func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) { + id, err := paramID("id", r) + if err != nil { + Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) + return + } + ctx := r.Context() + e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id)) + if err != nil { + notFound(w, id, s.Logger) + return + } + + res := newDashboardResponse(e) + encodeJSON(w, http.StatusOK, res, s.Logger) } +// type postDashboardRequest struct { +// Data interface{} `json:"data"` // Serialization of config. +// Name string `json:"name,omitempty"` // Exploration name given by user. +// } + // NewDashboard creates and returns a new dashboard object func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) { @@ -62,7 +81,24 @@ func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) { // RemoveDashboard deletes a dashboard func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) { + id, err := paramID("id", r) + if err != nil { + Error(w, http.StatusUnprocessableEntity, err.Error(), h.Logger) + return + } + ctx := r.Context() + e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id)) + if err != nil { + notFound(w, id, s.Logger) + return + } + + if err := s.DashboardsStore.Delete(ctx, &chronograf.Dashboard{ID: chronograf.DashboardID(id)}); err != nil { + unknownErrorWithMessage(w, err, s.Logger) + return + } + w.WriteHeader(http.StatusNoContent) } // UpdateDashboard updates a dashboard From 8bc8ba151e9d13171d3a98ebccdd7b7383100268 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Wed, 14 Dec 2016 12:12:20 -0800 Subject: [PATCH 15/25] formatting --- bolt/dashboards.go | 90 +++++++++++++++++++-------------------- bolt/internal/internal.go | 10 ++--- chronograf.go | 18 ++++---- server/dashboards.go | 80 +++++++++++++++++----------------- server/service.go | 2 +- 5 files changed, 100 insertions(+), 100 deletions(-) diff --git a/bolt/dashboards.go b/bolt/dashboards.go index 14f83b501..8bf58b583 100644 --- a/bolt/dashboards.go +++ b/bolt/dashboards.go @@ -1,12 +1,12 @@ package bolt import ( - "context" - "strconv" + "context" + "strconv" - "github.com/boltdb/bolt" - "github.com/influxdata/chronograf" - "github.com/influxdata/chronograf/bolt/internal" + "github.com/boltdb/bolt" + "github.com/influxdata/chronograf" + "github.com/influxdata/chronograf/bolt/internal" ) // Ensure DashboardsStore implements chronograf.DashboardsStore. @@ -15,40 +15,40 @@ var _ chronograf.DashboardsStore = &DashboardsStore{} var DashboardBucket = []byte("Dashoard") type DashboardsStore struct { - client *Client - IDs chronograf.DashboardID + client *Client + IDs chronograf.DashboardID } // All returns all known dashboards func (d *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, error) { - var srcs []chronograf.Dashboard - if err := d.client.db.View(func(tx *bolt.Tx) error { - if err := tx.Bucket(DashboardBucket).ForEach(func(k, v []byte) error { - var src chronograf.Dashboard - if err := internal.UnmarshalDashboard(v, &src); err != nil { - return err - } - srcs = append(srcs, src) - return nil - }); err != nil { - return err - } - return nil - }); err != nil { - return nil, err - } + var srcs []chronograf.Dashboard + if err := d.client.db.View(func(tx *bolt.Tx) error { + if err := tx.Bucket(DashboardBucket).ForEach(func(k, v []byte) error { + var src chronograf.Dashboard + if err := internal.UnmarshalDashboard(v, &src); err != nil { + return err + } + srcs = append(srcs, src) + return nil + }); err != nil { + return err + } + return nil + }); err != nil { + return nil, err + } - return srcs, nil + return srcs, nil } // Add creates a new Dashboard in the DashboardsStore func (d *DashboardsStore) Add(ctx context.Context, src *chronograf.Dashboard) (*chronograf.Dashboard, error) { - if err := d.client.db.Update(func(tx *bolt.Tx) error { + if err := d.client.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(DashboardBucket) id, _ := b.NextSequence() src.ID = chronograf.DashboardID(id) - strID := strconv.Itoa(int(id)) + strID := strconv.Itoa(int(id)) if v, err := internal.MarshalDashboard(*src); err != nil { return err } else if err := b.Put([]byte(strID), v); err != nil { @@ -66,7 +66,7 @@ func (d *DashboardsStore) Add(ctx context.Context, src *chronograf.Dashboard) (* func (d *DashboardsStore) Get(ctx context.Context, id chronograf.DashboardID) (*chronograf.Dashboard, error) { var src chronograf.Dashboard if err := d.client.db.View(func(tx *bolt.Tx) error { - strID := strconv.Itoa(int(id)) + strID := strconv.Itoa(int(id)) if v := tx.Bucket(DashboardBucket).Get([]byte(strID)); v == nil { return chronograf.ErrDashboardNotFound } else if err := internal.UnmarshalDashboard(v, &src); err != nil { @@ -82,7 +82,7 @@ func (d *DashboardsStore) Get(ctx context.Context, id chronograf.DashboardID) (* // Delete the dashboard from DashboardsStore func (s *DashboardsStore) Delete(ctx context.Context, d *chronograf.Dashboard) error { - if err := s.client.db.Update(func(tx *bolt.Tx) error { + if err := s.client.db.Update(func(tx *bolt.Tx) error { if err := tx.Bucket(DashboardBucket).Delete(itob(int(d.ID))); err != nil { return err } @@ -96,23 +96,23 @@ func (s *DashboardsStore) Delete(ctx context.Context, d *chronograf.Dashboard) e // Update the dashboard in DashboardsStore func (s *DashboardsStore) Update(ctx context.Context, d *chronograf.Dashboard) error { - if err := s.client.db.Update(func(tx *bolt.Tx) error { - // Get an existing dashboard with the same ID. - b := tx.Bucket(DashboardBucket) - strID := strconv.Itoa(int(d.ID)) - if v := b.Get([]byte(strID)); v == nil { - return chronograf.ErrDashboardNotFound - } + if err := s.client.db.Update(func(tx *bolt.Tx) error { + // Get an existing dashboard with the same ID. + b := tx.Bucket(DashboardBucket) + strID := strconv.Itoa(int(d.ID)) + if v := b.Get([]byte(strID)); v == nil { + return chronograf.ErrDashboardNotFound + } - if v, err := internal.MarshalDashboard(*d); err != nil { - return err - } else if err := b.Put([]byte(strID), v); err != nil { - return err - } - return nil - }); err != nil { - return err - } + if v, err := internal.MarshalDashboard(*d); err != nil { + return err + } else if err := b.Put([]byte(strID), v); err != nil { + return err + } + return nil + }); err != nil { + return err + } - return nil + return nil } diff --git a/bolt/internal/internal.go b/bolt/internal/internal.go index 0390ea9b0..b83baa2bd 100644 --- a/bolt/internal/internal.go +++ b/bolt/internal/internal.go @@ -205,9 +205,9 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { } return proto.Marshal(&Dashboard{ - ID: int64(d.ID), - Cells: cells, - Name: d.Name, + ID: int64(d.ID), + Cells: cells, + Name: d.Name, }) } @@ -231,9 +231,9 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error { } } - d.ID = chronograf.DashboardID(pb.ID) + d.ID = chronograf.DashboardID(pb.ID) d.Cells = cells - d.Name = pb.Name + d.Name = pb.Name return nil } diff --git a/chronograf.go b/chronograf.go index 96a9de27e..dc7731ca4 100644 --- a/chronograf.go +++ b/chronograf.go @@ -229,20 +229,20 @@ type DashboardID int // Dashboard represents all visual and query data for a dashboard type Dashboard struct { - ID DashboardID `json:"id"` + ID DashboardID `json:"id"` Cells []DashboardCell `json:"cells"` - Name string `json:"name"` + Name string `json:"name"` } // DashboardCell holds visual and query information for a cell type DashboardCell struct { - X int32 `json:"x"` - Y int32 `json:"y"` - W int32 `json:"w"` - H int32 `json:"h"` - Name string `json:"name"` + X int32 `json:"x"` + Y int32 `json:"y"` + W int32 `json:"w"` + H int32 `json:"h"` + Name string `json:"name"` Queries []string `json:"queries"` - Type string `json:"type"` + Type string `json:"type"` } // DashboardsStore is the storage and retrieval of dashboards @@ -295,7 +295,7 @@ type Cell struct { I string `json:"i"` Name string `json:"name"` Queries []Query `json:"queries"` - Type string `json:"type"` + Type string `json:"type"` } // Layout is a collection of Cells for visualization diff --git a/server/dashboards.go b/server/dashboards.go index 807710982..ee2308a3b 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -1,19 +1,19 @@ package server import ( - "fmt" - "net/http" + "fmt" + "net/http" - "github.com/influxdata/chronograf" + "github.com/influxdata/chronograf" ) type dashboardLinks struct { - Self string `json:"self"` // Self link mapping to this resource + Self string `json:"self"` // Self link mapping to this resource } type dashboardResponse struct { - chronograf.Dashboard - Links dashboardLinks `json:"links"` + chronograf.Dashboard + Links dashboardLinks `json:"links"` } type getDashboardsResponse struct { @@ -21,52 +21,52 @@ type getDashboardsResponse struct { } func newDashboardResponse(d chronograf.Dashboard) dashboardResponse { - base := "/chronograf/v1/dashboards" - return dashboardResponse{ - Dashboard: d, - Links: dashboardLinks{ - Self: fmt.Sprintf("%s/%d", base, d.ID), - }, - } + base := "/chronograf/v1/dashboards" + return dashboardResponse{ + Dashboard: d, + Links: dashboardLinks{ + Self: fmt.Sprintf("%s/%d", base, d.ID), + }, + } } // Dashboards returns all dashboards within the store func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - dashboards, err := s.DashboardsStore.All(ctx) - if err != nil { - Error(w, http.StatusInternalServerError, "Error loading layouts", s.Logger) - return - } + ctx := r.Context() + dashboards, err := s.DashboardsStore.All(ctx) + if err != nil { + Error(w, http.StatusInternalServerError, "Error loading layouts", s.Logger) + return + } - res := getDashboardsResponse{ - Dashboards: []dashboardResponse{}, - } + res := getDashboardsResponse{ + Dashboards: []dashboardResponse{}, + } - for _, dashboard := range dashboards { - res.Dashboards = append(res.Dashboards, newDashboardResponse(dashboard)) - } + for _, dashboard := range dashboards { + res.Dashboards = append(res.Dashboards, newDashboardResponse(dashboard)) + } - encodeJSON(w, http.StatusOK, res, s.Logger) + encodeJSON(w, http.StatusOK, res, s.Logger) } // DashboardID returns a single specified dashboard func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) { - id, err := paramID("id", r) - if err != nil { - Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) - return - } + id, err := paramID("id", r) + if err != nil { + Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) + return + } - ctx := r.Context() - e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id)) - if err != nil { - notFound(w, id, s.Logger) - return - } + ctx := r.Context() + e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id)) + if err != nil { + notFound(w, id, s.Logger) + return + } - res := newDashboardResponse(e) - encodeJSON(w, http.StatusOK, res, s.Logger) + res := newDashboardResponse(e) + encodeJSON(w, http.StatusOK, res, s.Logger) } // type postDashboardRequest struct { @@ -81,7 +81,7 @@ func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) { // RemoveDashboard deletes a dashboard func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) { - id, err := paramID("id", r) + id, err := paramID("id", r) if err != nil { Error(w, http.StatusUnprocessableEntity, err.Error(), h.Logger) return diff --git a/server/service.go b/server/service.go index 0a7363d53..628b9619b 100644 --- a/server/service.go +++ b/server/service.go @@ -10,7 +10,7 @@ type Service struct { LayoutStore chronograf.LayoutStore AlertRulesStore chronograf.AlertRulesStore UsersStore chronograf.UsersStore - DashboardsStore chronograf.DashboardsStore + DashboardsStore chronograf.DashboardsStore TimeSeries chronograf.TimeSeries Logger chronograf.Logger UseAuth bool From e8d1094be9d8ea4849704c136261a08129b4dbf8 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Wed, 14 Dec 2016 12:54:58 -0800 Subject: [PATCH 16/25] add dashboard creation to API --- server/dashboards.go | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/server/dashboards.go b/server/dashboards.go index ee2308a3b..63bbfb8a6 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -1,6 +1,7 @@ package server import ( + "encoding/json" "fmt" "net/http" @@ -65,25 +66,35 @@ func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) { return } - res := newDashboardResponse(e) + res := newDashboardResponse(*e) encodeJSON(w, http.StatusOK, res, s.Logger) } -// type postDashboardRequest struct { -// Data interface{} `json:"data"` // Serialization of config. -// Name string `json:"name,omitempty"` // Exploration name given by user. -// } - // NewDashboard creates and returns a new dashboard object func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) { + var dashboard *chronograf.Dashboard + if err := json.NewDecoder(r.Body).Decode(&dashboard); err != nil { + invalidJSON(w, s.Logger) + return + } + var err error + if dashboard, err = s.DashboardsStore.Add(r.Context(), dashboard); err != nil { + msg := fmt.Errorf("Error storing layout %v: %v", dashboard, err) + unknownErrorWithMessage(w, msg, s.Logger) + return + } + + res := newDashboardResponse(*dashboard) + w.Header().Add("Location", res.Links.Self) + encodeJSON(w, http.StatusCreated, res, s.Logger) } // RemoveDashboard deletes a dashboard func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) { id, err := paramID("id", r) if err != nil { - Error(w, http.StatusUnprocessableEntity, err.Error(), h.Logger) + Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) return } @@ -94,7 +105,7 @@ func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) { return } - if err := s.DashboardsStore.Delete(ctx, &chronograf.Dashboard{ID: chronograf.DashboardID(id)}); err != nil { + if err := s.DashboardsStore.Delete(ctx, e); err != nil { unknownErrorWithMessage(w, err, s.Logger) return } From 52e845844fc54a197b4a55ddd3d1012d0baecc22 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Wed, 14 Dec 2016 12:55:21 -0800 Subject: [PATCH 17/25] formatting --- server/dashboards.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/dashboards.go b/server/dashboards.go index 63bbfb8a6..51425d986 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -1,7 +1,7 @@ package server import ( - "encoding/json" + "encoding/json" "fmt" "net/http" From eda132df08882f3101997dca6b9fe5ba970f12f1 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 15 Dec 2016 00:31:53 -0800 Subject: [PATCH 18/25] add update function for dashboards api --- server/dashboards.go | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/server/dashboards.go b/server/dashboards.go index 51425d986..29a3296c6 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -4,7 +4,9 @@ import ( "encoding/json" "fmt" "net/http" + "strconv" + "github.com/bouk/httprouter" "github.com/influxdata/chronograf" ) @@ -112,7 +114,35 @@ func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) } -// UpdateDashboard updates a dashboard +// UpdateDashboard replaces a dashboard func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + idParam, err := strconv.Atoi(httprouter.GetParamFromContext(ctx, "id")) + if err != nil { + msg := fmt.Sprintf("Could not parse dashboard ID: %s", err) + Error(w, http.StatusInternalServerError, msg, s.Logger) + } + id := chronograf.DashboardID(idParam) + _, err = s.DashboardsStore.Get(ctx, id) + if err != nil { + Error(w, http.StatusNotFound, fmt.Sprintf("ID %s not found", id), s.Logger) + return + } + + var req *chronograf.Dashboard + if err := json.NewDecoder(r.Body).Decode(req); err != nil { + invalidJSON(w, s.Logger) + return + } + req.ID = id + + if err := s.DashboardsStore.Update(ctx, req); err != nil { + msg := fmt.Sprintf("Error updating dashboard ID %s: %v", id, err) + Error(w, http.StatusInternalServerError, msg, s.Logger) + return + } + + res := newDashboardResponse(*req) + encodeJSON(w, http.StatusOK, res, s.Logger) } From d3e77fd253afe757a641d771082402fe19fd2c1f Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 15 Dec 2016 00:41:42 -0800 Subject: [PATCH 19/25] wording --- server/dashboards.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/dashboards.go b/server/dashboards.go index 29a3296c6..d0cb271d8 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -38,7 +38,7 @@ func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) { ctx := r.Context() dashboards, err := s.DashboardsStore.All(ctx) if err != nil { - Error(w, http.StatusInternalServerError, "Error loading layouts", s.Logger) + Error(w, http.StatusInternalServerError, "Error loading dashboards", s.Logger) return } @@ -82,7 +82,7 @@ func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) { var err error if dashboard, err = s.DashboardsStore.Add(r.Context(), dashboard); err != nil { - msg := fmt.Errorf("Error storing layout %v: %v", dashboard, err) + msg := fmt.Errorf("Error storing dashboard %v: %v", dashboard, err) unknownErrorWithMessage(w, msg, s.Logger) return } From 0fd1cc7861c768b7fc035127bc8b9a95634e4d82 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 15 Dec 2016 00:49:43 -0800 Subject: [PATCH 20/25] be sure to create dashboardsbucket in bolt --- bolt/client.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bolt/client.go b/bolt/client.go index 730b74d72..c0fb38c29 100644 --- a/bolt/client.go +++ b/bolt/client.go @@ -65,6 +65,10 @@ func (c *Client) Open() error { if _, err := tx.CreateBucketIfNotExists(LayoutBucket); err != nil { return err } + // Always create Dashboards bucket. + if _, err := tx.CreateBucketIfNotExists(DashboardsBucket); err != nil { + return err + } // Always create Alerts bucket. if _, err := tx.CreateBucketIfNotExists(AlertsBucket); err != nil { return err From 4a92be218b2391958fe8e60bb0e42f1a02660aaf Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 15 Dec 2016 00:50:38 -0800 Subject: [PATCH 21/25] dashboard, not dashboards --- bolt/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bolt/client.go b/bolt/client.go index c0fb38c29..854839879 100644 --- a/bolt/client.go +++ b/bolt/client.go @@ -66,7 +66,7 @@ func (c *Client) Open() error { return err } // Always create Dashboards bucket. - if _, err := tx.CreateBucketIfNotExists(DashboardsBucket); err != nil { + if _, err := tx.CreateBucketIfNotExists(DashboardBucket); err != nil { return err } // Always create Alerts bucket. From 00f66e7593add68e2ba02925686c3386c0d7466d Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 15 Dec 2016 11:27:06 -0800 Subject: [PATCH 22/25] fix bugs --- bolt/internal/internal.pb.go | 93 ++++++++++++++++++------------------ bolt/internal/internal.proto | 4 +- chronograf.go | 1 + server/server.go | 1 + 4 files changed, 51 insertions(+), 48 deletions(-) diff --git a/bolt/internal/internal.pb.go b/bolt/internal/internal.pb.go index ee42d9213..586515e83 100644 --- a/bolt/internal/internal.pb.go +++ b/bolt/internal/internal.pb.go @@ -93,8 +93,8 @@ type DashboardCell struct { W int32 `protobuf:"varint,3,opt,name=w,proto3" json:"w,omitempty"` H int32 `protobuf:"varint,4,opt,name=h,proto3" json:"h,omitempty"` Queries []string `protobuf:"bytes,5,rep,name=queries" json:"queries,omitempty"` - Name string `protobuf:"bytes,7,opt,name=name,proto3" json:"name,omitempty"` - Type string `protobuf:"bytes,10,opt,name=type,proto3" json:"type,omitempty"` + Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` + Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"` } func (m *DashboardCell) Reset() { *m = DashboardCell{} } @@ -232,48 +232,49 @@ func init() { func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) } var fileDescriptorInternal = []byte{ - // 688 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x94, 0x51, 0x6e, 0xd3, 0x4c, - 0x10, 0xc7, 0xb5, 0xb1, 0x9d, 0xc4, 0x93, 0x7e, 0xfd, 0xd0, 0xaa, 0x02, 0x0b, 0xf1, 0x60, 0x59, - 0x20, 0x05, 0x09, 0xfa, 0xd0, 0x9e, 0x20, 0x8d, 0x2b, 0x14, 0x28, 0xa5, 0x6c, 0x1b, 0xf1, 0x04, - 0xd2, 0x36, 0xd9, 0x36, 0x96, 0x36, 0xb6, 0x59, 0xdb, 0xa4, 0x3e, 0x02, 0x12, 0x67, 0xe0, 0x10, - 0x70, 0x01, 0xee, 0xc0, 0x85, 0xd0, 0xec, 0xae, 0x9d, 0x54, 0x14, 0x14, 0x89, 0xb7, 0xfd, 0xed, - 0x8c, 0xc7, 0xff, 0x99, 0xff, 0xd8, 0xb0, 0x9b, 0xa4, 0xa5, 0x50, 0x29, 0x97, 0xfb, 0xb9, 0xca, - 0xca, 0x8c, 0xf6, 0x1b, 0x8e, 0xbe, 0x13, 0x18, 0x1c, 0xdf, 0xe4, 0x32, 0x53, 0xbc, 0x4c, 0xb2, - 0x94, 0xee, 0x42, 0x67, 0x12, 0x07, 0x24, 0x24, 0x43, 0x87, 0x75, 0x26, 0x31, 0xa5, 0xe0, 0x9e, - 0xf2, 0xa5, 0x08, 0x3a, 0x21, 0x19, 0xfa, 0x4c, 0x9f, 0xe9, 0x7d, 0xe8, 0x4e, 0x0b, 0xa1, 0x26, - 0x71, 0xe0, 0xe8, 0x3c, 0x4b, 0x98, 0x1b, 0xf3, 0x92, 0x07, 0xae, 0xc9, 0xc5, 0x33, 0x7d, 0x04, - 0xfe, 0x58, 0x09, 0x5e, 0x8a, 0xf9, 0xa8, 0x0c, 0x3c, 0x9d, 0xbe, 0xbe, 0xc0, 0xe8, 0x34, 0x9f, - 0xdb, 0x68, 0xd7, 0x44, 0xdb, 0x0b, 0x1a, 0x40, 0x2f, 0x16, 0x57, 0xbc, 0x92, 0x65, 0xd0, 0x0b, - 0xc9, 0xb0, 0xcf, 0x1a, 0x8c, 0x7e, 0x10, 0xe8, 0x9e, 0x67, 0x95, 0x9a, 0x89, 0xad, 0x04, 0x53, - 0x70, 0x2f, 0xea, 0x5c, 0x68, 0xb9, 0x3e, 0xd3, 0x67, 0xfa, 0x10, 0xfa, 0x28, 0x3b, 0xc5, 0x5c, - 0x23, 0xb8, 0x65, 0x8c, 0x9d, 0xf1, 0xa2, 0x58, 0x65, 0x6a, 0xae, 0x35, 0xfb, 0xac, 0x65, 0x7a, - 0x0f, 0x9c, 0x29, 0x3b, 0xd1, 0x62, 0x7d, 0x86, 0xc7, 0x3f, 0xcb, 0xc4, 0x3a, 0x17, 0x42, 0x8a, - 0x6b, 0xc5, 0xaf, 0x82, 0xbe, 0xa9, 0xd3, 0x70, 0xf4, 0x01, 0xfc, 0x98, 0x17, 0x8b, 0xcb, 0x8c, - 0xab, 0xf9, 0x56, 0x4d, 0x3c, 0x07, 0x6f, 0x26, 0xa4, 0x2c, 0x02, 0x27, 0x74, 0x86, 0x83, 0x83, - 0x07, 0xfb, 0xad, 0xa7, 0x6d, 0x9d, 0xb1, 0x90, 0x92, 0x99, 0xac, 0xe8, 0x33, 0x81, 0xff, 0x6e, - 0x05, 0xe8, 0x0e, 0x90, 0x1b, 0xfd, 0x0e, 0x8f, 0x91, 0x1b, 0xa4, 0x5a, 0xd7, 0xf7, 0x18, 0xa9, - 0x91, 0x56, 0x7a, 0x3c, 0x1e, 0x23, 0x2b, 0xa4, 0x85, 0x1e, 0x8a, 0xc7, 0xc8, 0x02, 0xfb, 0xfb, - 0x58, 0x09, 0x95, 0x88, 0x22, 0xf0, 0x42, 0x67, 0xe8, 0xb3, 0x06, 0x51, 0xa6, 0x9e, 0x5f, 0xcf, - 0xc8, 0x4c, 0xed, 0xac, 0x4b, 0x9c, 0x35, 0x98, 0x3b, 0x3c, 0x47, 0x5f, 0xd0, 0x2e, 0xa1, 0x3e, - 0x09, 0xb5, 0x55, 0xa7, 0x9b, 0xd6, 0x38, 0x7f, 0xb1, 0xc6, 0xbd, 0xdb, 0x1a, 0x6f, 0x6d, 0xcd, - 0x1e, 0x78, 0xe7, 0x6a, 0x36, 0x89, 0xed, 0x6e, 0x19, 0x88, 0xbe, 0x12, 0xe8, 0x9e, 0xf0, 0x3a, - 0xab, 0xca, 0x0d, 0x39, 0xbe, 0x96, 0x13, 0xc2, 0x60, 0x94, 0xe7, 0x32, 0x99, 0xe9, 0xaf, 0xc1, - 0xaa, 0xda, 0xbc, 0xc2, 0x8c, 0xd7, 0x82, 0x17, 0x95, 0x12, 0x4b, 0x91, 0x96, 0x56, 0xdf, 0xe6, - 0x15, 0x7d, 0x0c, 0xde, 0x58, 0x1b, 0xe5, 0x6a, 0xa3, 0x76, 0xd7, 0x46, 0x19, 0x7f, 0x74, 0x10, - 0x1b, 0x19, 0x55, 0x65, 0x76, 0x25, 0xb3, 0x95, 0x56, 0xdc, 0x67, 0x2d, 0x47, 0x3f, 0x09, 0xb8, - 0xff, 0x64, 0xd9, 0xd3, 0xdb, 0x96, 0x0d, 0x0e, 0xfe, 0x5f, 0x8b, 0x78, 0x5b, 0x09, 0x55, 0xaf, - 0x3d, 0xdc, 0x01, 0x92, 0xd8, 0x6d, 0x26, 0xc9, 0x9d, 0x8e, 0x06, 0xd0, 0xab, 0x15, 0x4f, 0xaf, - 0x45, 0x11, 0xf4, 0x43, 0x67, 0xe8, 0xb0, 0x06, 0x75, 0x44, 0xf2, 0x4b, 0x21, 0x8b, 0xc0, 0x37, - 0x9b, 0x61, 0xf1, 0xce, 0x2d, 0xf8, 0x46, 0xc0, 0xd3, 0x2f, 0xc7, 0xe7, 0xc6, 0xd9, 0x72, 0xc9, - 0xd3, 0xb9, 0x1d, 0x7d, 0x83, 0xe8, 0x47, 0x7c, 0x64, 0xc7, 0xde, 0x89, 0x8f, 0x90, 0xd9, 0x99, - 0x1d, 0x72, 0x87, 0x9d, 0xe1, 0xd4, 0x5e, 0xa8, 0xac, 0xca, 0x8f, 0x6a, 0x33, 0x5e, 0x9f, 0xb5, - 0x8c, 0xbf, 0xa5, 0x77, 0x0b, 0xa1, 0xda, 0x35, 0xb5, 0x84, 0x4b, 0x70, 0x82, 0xaa, 0x6c, 0x97, - 0x06, 0xe8, 0x13, 0xf0, 0x18, 0x76, 0xa1, 0x5b, 0xbd, 0x35, 0x20, 0x7d, 0xcd, 0x4c, 0x34, 0x3a, - 0xb4, 0x69, 0x58, 0x65, 0x9a, 0xe7, 0x42, 0xd9, 0xdd, 0x35, 0xa0, 0x6b, 0x67, 0x2b, 0xa1, 0xb4, - 0x64, 0x87, 0x19, 0x88, 0xde, 0x83, 0x3f, 0x92, 0x42, 0x95, 0xac, 0x92, 0xe2, 0xb7, 0x15, 0xa3, - 0xe0, 0xbe, 0x3c, 0x7f, 0x73, 0xda, 0x6c, 0x3c, 0x9e, 0xd7, 0x7b, 0xea, 0x6c, 0xec, 0x29, 0x36, - 0xf4, 0x8a, 0xe7, 0x7c, 0x12, 0x6b, 0x63, 0x1d, 0x66, 0x29, 0x7a, 0x06, 0x2e, 0x7e, 0x0f, 0x1b, - 0x95, 0x5d, 0x5d, 0x79, 0x0f, 0xbc, 0xe3, 0x25, 0x4f, 0xa4, 0x2d, 0x6d, 0xe0, 0xb2, 0xab, 0x7f, - 0xf9, 0x87, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xf6, 0x0c, 0x35, 0x69, 0x04, 0x06, 0x00, 0x00, + // 693 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x54, 0xdd, 0x6e, 0xd3, 0x4a, + 0x10, 0xd6, 0xc6, 0x76, 0x12, 0x4f, 0x7a, 0x7a, 0x8e, 0x56, 0xd5, 0xc1, 0x42, 0x5c, 0x44, 0x16, + 0x48, 0x41, 0x82, 0x5e, 0xb4, 0x4f, 0x90, 0xc6, 0x15, 0x0a, 0x94, 0x52, 0xb6, 0x8d, 0xb8, 0x02, + 0x69, 0x9b, 0x6c, 0x9b, 0x48, 0x9b, 0xd8, 0xac, 0x6d, 0xd2, 0x3c, 0x02, 0x12, 0xcf, 0xc0, 0x43, + 0xc0, 0x0b, 0xf0, 0x0e, 0xbc, 0x10, 0x9a, 0xd9, 0xb5, 0xe3, 0x8a, 0x1f, 0x55, 0xe2, 0x6e, 0xbe, + 0x99, 0xf1, 0xf8, 0x9b, 0xf9, 0x3e, 0x1b, 0x76, 0x17, 0xab, 0x42, 0x99, 0x95, 0xd4, 0xfb, 0x99, + 0x49, 0x8b, 0x94, 0x77, 0x2b, 0x1c, 0x7f, 0x65, 0xd0, 0x3b, 0xbe, 0xc9, 0x74, 0x6a, 0x64, 0xb1, + 0x48, 0x57, 0x7c, 0x17, 0x5a, 0xe3, 0x24, 0x62, 0x7d, 0x36, 0xf0, 0x44, 0x6b, 0x9c, 0x70, 0x0e, + 0xfe, 0xa9, 0x5c, 0xaa, 0xa8, 0xd5, 0x67, 0x83, 0x50, 0x50, 0xcc, 0xff, 0x87, 0xf6, 0x24, 0x57, + 0x66, 0x9c, 0x44, 0x1e, 0xf5, 0x39, 0x84, 0xbd, 0x89, 0x2c, 0x64, 0xe4, 0xdb, 0x5e, 0x8c, 0xf9, + 0x03, 0x08, 0x47, 0x46, 0xc9, 0x42, 0xcd, 0x86, 0x45, 0x14, 0x50, 0xfb, 0x36, 0x81, 0xd5, 0x49, + 0x36, 0x73, 0xd5, 0xb6, 0xad, 0xd6, 0x09, 0x1e, 0x41, 0x27, 0x51, 0x57, 0xb2, 0xd4, 0x45, 0xd4, + 0xe9, 0xb3, 0x41, 0x57, 0x54, 0x30, 0xfe, 0xc6, 0xa0, 0x7d, 0x9e, 0x96, 0x66, 0xaa, 0xee, 0x44, + 0x98, 0x83, 0x7f, 0xb1, 0xc9, 0x14, 0xd1, 0x0d, 0x05, 0xc5, 0xfc, 0x3e, 0x74, 0x91, 0xf6, 0x0a, + 0x7b, 0x2d, 0xe1, 0x1a, 0x63, 0xed, 0x4c, 0xe6, 0xf9, 0x3a, 0x35, 0x33, 0xe2, 0x1c, 0x8a, 0x1a, + 0xf3, 0xff, 0xc0, 0x9b, 0x88, 0x13, 0x22, 0x1b, 0x0a, 0x0c, 0x7f, 0x4f, 0x13, 0xe7, 0x5c, 0x28, + 0xad, 0xae, 0x8d, 0xbc, 0x8a, 0xba, 0x76, 0x4e, 0x85, 0xe3, 0x77, 0x10, 0x26, 0x32, 0x9f, 0x5f, + 0xa6, 0xd2, 0xcc, 0xee, 0xb4, 0xc4, 0x53, 0x08, 0xa6, 0x4a, 0xeb, 0x3c, 0xf2, 0xfa, 0xde, 0xa0, + 0x77, 0x70, 0x6f, 0xbf, 0xd6, 0xb4, 0x9e, 0x33, 0x52, 0x5a, 0x0b, 0xdb, 0x15, 0x7f, 0x64, 0xf0, + 0xcf, 0xad, 0x02, 0xdf, 0x01, 0x76, 0x43, 0xef, 0x08, 0x04, 0xbb, 0x41, 0xb4, 0xa1, 0xf9, 0x81, + 0x60, 0x1b, 0x44, 0x6b, 0x3a, 0x4f, 0x20, 0xd8, 0x1a, 0xd1, 0x9c, 0x8e, 0x12, 0x08, 0x36, 0xc7, + 0xfd, 0xde, 0x97, 0xca, 0x2c, 0x54, 0x1e, 0x05, 0x7d, 0x6f, 0x10, 0x8a, 0x0a, 0x22, 0x4d, 0xba, + 0x9f, 0x3d, 0x06, 0xc5, 0x98, 0x2b, 0xf0, 0xd6, 0x1d, 0x9b, 0xc3, 0x38, 0xfe, 0x84, 0x72, 0x29, + 0xf3, 0x41, 0x99, 0x3b, 0x6d, 0xda, 0x94, 0xc6, 0xfb, 0x83, 0x34, 0xfe, 0xaf, 0xa5, 0x09, 0xb6, + 0xd2, 0xec, 0x41, 0x70, 0x6e, 0xa6, 0xe3, 0xc4, 0x79, 0xcb, 0x82, 0xf8, 0x33, 0x83, 0xf6, 0x89, + 0xdc, 0xa4, 0x65, 0xd1, 0xa0, 0x13, 0x12, 0x9d, 0x3e, 0xf4, 0x86, 0x59, 0xa6, 0x17, 0x53, 0xfa, + 0x1a, 0x1c, 0xab, 0x66, 0x0a, 0x3b, 0x5e, 0x2a, 0x99, 0x97, 0x46, 0x2d, 0xd5, 0xaa, 0x70, 0xfc, + 0x9a, 0x29, 0xfe, 0x10, 0x82, 0x11, 0x09, 0xe5, 0x93, 0x50, 0xbb, 0x5b, 0xa1, 0xac, 0x3e, 0x54, + 0xc4, 0x45, 0x86, 0x65, 0x91, 0x5e, 0xe9, 0x74, 0x4d, 0x8c, 0xbb, 0xa2, 0xc6, 0xf1, 0x77, 0x06, + 0xfe, 0x5f, 0x49, 0xf6, 0xf8, 0xb6, 0x64, 0xbd, 0x83, 0x7f, 0xb7, 0x24, 0x5e, 0x97, 0xca, 0x6c, + 0xb6, 0x1a, 0xee, 0x00, 0x5b, 0x38, 0x01, 0xd9, 0xa2, 0x56, 0xb4, 0xd3, 0x50, 0x34, 0x82, 0xce, + 0xc6, 0xc8, 0xd5, 0xb5, 0xca, 0xa3, 0x6e, 0xdf, 0x1b, 0x78, 0xa2, 0x82, 0x54, 0xd1, 0xf2, 0x52, + 0xe9, 0x3c, 0x0a, 0xad, 0x33, 0x1c, 0xac, 0x5d, 0x00, 0x0d, 0x17, 0x7c, 0x61, 0x10, 0xd0, 0xcb, + 0xf1, 0xb9, 0x51, 0xba, 0x5c, 0xca, 0xd5, 0xcc, 0x9d, 0xbe, 0x82, 0xa8, 0x47, 0x72, 0xe4, 0xce, + 0xde, 0x4a, 0x8e, 0x10, 0x8b, 0x33, 0x77, 0xe4, 0x96, 0x38, 0xc3, 0xab, 0x3d, 0x33, 0x69, 0x99, + 0x1d, 0x6d, 0xec, 0x79, 0x43, 0x51, 0x63, 0xfc, 0x2d, 0xbd, 0x99, 0x2b, 0x53, 0xdb, 0xd4, 0x21, + 0x34, 0xc1, 0x09, 0xb2, 0x72, 0x5b, 0x5a, 0xc0, 0x1f, 0x41, 0x20, 0x70, 0x0b, 0x5a, 0xf5, 0xd6, + 0x81, 0x28, 0x2d, 0x6c, 0x35, 0x3e, 0x74, 0x6d, 0x38, 0x65, 0x92, 0x65, 0xca, 0x38, 0xef, 0x5a, + 0x40, 0xb3, 0xd3, 0xb5, 0x32, 0x44, 0xd9, 0x13, 0x16, 0xc4, 0x6f, 0x21, 0x1c, 0x6a, 0x65, 0x0a, + 0x51, 0x6a, 0xf5, 0x93, 0xc5, 0x38, 0xf8, 0xcf, 0xcf, 0x5f, 0x9d, 0x56, 0x8e, 0xc7, 0x78, 0xeb, + 0x53, 0xaf, 0xe1, 0x53, 0x5c, 0xe8, 0x85, 0xcc, 0xe4, 0x38, 0x21, 0x61, 0x3d, 0xe1, 0x50, 0xfc, + 0x04, 0x7c, 0xfc, 0x1e, 0x1a, 0x93, 0x7d, 0x9a, 0xbc, 0x07, 0xc1, 0xf1, 0x52, 0x2e, 0xb4, 0x1b, + 0x6d, 0xc1, 0x65, 0x9b, 0x7e, 0xf9, 0x87, 0x3f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x31, 0x9b, 0xcb, + 0xb7, 0x04, 0x06, 0x00, 0x00, } diff --git a/bolt/internal/internal.proto b/bolt/internal/internal.proto index 269c54241..790bcb1b2 100644 --- a/bolt/internal/internal.proto +++ b/bolt/internal/internal.proto @@ -34,8 +34,8 @@ message DashboardCell { int32 w = 3; // Width of Cell in the Dashboard int32 h = 4; // Height of Cell in the Dashboard repeated string queries = 5; // Time-series data queries for Dashboard - string name = 7; // User-facing name for this Dashboard - string type = 10; // Dashboard visualization type + string name = 6; // User-facing name for this Dashboard + string type = 7; // Dashboard visualization type } message Server { diff --git a/chronograf.go b/chronograf.go index dc7731ca4..0c8c3a29b 100644 --- a/chronograf.go +++ b/chronograf.go @@ -247,6 +247,7 @@ type DashboardCell struct { // DashboardsStore is the storage and retrieval of dashboards type DashboardsStore interface { + // All lists all dashboards from the DashboardStore All(context.Context) ([]Dashboard, error) // Create a new Dashboard in the DashboardStore Add(context.Context, *Dashboard) (*Dashboard, error) diff --git a/server/server.go b/server/server.go index 951b6eef3..a7ac976b4 100644 --- a/server/server.go +++ b/server/server.go @@ -142,6 +142,7 @@ func openService(boltPath, cannedPath string, logger chronograf.Logger, useAuth Logger: logger, }, LayoutStore: layouts, + DashboardsStore: db.DashboardsStore, AlertRulesStore: db.AlertsStore, Logger: logger, UseAuth: useAuth, From 7d275b9551b8153c7124e44ebfebc8ac39485bf9 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 15 Dec 2016 13:22:32 -0800 Subject: [PATCH 23/25] add dashboard validation --- server/dashboards.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/server/dashboards.go b/server/dashboards.go index d0cb271d8..96aa43c9a 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -80,6 +80,11 @@ func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) { return } + if err := ValidDashboardRequest(dashboard); err != nil { + invalidData(w, err, s.Logger) + return + } + var err error if dashboard, err = s.DashboardsStore.Add(r.Context(), dashboard); err != nil { msg := fmt.Errorf("Error storing dashboard %v: %v", dashboard, err) @@ -137,6 +142,11 @@ func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) { } req.ID = id + if err := ValidDashboardRequest(dashboard); err != nil { + invalidData(w, err, s.Logger) + return + } + if err := s.DashboardsStore.Update(ctx, req); err != nil { msg := fmt.Sprintf("Error updating dashboard ID %s: %v", id, err) Error(w, http.StatusInternalServerError, msg, s.Logger) @@ -146,3 +156,20 @@ func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) { res := newDashboardResponse(*req) encodeJSON(w, http.StatusOK, res, s.Logger) } + +// ValidDashboardRequest verifies that the dashboard cells have a query +func ValidDashboardRequest(d chronograf.Dashboard) error { + if len(d.Cells) == 0 { + return fmt.Errorf("cells are required") + } + + for _, c := range d.Cells { + for _, q := range c.Queries { + if len(q) == 0 { + return ftm.Errorf("query required") + } + } + } + + return nil +} From ffe994321248bdd8a959c5717bddc81ea4f37caf Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 15 Dec 2016 13:37:11 -0800 Subject: [PATCH 24/25] clean up pointer usage --- bolt/dashboards.go | 18 +++++++++--------- chronograf.go | 8 ++++---- server/dashboards.go | 16 ++++++++-------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/bolt/dashboards.go b/bolt/dashboards.go index 8bf58b583..4df9ebf8e 100644 --- a/bolt/dashboards.go +++ b/bolt/dashboards.go @@ -42,28 +42,28 @@ func (d *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, erro } // Add creates a new Dashboard in the DashboardsStore -func (d *DashboardsStore) Add(ctx context.Context, src *chronograf.Dashboard) (*chronograf.Dashboard, error) { +func (d *DashboardsStore) Add(ctx context.Context, src chronograf.Dashboard) (chronograf.Dashboard, error) { if err := d.client.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(DashboardBucket) id, _ := b.NextSequence() src.ID = chronograf.DashboardID(id) strID := strconv.Itoa(int(id)) - if v, err := internal.MarshalDashboard(*src); err != nil { + if v, err := internal.MarshalDashboard(src); err != nil { return err } else if err := b.Put([]byte(strID), v); err != nil { return err } return nil }); err != nil { - return &chronograf.Dashboard{}, err + return chronograf.Dashboard{}, err } return src, nil } // Get returns a Dashboard if the id exists. -func (d *DashboardsStore) Get(ctx context.Context, id chronograf.DashboardID) (*chronograf.Dashboard, error) { +func (d *DashboardsStore) Get(ctx context.Context, id chronograf.DashboardID) (chronograf.Dashboard, error) { var src chronograf.Dashboard if err := d.client.db.View(func(tx *bolt.Tx) error { strID := strconv.Itoa(int(id)) @@ -74,14 +74,14 @@ func (d *DashboardsStore) Get(ctx context.Context, id chronograf.DashboardID) (* } return nil }); err != nil { - return &chronograf.Dashboard{}, err + return chronograf.Dashboard{}, err } - return &src, nil + return src, nil } // Delete the dashboard from DashboardsStore -func (s *DashboardsStore) Delete(ctx context.Context, d *chronograf.Dashboard) error { +func (s *DashboardsStore) Delete(ctx context.Context, d chronograf.Dashboard) error { if err := s.client.db.Update(func(tx *bolt.Tx) error { if err := tx.Bucket(DashboardBucket).Delete(itob(int(d.ID))); err != nil { return err @@ -95,7 +95,7 @@ func (s *DashboardsStore) Delete(ctx context.Context, d *chronograf.Dashboard) e } // Update the dashboard in DashboardsStore -func (s *DashboardsStore) Update(ctx context.Context, d *chronograf.Dashboard) error { +func (s *DashboardsStore) Update(ctx context.Context, d chronograf.Dashboard) error { if err := s.client.db.Update(func(tx *bolt.Tx) error { // Get an existing dashboard with the same ID. b := tx.Bucket(DashboardBucket) @@ -104,7 +104,7 @@ func (s *DashboardsStore) Update(ctx context.Context, d *chronograf.Dashboard) e return chronograf.ErrDashboardNotFound } - if v, err := internal.MarshalDashboard(*d); err != nil { + if v, err := internal.MarshalDashboard(d); err != nil { return err } else if err := b.Put([]byte(strID), v); err != nil { return err diff --git a/chronograf.go b/chronograf.go index 0c8c3a29b..d26613205 100644 --- a/chronograf.go +++ b/chronograf.go @@ -250,13 +250,13 @@ type DashboardsStore interface { // All lists all dashboards from the DashboardStore All(context.Context) ([]Dashboard, error) // Create a new Dashboard in the DashboardStore - Add(context.Context, *Dashboard) (*Dashboard, error) + Add(context.Context, Dashboard) (Dashboard, error) // Delete the Dashboard from the DashboardStore if `ID` exists. - Delete(context.Context, *Dashboard) error + Delete(context.Context, Dashboard) error // Get retrieves a dashboard if `ID` exists. - Get(ctx context.Context, id DashboardID) (*Dashboard, error) + Get(ctx context.Context, id DashboardID) (Dashboard, error) // Update replaces the dashboard information - Update(context.Context, *Dashboard) error + Update(context.Context, Dashboard) error } // ExplorationID is a unique ID for an Exploration. diff --git a/server/dashboards.go b/server/dashboards.go index 96aa43c9a..8d792b43b 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -68,14 +68,14 @@ func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) { return } - res := newDashboardResponse(*e) + res := newDashboardResponse(e) encodeJSON(w, http.StatusOK, res, s.Logger) } // NewDashboard creates and returns a new dashboard object func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) { - var dashboard *chronograf.Dashboard - if err := json.NewDecoder(r.Body).Decode(&dashboard); err != nil { + var dashboard chronograf.Dashboard + if err := json.NewDecoder(r.Body).Decode(dashboard); err != nil { invalidJSON(w, s.Logger) return } @@ -92,7 +92,7 @@ func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) { return } - res := newDashboardResponse(*dashboard) + res := newDashboardResponse(dashboard) w.Header().Add("Location", res.Links.Self) encodeJSON(w, http.StatusCreated, res, s.Logger) } @@ -135,14 +135,14 @@ func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) { return } - var req *chronograf.Dashboard + var req chronograf.Dashboard if err := json.NewDecoder(r.Body).Decode(req); err != nil { invalidJSON(w, s.Logger) return } req.ID = id - if err := ValidDashboardRequest(dashboard); err != nil { + if err := ValidDashboardRequest(req); err != nil { invalidData(w, err, s.Logger) return } @@ -153,7 +153,7 @@ func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) { return } - res := newDashboardResponse(*req) + res := newDashboardResponse(req) encodeJSON(w, http.StatusOK, res, s.Logger) } @@ -166,7 +166,7 @@ func ValidDashboardRequest(d chronograf.Dashboard) error { for _, c := range d.Cells { for _, q := range c.Queries { if len(q) == 0 { - return ftm.Errorf("query required") + return fmt.Errorf("query required") } } } From 32f1097a7d41125974993570490685a9f2d98df7 Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 15 Dec 2016 13:53:43 -0800 Subject: [PATCH 25/25] fix json decoding --- server/dashboards.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/dashboards.go b/server/dashboards.go index 8d792b43b..ef62028d8 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -75,7 +75,7 @@ func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) { // NewDashboard creates and returns a new dashboard object func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) { var dashboard chronograf.Dashboard - if err := json.NewDecoder(r.Body).Decode(dashboard); err != nil { + if err := json.NewDecoder(r.Body).Decode(&dashboard); err != nil { invalidJSON(w, s.Logger) return } @@ -136,7 +136,7 @@ func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) { } var req chronograf.Dashboard - if err := json.NewDecoder(r.Body).Decode(req); err != nil { + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { invalidJSON(w, s.Logger) return }