influxdb/chronograf/server/dashboardsv2.go

237 lines
6.4 KiB
Go

package server
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/bouk/httprouter"
platform "github.com/influxdata/platform/chronograf/v2"
)
type dashboardV2Links struct {
Self string `json:"self"`
}
type dashboardV2Response struct {
platform.Dashboard
Links dashboardV2Links `json:"links"`
}
func newDashboardV2Response(d *platform.Dashboard) dashboardV2Response {
// Make nil slice values into empty array for front end.
if d.Cells == nil {
d.Cells = []platform.DashboardCell{}
}
return dashboardV2Response{
Links: dashboardV2Links{
Self: fmt.Sprintf("/chronograf/v2/dashboards/%s", d.ID),
},
Dashboard: *d,
}
}
// DashboardsV2 returns all dashboards within the store.
func (s *Service) DashboardsV2(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// TODO: support filtering via query params
dashboards, _, err := s.Store.DashboardsV2(ctx).FindDashboards(ctx, platform.DashboardFilter{})
if err != nil {
Error(w, http.StatusInternalServerError, "Error loading dashboards", s.Logger)
return
}
s.encodeGetDashboardsResponse(w, dashboards)
}
type getDashboardsV2Links struct {
Self string `json:"self"`
}
type getDashboardsV2Response struct {
Links getDashboardsV2Links `json:"links"`
Dashboards []dashboardV2Response `json:"dashboards"`
}
func (s *Service) encodeGetDashboardsResponse(w http.ResponseWriter, dashboards []*platform.Dashboard) {
res := getDashboardsV2Response{
Links: getDashboardsV2Links{
Self: "/chronograf/v2/dashboards",
},
Dashboards: make([]dashboardV2Response, 0, len(dashboards)),
}
for _, dashboard := range dashboards {
res.Dashboards = append(res.Dashboards, newDashboardV2Response(dashboard))
}
encodeJSON(w, http.StatusOK, res, s.Logger)
}
// NewDashboardV2 creates a new dashboard.
func (s *Service) NewDashboardV2(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodePostDashboardRequest(ctx, r)
if err != nil {
Error(w, http.StatusBadRequest, err.Error(), s.Logger)
return
}
if err := s.Store.DashboardsV2(ctx).CreateDashboard(ctx, req.Dashboard); err != nil {
Error(w, http.StatusInternalServerError, fmt.Sprintf("Error loading dashboards: %v", err), s.Logger)
return
}
s.encodePostDashboardResponse(w, req.Dashboard)
}
type postDashboardRequest struct {
Dashboard *platform.Dashboard
}
func decodePostDashboardRequest(ctx context.Context, r *http.Request) (*postDashboardRequest, error) {
c := &platform.Dashboard{}
if err := json.NewDecoder(r.Body).Decode(c); err != nil {
return nil, err
}
return &postDashboardRequest{
Dashboard: c,
}, nil
}
func (s *Service) encodePostDashboardResponse(w http.ResponseWriter, dashboard *platform.Dashboard) {
encodeJSON(w, http.StatusCreated, newDashboardV2Response(dashboard), s.Logger)
}
// DashboardIDV2 retrieves a dashboard by ID.
func (s *Service) DashboardIDV2(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodeGetDashboardRequest(ctx, r)
if err != nil {
Error(w, http.StatusBadRequest, err.Error(), s.Logger)
return
}
dashboard, err := s.Store.DashboardsV2(ctx).FindDashboardByID(ctx, req.DashboardID)
if err == platform.ErrDashboardNotFound {
Error(w, http.StatusNotFound, err.Error(), s.Logger)
return
}
if err != nil {
Error(w, http.StatusInternalServerError, fmt.Sprintf("Error loading dashboard: %v", err), s.Logger)
return
}
s.encodeGetDashboardResponse(w, dashboard)
}
type getDashboardRequest struct {
DashboardID platform.ID
}
func decodeGetDashboardRequest(ctx context.Context, r *http.Request) (*getDashboardRequest, error) {
param := httprouter.GetParamFromContext(ctx, "id")
return &getDashboardRequest{
DashboardID: platform.ID(param),
}, nil
}
func (s *Service) encodeGetDashboardResponse(w http.ResponseWriter, dashboard *platform.Dashboard) {
encodeJSON(w, http.StatusOK, newDashboardV2Response(dashboard), s.Logger)
}
// RemoveDashboardV2 removes a dashboard by ID.
func (s *Service) RemoveDashboardV2(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodeDeleteDashboardRequest(ctx, r)
if err != nil {
Error(w, http.StatusBadRequest, err.Error(), s.Logger)
return
}
err = s.Store.DashboardsV2(ctx).DeleteDashboard(ctx, req.DashboardID)
if err == platform.ErrDashboardNotFound {
Error(w, http.StatusNotFound, err.Error(), s.Logger)
return
}
if err != nil {
Error(w, http.StatusInternalServerError, fmt.Sprintf("Error deleting dashboard: %v", err), s.Logger)
return
}
w.WriteHeader(http.StatusNoContent)
}
type deleteDashboardRequest struct {
DashboardID platform.ID
}
func decodeDeleteDashboardRequest(ctx context.Context, r *http.Request) (*deleteDashboardRequest, error) {
param := httprouter.GetParamFromContext(ctx, "id")
return &deleteDashboardRequest{
DashboardID: platform.ID(param),
}, nil
}
// UpdateDashboardV2 updates a dashboard.
func (s *Service) UpdateDashboardV2(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodePatchDashboardRequest(ctx, r)
if err != nil {
Error(w, http.StatusBadRequest, err.Error(), s.Logger)
return
}
dashboard, err := s.Store.DashboardsV2(ctx).UpdateDashboard(ctx, req.DashboardID, req.Upd)
if err == platform.ErrDashboardNotFound {
Error(w, http.StatusNotFound, err.Error(), s.Logger)
return
}
if err != nil {
Error(w, http.StatusInternalServerError, fmt.Sprintf("Error updating dashboard: %v", err), s.Logger)
return
}
s.encodePatchDashboardResponse(w, dashboard)
}
type patchDashboardRequest struct {
DashboardID platform.ID
Upd platform.DashboardUpdate
}
func decodePatchDashboardRequest(ctx context.Context, r *http.Request) (*patchDashboardRequest, error) {
req := &patchDashboardRequest{}
upd := platform.DashboardUpdate{}
if err := json.NewDecoder(r.Body).Decode(&upd); err != nil {
return nil, err
}
req.Upd = upd
param := httprouter.GetParamFromContext(ctx, "id")
req.DashboardID = platform.ID(param)
if err := req.Valid(); err != nil {
return nil, err
}
return req, nil
}
// Valid validates that the dashboard ID is non zero valued and update has expected values set.
func (r *patchDashboardRequest) Valid() error {
if r.DashboardID == "" {
return fmt.Errorf("missing dashboard ID")
}
return r.Upd.Valid()
}
func (s *Service) encodePatchDashboardResponse(w http.ResponseWriter, dashboard *platform.Dashboard) {
encodeJSON(w, http.StatusOK, newDashboardV2Response(dashboard), s.Logger)
}