Fix mux paths to be hardcoded; clarify server start; fix golint
parent
d1359c09b3
commit
d6a067427b
|
@ -8,9 +8,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Dir = "../ui/build"
|
// Dir is prefix of the assets in the bindata
|
||||||
Default = "../ui/build/index.html"
|
Dir = "../ui/build"
|
||||||
DebugDir = "ui/build"
|
// Default is the default item to load if 404
|
||||||
|
Default = "../ui/build/index.html"
|
||||||
|
// DebugDir is the prefix of the assets in development mode
|
||||||
|
DebugDir = "ui/build"
|
||||||
|
// DebugDefault is the default item to load if 404
|
||||||
DebugDefault = "ui/build/index.html"
|
DebugDefault = "ui/build/index.html"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ type exploration struct {
|
||||||
|
|
||||||
func newExploration(e *chronograf.Exploration) exploration {
|
func newExploration(e *chronograf.Exploration) exploration {
|
||||||
rel := "self"
|
rel := "self"
|
||||||
href := fmt.Sprintf("%s/%d/explorations/%d", httpAPIUsrs, e.UserID, e.ID)
|
href := fmt.Sprintf("%s/%d/explorations/%d", "/chronograf/v1/users", e.UserID, e.ID)
|
||||||
return exploration{
|
return exploration{
|
||||||
Name: e.Name,
|
Name: e.Name,
|
||||||
Data: e.Data,
|
Data: e.Data,
|
||||||
|
@ -41,7 +41,8 @@ type explorations struct {
|
||||||
Explorations []exploration `json:"explorations"`
|
Explorations []exploration `json:"explorations"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) Explorations(w http.ResponseWriter, r *http.Request) {
|
// Explorations returns all explorations scoped by user id.
|
||||||
|
func (h *Service) Explorations(w http.ResponseWriter, r *http.Request) {
|
||||||
id, err := paramID("id", r)
|
id, err := paramID("id", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -66,7 +67,8 @@ func (h *Store) Explorations(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusOK, res, h.Logger)
|
encodeJSON(w, http.StatusOK, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) ExplorationsID(w http.ResponseWriter, r *http.Request) {
|
// ExplorationsID retrieves exploration ID scoped under user.
|
||||||
|
func (h *Service) ExplorationsID(w http.ResponseWriter, r *http.Request) {
|
||||||
eID, err := paramID("eid", r)
|
eID, err := paramID("eid", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -95,7 +97,8 @@ type patchExplorationRequest struct {
|
||||||
Name *string `json:"name,omitempty"` // Exploration name given by user.
|
Name *string `json:"name,omitempty"` // Exploration name given by user.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) UpdateExploration(w http.ResponseWriter, r *http.Request) {
|
// UpdateExploration incrementally updates exploration
|
||||||
|
func (h *Service) UpdateExploration(w http.ResponseWriter, r *http.Request) {
|
||||||
id, err := paramID("eid", r)
|
id, err := paramID("eid", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -149,7 +152,8 @@ type postExplorationRequest struct {
|
||||||
Name string `json:"name,omitempty"` // Exploration name given by user.
|
Name string `json:"name,omitempty"` // Exploration name given by user.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) NewExploration(w http.ResponseWriter, r *http.Request) {
|
// NewExploration adds valid exploration scoped by user id.
|
||||||
|
func (h *Service) NewExploration(w http.ResponseWriter, r *http.Request) {
|
||||||
uID, err := paramID("id", r)
|
uID, err := paramID("id", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -186,7 +190,8 @@ func (h *Store) NewExploration(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusCreated, res, h.Logger)
|
encodeJSON(w, http.StatusCreated, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) RemoveExploration(w http.ResponseWriter, r *http.Request) {
|
// RemoveExploration deletes exploration from store.
|
||||||
|
func (h *Service) RemoveExploration(w http.ResponseWriter, r *http.Request) {
|
||||||
eID, err := paramID("eid", r)
|
eID, err := paramID("eid", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
|
|
@ -15,7 +15,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultCookieName = "session"
|
// DefaultCookieName is the name of the stored cookie
|
||||||
|
DefaultCookieName = "session"
|
||||||
|
// DefaultCookieDuration is the length of time the cookie is valid
|
||||||
DefaultCookieDuration = time.Hour * 24 * 30
|
DefaultCookieDuration = time.Hour * 24 * 30
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,8 @@ type kapacitor struct {
|
||||||
Links kapaLinks `json:"links"` // Links are URI locations related to kapacitor
|
Links kapaLinks `json:"links"` // Links are URI locations related to kapacitor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) NewKapacitor(w http.ResponseWriter, r *http.Request) {
|
// NewKapacitor adds valid kapacitor store store.
|
||||||
|
func (h *Service) NewKapacitor(w http.ResponseWriter, r *http.Request) {
|
||||||
srcID, err := paramID("id", r)
|
srcID, err := paramID("id", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -91,6 +92,7 @@ func (h *Store) NewKapacitor(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newKapacitor(srv chronograf.Server) kapacitor {
|
func newKapacitor(srv chronograf.Server) kapacitor {
|
||||||
|
httpAPISrcs := "/chronograf/v1/sources"
|
||||||
return kapacitor{
|
return kapacitor{
|
||||||
ID: strconv.Itoa(srv.ID),
|
ID: strconv.Itoa(srv.ID),
|
||||||
Name: srv.Name,
|
Name: srv.Name,
|
||||||
|
@ -108,7 +110,8 @@ type kapacitors struct {
|
||||||
Kapacitors []kapacitor `json:"kapacitors"`
|
Kapacitors []kapacitor `json:"kapacitors"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) Kapacitors(w http.ResponseWriter, r *http.Request) {
|
// Kapacitors retrieves all kapacitors from store.
|
||||||
|
func (h *Service) Kapacitors(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
mrSrvs, err := h.ServersStore.All(ctx)
|
mrSrvs, err := h.ServersStore.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -128,7 +131,8 @@ func (h *Store) Kapacitors(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusOK, res, h.Logger)
|
encodeJSON(w, http.StatusOK, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) KapacitorsID(w http.ResponseWriter, r *http.Request) {
|
// KapacitorsID retrieves a kapacitor with ID from store.
|
||||||
|
func (h *Service) KapacitorsID(w http.ResponseWriter, r *http.Request) {
|
||||||
id, err := paramID("kid", r)
|
id, err := paramID("kid", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -152,7 +156,8 @@ func (h *Store) KapacitorsID(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusOK, res, h.Logger)
|
encodeJSON(w, http.StatusOK, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) RemoveKapacitor(w http.ResponseWriter, r *http.Request) {
|
// RemoveKapacitor deletes kapacitor from store.
|
||||||
|
func (h *Service) RemoveKapacitor(w http.ResponseWriter, r *http.Request) {
|
||||||
id, err := paramID("kid", r)
|
id, err := paramID("kid", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -199,7 +204,8 @@ func (p *patchKapacitorRequest) Valid() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) UpdateKapacitor(w http.ResponseWriter, r *http.Request) {
|
// UpdateKapacitor incrementally updates a kapacitor definition in the store
|
||||||
|
func (h *Service) UpdateKapacitor(w http.ResponseWriter, r *http.Request) {
|
||||||
id, err := paramID("kid", r)
|
id, err := paramID("kid", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
|
|
@ -15,6 +15,7 @@ type layoutResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLayoutResponse(layout chronograf.Layout) layoutResponse {
|
func newLayoutResponse(layout chronograf.Layout) layoutResponse {
|
||||||
|
httpAPILayouts := "/chronograf/v1/layouts"
|
||||||
href := fmt.Sprintf("%s/%s", httpAPILayouts, layout.ID)
|
href := fmt.Sprintf("%s/%s", httpAPILayouts, layout.ID)
|
||||||
rel := "self"
|
rel := "self"
|
||||||
|
|
||||||
|
@ -27,7 +28,8 @@ func newLayoutResponse(layout chronograf.Layout) layoutResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) NewLayout(w http.ResponseWriter, r *http.Request) {
|
// NewLayout adds a valid layout to store.
|
||||||
|
func (h *Service) NewLayout(w http.ResponseWriter, r *http.Request) {
|
||||||
var layout chronograf.Layout
|
var layout chronograf.Layout
|
||||||
if err := json.NewDecoder(r.Body).Decode(&layout); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&layout); err != nil {
|
||||||
invalidJSON(w)
|
invalidJSON(w)
|
||||||
|
@ -54,7 +56,8 @@ type getLayoutsResponse struct {
|
||||||
Layouts []layoutResponse `json:"layouts"`
|
Layouts []layoutResponse `json:"layouts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) Layouts(w http.ResponseWriter, r *http.Request) {
|
// Layouts retrieves all layouts from store
|
||||||
|
func (h *Service) Layouts(w http.ResponseWriter, r *http.Request) {
|
||||||
// Construct a filter sieve for both applications and measurements
|
// Construct a filter sieve for both applications and measurements
|
||||||
filtered := map[string]bool{}
|
filtered := map[string]bool{}
|
||||||
for _, a := range r.URL.Query()["app"] {
|
for _, a := range r.URL.Query()["app"] {
|
||||||
|
@ -93,7 +96,8 @@ func (h *Store) Layouts(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusOK, res, h.Logger)
|
encodeJSON(w, http.StatusOK, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) LayoutsID(w http.ResponseWriter, r *http.Request) {
|
// LayoutsID retrieves layout with ID from store
|
||||||
|
func (h *Service) LayoutsID(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
id := httprouter.GetParamFromContext(ctx, "id")
|
id := httprouter.GetParamFromContext(ctx, "id")
|
||||||
|
|
||||||
|
@ -107,7 +111,8 @@ func (h *Store) LayoutsID(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusOK, res, h.Logger)
|
encodeJSON(w, http.StatusOK, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) RemoveLayout(w http.ResponseWriter, r *http.Request) {
|
// RemoveLayout deletes layout from store.
|
||||||
|
func (h *Service) RemoveLayout(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
id := httprouter.GetParamFromContext(ctx, "id")
|
id := httprouter.GetParamFromContext(ctx, "id")
|
||||||
|
|
||||||
|
@ -123,7 +128,8 @@ func (h *Store) RemoveLayout(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) UpdateLayout(w http.ResponseWriter, r *http.Request) {
|
// UpdateLayout replaces the layout of ID with new valid layout.
|
||||||
|
func (h *Service) UpdateLayout(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
id := httprouter.GetParamFromContext(ctx, "id")
|
id := httprouter.GetParamFromContext(ctx, "id")
|
||||||
|
|
||||||
|
@ -155,6 +161,7 @@ func (h *Store) UpdateLayout(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusOK, res, h.Logger)
|
encodeJSON(w, http.StatusOK, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidLayoutRequest checks if the layout has valid application, measurement and cells.
|
||||||
func ValidLayoutRequest(l chronograf.Layout) error {
|
func ValidLayoutRequest(l chronograf.Layout) error {
|
||||||
if l.Application == "" || l.Measurement == "" || len(l.Cells) == 0 {
|
if l.Application == "" || l.Measurement == "" || len(l.Cells) == 0 {
|
||||||
return fmt.Errorf("app, measurement, and cells required")
|
return fmt.Errorf("app, measurement, and cells required")
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/influxdata/chronograf"
|
"github.com/influxdata/chronograf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Logger is middleware that logs the request
|
||||||
func Logger(logger chronograf.Logger, next http.Handler) http.Handler {
|
func Logger(logger chronograf.Logger, next http.Handler) http.Handler {
|
||||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||||
logger.
|
logger.
|
||||||
|
|
|
@ -11,7 +11,8 @@ type mapping struct {
|
||||||
Name string `json:"name"` // The application name which will be assigned to the corresponding measurement
|
Name string `json:"name"` // The application name which will be assigned to the corresponding measurement
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) GetMappings(w http.ResponseWriter, r *http.Request) {
|
// GetMappings returns the known mappings of measurements to applications
|
||||||
|
func (h *Service) GetMappings(w http.ResponseWriter, r *http.Request) {
|
||||||
cpu := "cpu"
|
cpu := "cpu"
|
||||||
system := "System"
|
system := "System"
|
||||||
mp := getMappingsResponse{
|
mp := getMappingsResponse{
|
||||||
|
|
119
server/mux.go
119
server/mux.go
|
@ -17,40 +17,18 @@ const (
|
||||||
JSONType = "application/json"
|
JSONType = "application/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// MuxOpts are the options for the router. Mostly related to auth.
|
||||||
httpAPIRoot = "/chronograf/v1/"
|
|
||||||
httpAPILayouts = "/chronograf/v1/layouts"
|
|
||||||
httpAPILayoutsID = "/chronograf/v1/layouts/:id"
|
|
||||||
httpAPIMappings = "/chronograf/v1/mappings"
|
|
||||||
httpAPISrcs = "/chronograf/v1/sources"
|
|
||||||
httpAPISrcsID = "/chronograf/v1/sources/:id"
|
|
||||||
httpAPISrcsIDProxy = "/chronograf/v1/sources/:id/proxy"
|
|
||||||
httpAPISrcsIDKapas = "/chronograf/v1/sources/:id/kapacitors"
|
|
||||||
httpAPISrcsIDKapasID = "/chronograf/v1/sources/:id/kapacitors/:kid"
|
|
||||||
httpAPISrcsIDKapasIDProxy = "/chronograf/v1/sources/:id/kapacitors/:kid/proxy"
|
|
||||||
httpAPIUsrs = "/chronograf/v1/users"
|
|
||||||
httpAPIUsrsID = "/chronograf/v1/users/:id"
|
|
||||||
httpAPIUsrsIDExps = "/chronograf/v1/users/:id/explorations"
|
|
||||||
httpAPIUsrsIDExpsID = "/chronograf/v1/users/:id/explorations/:eid"
|
|
||||||
|
|
||||||
httpOAuth = "/oauth"
|
|
||||||
httpOAuthLogout = "/oauth/logout"
|
|
||||||
httpOAuthGHCallback = "/oauth/github/callback"
|
|
||||||
|
|
||||||
httpSwagger = "/swagger.json"
|
|
||||||
httpDocs = "/docs"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MuxOpts struct {
|
type MuxOpts struct {
|
||||||
Develop bool
|
|
||||||
UseAuth bool
|
|
||||||
TokenSecret string
|
|
||||||
GithubClientID string
|
|
||||||
GithubClientSecret string
|
|
||||||
Logger chronograf.Logger
|
Logger chronograf.Logger
|
||||||
|
Develop bool // Develop loads assets from filesystem instead of bindata
|
||||||
|
UseAuth bool // UseAuth turns on Github OAuth and JWT
|
||||||
|
TokenSecret string // TokenSecret is the JWT secret
|
||||||
|
GithubClientID string // GithubClientID is the GH OAuth id
|
||||||
|
GithubClientSecret string // GithubClientSecret is the GH OAuth secret
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMux(opts MuxOpts, store Store, proxy InfluxProxy) http.Handler {
|
// NewMux attaches all the route handlers; handler returned servers chronograf.
|
||||||
|
func NewMux(opts MuxOpts, service Service) http.Handler {
|
||||||
router := httprouter.New()
|
router := httprouter.New()
|
||||||
|
|
||||||
/* React Application */
|
/* React Application */
|
||||||
|
@ -64,65 +42,65 @@ func NewMux(opts MuxOpts, store Store, proxy InfluxProxy) http.Handler {
|
||||||
router.NotFound = assets
|
router.NotFound = assets
|
||||||
|
|
||||||
/* Documentation */
|
/* Documentation */
|
||||||
router.GET(httpSwagger, Spec())
|
router.GET("/swagger.json", Spec())
|
||||||
router.GET(httpDocs, Redoc(httpSwagger))
|
router.GET("/docs", Redoc("/swagger.json"))
|
||||||
|
|
||||||
/* API */
|
/* API */
|
||||||
// Root Routes returns all top-level routes in the API
|
// Root Routes returns all top-level routes in the API
|
||||||
router.GET(httpAPIRoot, AllRoutes(opts.Logger))
|
router.GET("/chronograf/v1/", AllRoutes(opts.Logger))
|
||||||
|
|
||||||
// Sources
|
// Sources
|
||||||
router.GET(httpAPISrcs, store.Sources)
|
router.GET("/chronograf/v1/sources", service.Sources)
|
||||||
router.POST(httpAPISrcs, store.NewSource)
|
router.POST("/chronograf/v1/sources", service.NewSource)
|
||||||
|
|
||||||
router.GET(httpAPISrcsID, store.SourcesID)
|
router.GET("/chronograf/v1/sources/:id", service.SourcesID)
|
||||||
router.PATCH(httpAPISrcsID, store.UpdateSource)
|
router.PATCH("/chronograf/v1/sources/:id", service.UpdateSource)
|
||||||
router.DELETE(httpAPISrcsID, store.RemoveSource)
|
router.DELETE("/chronograf/v1/sources/:id", service.RemoveSource)
|
||||||
|
|
||||||
// Source Proxy
|
// Source Proxy
|
||||||
router.POST(httpAPISrcsIDProxy, proxy.Proxy)
|
router.POST("/chronograf/v1/sources/:id/proxy", service.Proxy)
|
||||||
|
|
||||||
// Kapacitor
|
// Kapacitor
|
||||||
router.GET(httpAPISrcsIDKapas, store.Kapacitors)
|
router.GET("/chronograf/v1/sources/:id/kapacitors", service.Kapacitors)
|
||||||
router.POST(httpAPISrcsIDKapas, store.NewKapacitor)
|
router.POST("/chronograf/v1/sources/:id/kapacitors", service.NewKapacitor)
|
||||||
|
|
||||||
router.GET(httpAPISrcsIDKapasID, store.KapacitorsID)
|
router.GET("/chronograf/v1/sources/:id/kapacitors/:kid", service.KapacitorsID)
|
||||||
router.PATCH(httpAPISrcsIDKapasID, store.UpdateKapacitor)
|
router.PATCH("/chronograf/v1/sources/:id/kapacitors/:kid", service.UpdateKapacitor)
|
||||||
router.DELETE(httpAPISrcsIDKapasID, store.RemoveKapacitor)
|
router.DELETE("/chronograf/v1/sources/:id/kapacitors/:kid", service.RemoveKapacitor)
|
||||||
|
|
||||||
// Kapacitor Proxy
|
// Kapacitor Proxy
|
||||||
router.GET(httpAPISrcsIDKapasIDProxy, proxy.KapacitorProxyGet)
|
router.GET("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyGet)
|
||||||
router.POST(httpAPISrcsIDKapasIDProxy, proxy.KapacitorProxyPost)
|
router.POST("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyPost)
|
||||||
router.PATCH(httpAPISrcsIDKapasIDProxy, proxy.KapacitorProxyPatch)
|
router.PATCH("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyPatch)
|
||||||
router.DELETE(httpAPISrcsIDKapasIDProxy, proxy.KapacitorProxyDelete)
|
router.DELETE("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyDelete)
|
||||||
|
|
||||||
// Mappings
|
// Mappings
|
||||||
router.GET(httpAPIMappings, store.GetMappings)
|
router.GET("/chronograf/v1/mappings", service.GetMappings)
|
||||||
|
|
||||||
// Layouts
|
// Layouts
|
||||||
router.GET(httpAPILayouts, store.Layouts)
|
router.GET("/chronograf/v1/layouts", service.Layouts)
|
||||||
router.POST(httpAPILayouts, store.NewLayout)
|
router.POST("/chronograf/v1/layouts", service.NewLayout)
|
||||||
|
|
||||||
router.GET(httpAPILayoutsID, store.LayoutsID)
|
router.GET("/chronograf/v1/layouts/:id", service.LayoutsID)
|
||||||
router.PUT(httpAPILayoutsID, store.UpdateLayout)
|
router.PUT("/chronograf/v1/layouts/:id", service.UpdateLayout)
|
||||||
router.DELETE(httpAPILayoutsID, store.RemoveLayout)
|
router.DELETE("/chronograf/v1/layouts/:id", service.RemoveLayout)
|
||||||
|
|
||||||
// Users
|
// Users
|
||||||
/*
|
/*
|
||||||
router.GET(httpAPIUsrs, Users)
|
router.GET("/chronograf/v1/users", Users)
|
||||||
router.POST(httpAPIUsrs, NewUser)
|
router.POST("/chronograf/v1/users", NewUser)
|
||||||
|
|
||||||
router.GET(httpAPIUsrsID, UsersID)
|
router.GET("/chronograf/v1/users/:id", UsersID)
|
||||||
router.PATCH(httpAPIUsrsID, UpdateUser)
|
router.PATCH("/chronograf/v1/users/:id", UpdateUser)
|
||||||
router.DELETE(httpAPIUsrsID, RemoveUser)
|
router.DELETE("/chronograf/v1/users/:id", RemoveUser)
|
||||||
*/
|
*/
|
||||||
// Explorations
|
// Explorations
|
||||||
router.GET(httpAPIUsrsIDExps, store.Explorations)
|
router.GET("/chronograf/v1/users/:id/explorations", service.Explorations)
|
||||||
router.POST(httpAPIUsrsIDExps, store.NewExploration)
|
router.POST("/chronograf/v1/users/:id/explorations", service.NewExploration)
|
||||||
|
|
||||||
router.GET(httpAPIUsrsIDExpsID, store.ExplorationsID)
|
router.GET("/chronograf/v1/users/:id/explorations/:eid", service.ExplorationsID)
|
||||||
router.PATCH(httpAPIUsrsIDExpsID, store.UpdateExploration)
|
router.PATCH("/chronograf/v1/users/:id/explorations/:eid", service.UpdateExploration)
|
||||||
router.DELETE(httpAPIUsrsIDExpsID, store.RemoveExploration)
|
router.DELETE("/chronograf/v1/users/:id/explorations/:eid", service.RemoveExploration)
|
||||||
|
|
||||||
/* Authentication */
|
/* Authentication */
|
||||||
if opts.UseAuth {
|
if opts.UseAuth {
|
||||||
|
@ -132,6 +110,7 @@ func NewMux(opts MuxOpts, store Store, proxy InfluxProxy) http.Handler {
|
||||||
return Logger(opts.Logger, router)
|
return Logger(opts.Logger, router)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthAPI adds the OAuth routes if auth is enabled.
|
||||||
func AuthAPI(opts MuxOpts, router *httprouter.Router) http.Handler {
|
func AuthAPI(opts MuxOpts, router *httprouter.Router) http.Handler {
|
||||||
auth := jwt.NewJWT(opts.TokenSecret)
|
auth := jwt.NewJWT(opts.TokenSecret)
|
||||||
|
|
||||||
|
@ -146,19 +125,18 @@ func AuthAPI(opts MuxOpts, router *httprouter.Router) http.Handler {
|
||||||
opts.Logger,
|
opts.Logger,
|
||||||
)
|
)
|
||||||
|
|
||||||
router.GET(httpOAuth, gh.Login())
|
router.GET("/oauth", gh.Login())
|
||||||
router.GET(httpOAuthLogout, gh.Logout())
|
router.GET("/oauth/logout", gh.Logout())
|
||||||
router.GET(httpOAuthGHCallback, gh.Callback())
|
router.GET("/oauth/github/callback", gh.Callback())
|
||||||
|
|
||||||
tokenMiddleware := AuthorizedToken(&auth, &CookieExtractor{Name: "session"}, opts.Logger, router)
|
tokenMiddleware := AuthorizedToken(&auth, &CookieExtractor{Name: "session"}, opts.Logger, router)
|
||||||
// Wrap the API with token validation middleware.
|
// Wrap the API with token validation middleware.
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if strings.HasPrefix(r.URL.Path, httpAPIRoot) {
|
if strings.HasPrefix(r.URL.Path, "/chronograf/v1/") {
|
||||||
tokenMiddleware.ServeHTTP(w, r)
|
tokenMiddleware.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
router.ServeHTTP(w, r)
|
|
||||||
}
|
}
|
||||||
|
router.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +148,7 @@ func encodeJSON(w http.ResponseWriter, status int, v interface{}, logger chronog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error writes an JSON message
|
||||||
func Error(w http.ResponseWriter, code int, msg string) {
|
func Error(w http.ResponseWriter, code int, msg string) {
|
||||||
e := struct {
|
e := struct {
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
|
|
|
@ -10,13 +10,7 @@ import (
|
||||||
"github.com/influxdata/chronograf"
|
"github.com/influxdata/chronograf"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InfluxProxy struct {
|
// ValidProxyRequest checks if queries specify a command.
|
||||||
Srcs chronograf.SourcesStore
|
|
||||||
ServersStore chronograf.ServersStore
|
|
||||||
TimeSeries chronograf.TimeSeries
|
|
||||||
Logger chronograf.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidProxyRequest(p chronograf.Query) error {
|
func ValidProxyRequest(p chronograf.Query) error {
|
||||||
if p.Command == "" {
|
if p.Command == "" {
|
||||||
return fmt.Errorf("query field required")
|
return fmt.Errorf("query field required")
|
||||||
|
@ -28,7 +22,8 @@ type postProxyResponse struct {
|
||||||
Results interface{} `json:"results"` // results from influx
|
Results interface{} `json:"results"` // results from influx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *InfluxProxy) Proxy(w http.ResponseWriter, r *http.Request) {
|
// Proxy proxies requests to infludb.
|
||||||
|
func (h *Service) Proxy(w http.ResponseWriter, r *http.Request) {
|
||||||
id, err := paramID("id", r)
|
id, err := paramID("id", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -46,7 +41,7 @@ func (h *InfluxProxy) Proxy(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
src, err := h.Srcs.Get(ctx, id)
|
src, err := h.SourcesStore.Get(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
notFound(w, id)
|
notFound(w, id)
|
||||||
return
|
return
|
||||||
|
@ -76,7 +71,8 @@ func (h *InfluxProxy) Proxy(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusOK, res, h.Logger)
|
encodeJSON(w, http.StatusOK, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *InfluxProxy) KapacitorProxy(w http.ResponseWriter, r *http.Request) {
|
// KapacitorProxy proxies requests to kapacitor using the path query parameter.
|
||||||
|
func (h *Service) KapacitorProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
srcID, err := paramID("id", r)
|
srcID, err := paramID("id", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -123,18 +119,22 @@ func (h *InfluxProxy) KapacitorProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
proxy.ServeHTTP(w, r)
|
proxy.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *InfluxProxy) KapacitorProxyPost(w http.ResponseWriter, r *http.Request) {
|
// KapacitorProxyPost proxies POST to kapacitor
|
||||||
|
func (h *Service) KapacitorProxyPost(w http.ResponseWriter, r *http.Request) {
|
||||||
h.KapacitorProxy(w, r)
|
h.KapacitorProxy(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *InfluxProxy) KapacitorProxyPatch(w http.ResponseWriter, r *http.Request) {
|
// KapacitorProxyPatch proxies PATCH to kapacitor
|
||||||
|
func (h *Service) KapacitorProxyPatch(w http.ResponseWriter, r *http.Request) {
|
||||||
h.KapacitorProxy(w, r)
|
h.KapacitorProxy(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *InfluxProxy) KapacitorProxyGet(w http.ResponseWriter, r *http.Request) {
|
// KapacitorProxyGet proxies GET to kapacitor
|
||||||
|
func (h *Service) KapacitorProxyGet(w http.ResponseWriter, r *http.Request) {
|
||||||
h.KapacitorProxy(w, r)
|
h.KapacitorProxy(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *InfluxProxy) KapacitorProxyDelete(w http.ResponseWriter, r *http.Request) {
|
// KapacitorProxyDelete proxies DELETE to kapacitor
|
||||||
|
func (h *Service) KapacitorProxyDelete(w http.ResponseWriter, r *http.Request) {
|
||||||
h.KapacitorProxy(w, r)
|
h.KapacitorProxy(w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ const index = `<!DOCTYPE html>
|
||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// Redoc servers the swagger JSON using the redoc package.
|
||||||
func Redoc(swagger string) http.HandlerFunc {
|
func Redoc(swagger string) http.HandlerFunc {
|
||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
|
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
|
|
@ -13,12 +13,13 @@ type getRoutesResponse struct {
|
||||||
Users string `json:"users"` // Location of the users endpoint
|
Users string `json:"users"` // Location of the users endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllRoutes returns all top level routes within chronograf
|
||||||
func AllRoutes(logger chronograf.Logger) http.HandlerFunc {
|
func AllRoutes(logger chronograf.Logger) http.HandlerFunc {
|
||||||
routes := getRoutesResponse{
|
routes := getRoutesResponse{
|
||||||
Sources: httpAPISrcs,
|
Sources: "/chronograf/v1/sources",
|
||||||
Layouts: httpAPILayouts,
|
Layouts: "/chronograf/v1/layouts",
|
||||||
Users: httpAPIUsrs,
|
Users: "/chronograf/v1/users",
|
||||||
Mappings: httpAPIMappings,
|
Mappings: "/chronograf/v1/mappings",
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
111
server/server.go
111
server/server.go
|
@ -1,11 +1,9 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/influxdata/chronograf"
|
"github.com/influxdata/chronograf"
|
||||||
|
@ -19,7 +17,7 @@ import (
|
||||||
"github.com/tylerb/graceful"
|
"github.com/tylerb/graceful"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logger chronograf.Logger = clog.New()
|
var logger = clog.New()
|
||||||
|
|
||||||
// Server for the chronograf API
|
// Server for the chronograf API
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
@ -38,73 +36,82 @@ type Server struct {
|
||||||
GithubClientID string `short:"i" long:"github-client-id" description:"Github Client ID for OAuth 2 support" env:"GH_CLIENT_ID"`
|
GithubClientID string `short:"i" long:"github-client-id" description:"Github Client ID for OAuth 2 support" env:"GH_CLIENT_ID"`
|
||||||
GithubClientSecret string `short:"s" long:"github-client-secret" description:"Github Client Secret for OAuth 2 support" env:"GH_CLIENT_SECRET"`
|
GithubClientSecret string `short:"s" long:"github-client-secret" description:"Github Client Secret for OAuth 2 support" env:"GH_CLIENT_SECRET"`
|
||||||
|
|
||||||
httpServerL net.Listener
|
Listener net.Listener
|
||||||
handler http.Handler
|
handler http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) useAuth() bool {
|
||||||
|
return s.TokenSecret != "" && s.GithubClientID != "" && s.GithubClientSecret != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve starts and runs the chronograf server
|
||||||
func (s *Server) Serve() error {
|
func (s *Server) Serve() error {
|
||||||
c := bolt.NewClient()
|
service := openService(s.BoltPath, s.CannedPath)
|
||||||
c.Path = s.BoltPath
|
|
||||||
if err := c.Open(); err != nil {
|
|
||||||
logger.WithField("component", "boltstore").Panic("Unable to open boltdb; is there a mrfusion already running?", err)
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
apps := canned.NewApps(s.CannedPath, &uuid.V4{})
|
|
||||||
|
|
||||||
// allLayouts acts as a front-end to both the bolt layouts and the filesystem layouts.
|
|
||||||
allLayouts := &layouts.MultiLayoutStore{
|
|
||||||
Stores: []chronograf.LayoutStore{
|
|
||||||
c.LayoutStore,
|
|
||||||
apps,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
h := Store{
|
|
||||||
ExplorationStore: c.ExplorationStore,
|
|
||||||
SourcesStore: c.SourcesStore,
|
|
||||||
ServersStore: c.ServersStore,
|
|
||||||
LayoutStore: allLayouts,
|
|
||||||
}
|
|
||||||
|
|
||||||
p := InfluxProxy{
|
|
||||||
Srcs: c.SourcesStore,
|
|
||||||
TimeSeries: &influx.Client{},
|
|
||||||
ServersStore: c.ServersStore,
|
|
||||||
}
|
|
||||||
|
|
||||||
useAuth := s.TokenSecret != "" && s.GithubClientID != "" && s.GithubClientSecret != ""
|
|
||||||
s.handler = NewMux(MuxOpts{
|
s.handler = NewMux(MuxOpts{
|
||||||
Develop: s.Develop,
|
Develop: s.Develop,
|
||||||
TokenSecret: s.TokenSecret,
|
TokenSecret: s.TokenSecret,
|
||||||
GithubClientID: s.GithubClientID,
|
GithubClientID: s.GithubClientID,
|
||||||
GithubClientSecret: s.GithubClientSecret,
|
GithubClientSecret: s.GithubClientSecret,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
UseAuth: useAuth,
|
UseAuth: s.useAuth(),
|
||||||
}, h, p)
|
}, service)
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)))
|
var err error
|
||||||
|
s.Listener, err = net.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.
|
||||||
|
WithField("component", "server").
|
||||||
|
Error(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.httpServerL = listener
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
|
|
||||||
httpServer := &graceful.Server{Server: new(http.Server)}
|
httpServer := &graceful.Server{Server: new(http.Server)}
|
||||||
httpServer.SetKeepAlivesEnabled(true)
|
httpServer.SetKeepAlivesEnabled(true)
|
||||||
httpServer.TCPKeepAlive = 3 * time.Minute
|
httpServer.TCPKeepAlive = 1 * time.Minute
|
||||||
httpServer.Handler = s.handler
|
httpServer.Handler = s.handler
|
||||||
|
|
||||||
wg.Add(1)
|
logger.
|
||||||
log.Printf("Serving chronograf at http://%s", s.httpServerL.Addr())
|
WithField("component", "server").
|
||||||
go func(l net.Listener) {
|
Info("Serving chronograf at http://%s", s.Listener.Addr())
|
||||||
defer wg.Done()
|
|
||||||
if err := httpServer.Serve(l); err != nil {
|
if err := httpServer.Serve(s.Listener); err != nil {
|
||||||
log.Fatalf("%v", err)
|
logger.
|
||||||
}
|
WithField("component", "server").
|
||||||
log.Printf("Stopped serving chronograf at http://%s", l.Addr())
|
Error(err)
|
||||||
}(s.httpServerL)
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.
|
||||||
|
WithField("component", "server").
|
||||||
|
Info("Stopped serving chronograf at http://%s", s.Listener.Addr())
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func openService(boltPath, cannedPath string) Service {
|
||||||
|
db := bolt.NewClient()
|
||||||
|
db.Path = boltPath
|
||||||
|
if err := db.Open(); err != nil {
|
||||||
|
logger.
|
||||||
|
WithField("component", "boltstore").
|
||||||
|
Panic("Unable to open boltdb; is there a mrfusion already running?", err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
apps := canned.NewApps(cannedPath, &uuid.V4{})
|
||||||
|
// Acts as a front-end to both the bolt layouts and the filesystem layouts.
|
||||||
|
layouts := &layouts.MultiLayoutStore{
|
||||||
|
Stores: []chronograf.LayoutStore{
|
||||||
|
db.LayoutStore,
|
||||||
|
apps,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return Service{
|
||||||
|
ExplorationStore: db.ExplorationStore,
|
||||||
|
SourcesStore: db.SourcesStore,
|
||||||
|
ServersStore: db.ServersStore,
|
||||||
|
TimeSeries: &influx.Client{},
|
||||||
|
LayoutStore: layouts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,11 +2,12 @@ package server
|
||||||
|
|
||||||
import "github.com/influxdata/chronograf"
|
import "github.com/influxdata/chronograf"
|
||||||
|
|
||||||
// Store handles REST calls to the persistence
|
// Service handles REST calls to the persistence
|
||||||
type Store struct {
|
type Service struct {
|
||||||
ExplorationStore chronograf.ExplorationStore
|
ExplorationStore chronograf.ExplorationStore
|
||||||
SourcesStore chronograf.SourcesStore
|
SourcesStore chronograf.SourcesStore
|
||||||
ServersStore chronograf.ServersStore
|
ServersStore chronograf.ServersStore
|
||||||
LayoutStore chronograf.LayoutStore
|
LayoutStore chronograf.LayoutStore
|
||||||
|
TimeSeries chronograf.TimeSeries
|
||||||
Logger chronograf.Logger
|
Logger chronograf.Logger
|
||||||
}
|
}
|
|
@ -21,6 +21,7 @@ type sourceResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSourceResponse(src chronograf.Source) sourceResponse {
|
func newSourceResponse(src chronograf.Source) sourceResponse {
|
||||||
|
httpAPISrcs := "/chronograf/v1/sources"
|
||||||
return sourceResponse{
|
return sourceResponse{
|
||||||
Source: src,
|
Source: src,
|
||||||
Links: sourceLinks{
|
Links: sourceLinks{
|
||||||
|
@ -31,7 +32,8 @@ func newSourceResponse(src chronograf.Source) sourceResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) NewSource(w http.ResponseWriter, r *http.Request) {
|
// NewSource adds a new valid source to the store
|
||||||
|
func (h *Service) NewSource(w http.ResponseWriter, r *http.Request) {
|
||||||
var src chronograf.Source
|
var src chronograf.Source
|
||||||
if err := json.NewDecoder(r.Body).Decode(&src); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&src); err != nil {
|
||||||
invalidJSON(w)
|
invalidJSON(w)
|
||||||
|
@ -58,7 +60,8 @@ type getSourcesResponse struct {
|
||||||
Sources []sourceResponse `json:"sources"`
|
Sources []sourceResponse `json:"sources"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) Sources(w http.ResponseWriter, r *http.Request) {
|
// Sources returns all sources from the store.
|
||||||
|
func (h *Service) Sources(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
srcs, err := h.SourcesStore.All(ctx)
|
srcs, err := h.SourcesStore.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -77,7 +80,8 @@ func (h *Store) Sources(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusOK, res, h.Logger)
|
encodeJSON(w, http.StatusOK, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) SourcesID(w http.ResponseWriter, r *http.Request) {
|
// SourcesID retrieves a source from the store
|
||||||
|
func (h *Service) SourcesID(w http.ResponseWriter, r *http.Request) {
|
||||||
id, err := paramID("id", r)
|
id, err := paramID("id", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -95,7 +99,8 @@ func (h *Store) SourcesID(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusOK, res, h.Logger)
|
encodeJSON(w, http.StatusOK, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) RemoveSource(w http.ResponseWriter, r *http.Request) {
|
// RemoveSource deletes the source from the store
|
||||||
|
func (h *Service) RemoveSource(w http.ResponseWriter, r *http.Request) {
|
||||||
id, err := paramID("id", r)
|
id, err := paramID("id", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -112,7 +117,8 @@ func (h *Store) RemoveSource(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Store) UpdateSource(w http.ResponseWriter, r *http.Request) {
|
// UpdateSource handles incremental updates of a data source
|
||||||
|
func (h *Service) UpdateSource(w http.ResponseWriter, r *http.Request) {
|
||||||
id, err := paramID("id", r)
|
id, err := paramID("id", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusUnprocessableEntity, err.Error())
|
Error(w, http.StatusUnprocessableEntity, err.Error())
|
||||||
|
@ -162,6 +168,7 @@ func (h *Store) UpdateSource(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusOK, newSourceResponse(src), h.Logger)
|
encodeJSON(w, http.StatusOK, newSourceResponse(src), h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidSourceRequest checks if name, url and type are valid
|
||||||
func ValidSourceRequest(s chronograf.Source) error {
|
func ValidSourceRequest(s chronograf.Source) error {
|
||||||
// Name and URL areq required
|
// Name and URL areq required
|
||||||
if s.Name == "" || s.URL == "" {
|
if s.Name == "" || s.URL == "" {
|
||||||
|
|
|
@ -4,6 +4,7 @@ package server
|
||||||
|
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
||||||
|
// Spec servers the swagger.json file from bindata
|
||||||
func Spec() http.HandlerFunc {
|
func Spec() http.HandlerFunc {
|
||||||
swagger, err := Asset("swagger.json")
|
swagger, err := Asset("swagger.json")
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
Loading…
Reference in New Issue