diff --git a/Gopkg.toml b/Gopkg.toml index 48bab20af9..d593ba5459 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -72,6 +72,9 @@ required = ["github.com/kevinburke/go-bindata","github.com/gogo/protobuf/proto", name = "github.com/influxdata/influxdb" version = "~1.1.0" +[[constraint]] + name = "github.com/influxdata/ifql" + revision = "master" [[constraint]] name = "github.com/influxdata/kapacitor" diff --git a/Makefile b/Makefile index 13b501e219..2aae583c55 100644 --- a/Makefile +++ b/Makefile @@ -124,3 +124,6 @@ clean: ctags: ctags -R --languages="Go" --exclude=.git --exclude=ui . + +lint: + cd ui && yarn prettier diff --git a/server/ifql.go b/server/ifql.go new file mode 100644 index 0000000000..9a4ba9088e --- /dev/null +++ b/server/ifql.go @@ -0,0 +1,41 @@ +package server + +import ( + "net/http" + + "github.com/bouk/httprouter" + "github.com/influxdata/ifql" +) + +// SuggestionsResponse provides a list of available IFQL functions +type SuggestionsResponse struct { + Functions []string `json:"funcs"` +} + +// SuggestionResponse provides the parameters available for a given IFQL function +type SuggestionResponse struct { + Params map[string]string `json:"params"` +} + +// IFQLSuggestions returns a list of available IFQL functions for the IFQL Builder +func (s *Service) IFQLSuggestions(w http.ResponseWriter, r *http.Request) { + completer := ifql.DefaultCompleter() + names := completer.FunctionNames() + res := SuggestionsResponse{Functions: names} + + encodeJSON(w, http.StatusOK, res, s.Logger) +} + +// IFQLSuggestion returns the function parameters for the requested function +func (s *Service) IFQLSuggestion(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + name := httprouter.GetParamFromContext(ctx, "name") + completer := ifql.DefaultCompleter() + + res, err := completer.FunctionSuggestion(name) + if err != nil { + Error(w, http.StatusNotFound, err.Error(), s.Logger) + } + + encodeJSON(w, http.StatusOK, SuggestionResponse(res), s.Logger) +} diff --git a/server/links.go b/server/links.go index 3a3b3fd41d..ceda0db92a 100644 --- a/server/links.go +++ b/server/links.go @@ -5,6 +5,11 @@ import ( "net/url" ) +type getIFQLLinksResponse struct { + Self string `json:"self"` + Suggestions string `json:"suggestions"` +} + type getConfigLinksResponse struct { Self string `json:"self"` // Location of the whole global application configuration Auth string `json:"auth"` // Location of the auth section of the global application configuration diff --git a/server/mux.go b/server/mux.go index cf8d1d83ec..827cbf087b 100644 --- a/server/mux.go +++ b/server/mux.go @@ -156,6 +156,9 @@ func NewMux(opts MuxOpts, service Service) http.Handler { router.PATCH("/chronograf/v1/sources/:id", EnsureEditor(service.UpdateSource)) router.DELETE("/chronograf/v1/sources/:id", EnsureEditor(service.RemoveSource)) + router.GET("/chronograf/v1/ifql/suggestions", EnsureViewer(service.IFQLSuggestions)) + router.GET("/chronograf/v1/ifql/suggestions/:name", EnsureViewer(service.IFQLSuggestion)) + // Source Proxy to Influx; Has gzip compression around the handler influx := gziphandler.GzipHandler(http.HandlerFunc(EnsureViewer(service.Influx))) router.Handler("POST", "/chronograf/v1/sources/:id/proxy", influx) diff --git a/server/routes.go b/server/routes.go index a74cd6b9e2..f275deea30 100644 --- a/server/routes.go +++ b/server/routes.go @@ -44,6 +44,7 @@ type getRoutesResponse struct { Auth []AuthRoute `json:"auth"` // Location of all auth routes. Logout *string `json:"logout,omitempty"` // Location of the logout route for all auth routes ExternalLinks getExternalLinksResponse `json:"external"` // All external links for the client to use + IFQL getIFQLLinksResponse `json:"ifql"` } // AllRoutes is a handler that returns all links to resources in Chronograf server, as well as @@ -94,6 +95,10 @@ func (a *AllRoutes) ServeHTTP(w http.ResponseWriter, r *http.Request) { StatusFeed: &a.StatusFeed, CustomLinks: customLinks, }, + IFQL: getIFQLLinksResponse{ + Self: "/chronograf/v1/ifql", + Suggestions: "/chronograf/v1/ifql/suggestions", + }, } // The JSON response will have no field present for the LogoutLink if there is no logout link.