chronograf/restapi/configure_chronograf.go

312 lines
13 KiB
Go

package restapi
import (
"crypto/tls"
"fmt"
"net/http"
"strings"
errors "github.com/go-openapi/errors"
runtime "github.com/go-openapi/runtime"
middleware "github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/swag"
"golang.org/x/net/context"
"github.com/influxdata/chronograf"
"github.com/influxdata/chronograf/bolt"
"github.com/influxdata/chronograf/canned"
"github.com/influxdata/chronograf/handlers"
"github.com/influxdata/chronograf/influx"
"github.com/influxdata/chronograf/jwt"
"github.com/influxdata/chronograf/kapacitor"
"github.com/influxdata/chronograf/layouts"
clog "github.com/influxdata/chronograf/log"
"github.com/influxdata/chronograf/mock"
op "github.com/influxdata/chronograf/restapi/operations"
"github.com/influxdata/chronograf/uuid"
)
// This file is safe to edit. Once it exists it will not be overwritten
//go:generate swagger generate server --target .. --name --spec ../swagger.yaml --with-context
var logger chronograf.Logger = clog.New()
var devFlags = struct {
Develop bool `short:"d" long:"develop" description:"Run server in develop mode."`
}{}
var storeFlags = struct {
BoltPath string `short:"b" long:"bolt-path" description:"Full path to boltDB file (/Users/somebody/chronograf.db)" env:"BOLT_PATH" default:"chronograf.db"`
}{}
var cannedFlags = struct {
CannedPath string `short:"c" long:"canned-path" description:"Path to directory of pre-canned application layouts" env:"CANNED_PATH" default:"canned"`
}{}
var authFlags = struct {
TokenSecret string `short:"t" long:"token-secret" description:"Secret to sign tokens" env:"TOKEN_SECRET"`
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"`
}{}
func configureFlags(api *op.ChronografAPI) {
api.CommandLineOptionsGroups = []swag.CommandLineOptionsGroup{
swag.CommandLineOptionsGroup{
ShortDescription: "Develop Mode server",
LongDescription: "Server will use the ui/build directory directly.",
Options: &devFlags,
},
swag.CommandLineOptionsGroup{
ShortDescription: "Default Store Backend",
LongDescription: "Specify the path to a BoltDB file",
Options: &storeFlags,
},
swag.CommandLineOptionsGroup{
ShortDescription: "Directory of pre-canned layouts",
LongDescription: "Specify the path to a directory of pre-canned application layout files.",
Options: &cannedFlags,
},
swag.CommandLineOptionsGroup{
ShortDescription: "Server Authentication",
LongDescription: "Server will use authentication",
Options: &authFlags,
},
}
}
func configureAPI(api *op.ChronografAPI) http.Handler {
// configure the api here
api.ServeError = errors.ServeError
// Set your custom logger if needed. Default one is log.Printf
// Expected interface func(string, ...interface{})
//
// Example:
api.Logger = func(msg string, args ...interface{}) {
logger.
WithField("component", "api").
Info(fmt.Sprintf(msg, args))
}
api.JSONConsumer = runtime.JSONConsumer()
api.JSONProducer = runtime.JSONProducer()
mockHandler := mock.NewHandler()
api.GetHandler = op.GetHandlerFunc(mockHandler.AllRoutes)
if len(storeFlags.BoltPath) > 0 {
c := bolt.NewClient()
c.Path = storeFlags.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(cannedFlags.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 := handlers.Store{
ExplorationStore: c.ExplorationStore,
SourcesStore: c.SourcesStore,
ServersStore: c.ServersStore,
LayoutStore: allLayouts,
}
api.GetTokenHandler = op.GetTokenHandlerFunc(mockHandler.Token)
api.DeleteUsersUserIDExplorationsExplorationIDHandler = op.DeleteUsersUserIDExplorationsExplorationIDHandlerFunc(h.DeleteExploration)
api.GetUsersUserIDExplorationsExplorationIDHandler = op.GetUsersUserIDExplorationsExplorationIDHandlerFunc(h.Exploration)
api.GetUsersUserIDExplorationsHandler = op.GetUsersUserIDExplorationsHandlerFunc(h.Explorations)
api.PatchUsersUserIDExplorationsExplorationIDHandler = op.PatchUsersUserIDExplorationsExplorationIDHandlerFunc(h.UpdateExploration)
api.PostUsersUserIDExplorationsHandler = op.PostUsersUserIDExplorationsHandlerFunc(h.NewExploration)
api.DeleteSourcesIDHandler = op.DeleteSourcesIDHandlerFunc(h.RemoveSource)
api.PatchSourcesIDHandler = op.PatchSourcesIDHandlerFunc(h.UpdateSource)
api.GetSourcesHandler = op.GetSourcesHandlerFunc(h.Sources)
api.GetSourcesIDHandler = op.GetSourcesIDHandlerFunc(h.SourcesID)
api.PostSourcesHandler = op.PostSourcesHandlerFunc(h.NewSource)
api.GetSourcesIDKapacitorsHandler = op.GetSourcesIDKapacitorsHandlerFunc(h.Kapacitors)
api.PostSourcesIDKapacitorsHandler = op.PostSourcesIDKapacitorsHandlerFunc(h.NewKapacitor)
api.GetSourcesIDKapacitorsKapaIDHandler = op.GetSourcesIDKapacitorsKapaIDHandlerFunc(h.KapacitorsID)
api.DeleteSourcesIDKapacitorsKapaIDHandler = op.DeleteSourcesIDKapacitorsKapaIDHandlerFunc(h.RemoveKapacitor)
api.PatchSourcesIDKapacitorsKapaIDHandler = op.PatchSourcesIDKapacitorsKapaIDHandlerFunc(h.UpdateKapacitor)
p := handlers.InfluxProxy{
Srcs: c.SourcesStore,
TimeSeries: &influx.Client{},
KapacitorProxy: &kapacitor.Proxy{},
ServersStore: c.ServersStore,
}
api.PostSourcesIDProxyHandler = op.PostSourcesIDProxyHandlerFunc(p.Proxy)
api.PostSourcesIDKapacitorsKapaIDProxyHandler = op.PostSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyPost)
api.PatchSourcesIDKapacitorsKapaIDProxyHandler = op.PatchSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyPatch)
api.GetSourcesIDKapacitorsKapaIDProxyHandler = op.GetSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyGet)
api.DeleteSourcesIDKapacitorsKapaIDProxyHandler = op.DeleteSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyDelete)
api.DeleteLayoutsIDHandler = op.DeleteLayoutsIDHandlerFunc(h.RemoveLayout)
api.GetLayoutsHandler = op.GetLayoutsHandlerFunc(h.Layouts)
api.GetLayoutsIDHandler = op.GetLayoutsIDHandlerFunc(h.LayoutsID)
api.PostLayoutsHandler = op.PostLayoutsHandlerFunc(h.NewLayout)
api.PutLayoutsIDHandler = op.PutLayoutsIDHandlerFunc(h.UpdateLayout)
} else {
api.DeleteUsersUserIDExplorationsExplorationIDHandler = op.DeleteUsersUserIDExplorationsExplorationIDHandlerFunc(mockHandler.DeleteExploration)
api.GetUsersUserIDExplorationsExplorationIDHandler = op.GetUsersUserIDExplorationsExplorationIDHandlerFunc(mockHandler.Exploration)
api.GetUsersUserIDExplorationsHandler = op.GetUsersUserIDExplorationsHandlerFunc(mockHandler.Explorations)
api.PatchUsersUserIDExplorationsExplorationIDHandler = op.PatchUsersUserIDExplorationsExplorationIDHandlerFunc(mockHandler.UpdateExploration)
api.PostUsersUserIDExplorationsHandler = op.PostUsersUserIDExplorationsHandlerFunc(mockHandler.NewExploration)
api.DeleteSourcesIDHandler = op.DeleteSourcesIDHandlerFunc(mockHandler.RemoveSource)
api.PatchSourcesIDHandler = op.PatchSourcesIDHandlerFunc(mockHandler.UpdateSource)
api.GetSourcesHandler = op.GetSourcesHandlerFunc(mockHandler.Sources)
api.GetSourcesIDHandler = op.GetSourcesIDHandlerFunc(mockHandler.SourcesID)
api.PostSourcesHandler = op.PostSourcesHandlerFunc(mockHandler.NewSource)
api.PostSourcesIDProxyHandler = op.PostSourcesIDProxyHandlerFunc(mockHandler.Proxy)
}
api.DeleteSourcesIDRolesRoleIDHandler = op.DeleteSourcesIDRolesRoleIDHandlerFunc(func(ctx context.Context, params op.DeleteSourcesIDRolesRoleIDParams) middleware.Responder {
return middleware.NotImplemented("operation .DeleteSourcesIDRolesRoleID has not yet been implemented")
})
api.DeleteUsersUserIDHandler = op.DeleteUsersUserIDHandlerFunc(func(ctx context.Context, params op.DeleteUsersUserIDParams) middleware.Responder {
return middleware.NotImplemented("operation .DeleteUsersUserID has not yet been implemented")
})
api.GetSourcesIDPermissionsHandler = op.GetSourcesIDPermissionsHandlerFunc(func(ctx context.Context, params op.GetSourcesIDPermissionsParams) middleware.Responder {
return middleware.NotImplemented("operation .GetSourcesIDPermissions has not yet been implemented")
})
api.GetSourcesIDRolesHandler = op.GetSourcesIDRolesHandlerFunc(func(ctx context.Context, params op.GetSourcesIDRolesParams) middleware.Responder {
return middleware.NotImplemented("operation .GetSourcesIDRoles has not yet been implemented")
})
api.GetSourcesIDRolesRoleIDHandler = op.GetSourcesIDRolesRoleIDHandlerFunc(func(ctx context.Context, params op.GetSourcesIDRolesRoleIDParams) middleware.Responder {
return middleware.NotImplemented("operation .GetSourcesIDRolesRoleID has not yet been implemented")
})
api.GetUsersHandler = op.GetUsersHandlerFunc(func(ctx context.Context, params op.GetUsersParams) middleware.Responder {
return middleware.NotImplemented("operation .GetUsers has not yet been implemented")
})
api.GetUsersUserIDHandler = op.GetUsersUserIDHandlerFunc(func(ctx context.Context, params op.GetUsersUserIDParams) middleware.Responder {
return middleware.NotImplemented("operation .GetUsersUserID has not yet been implemented")
})
api.PatchSourcesIDRolesRoleIDHandler = op.PatchSourcesIDRolesRoleIDHandlerFunc(func(ctx context.Context, params op.PatchSourcesIDRolesRoleIDParams) middleware.Responder {
return middleware.NotImplemented("operation .PatchSourcesIDRolesRoleID has not yet been implemented")
})
api.PatchUsersUserIDHandler = op.PatchUsersUserIDHandlerFunc(func(ctx context.Context, params op.PatchUsersUserIDParams) middleware.Responder {
return middleware.NotImplemented("operation .PatchUsersUserID has not yet been implemented")
})
api.PostSourcesIDRolesHandler = op.PostSourcesIDRolesHandlerFunc(func(ctx context.Context, params op.PostSourcesIDRolesParams) middleware.Responder {
return middleware.NotImplemented("operation .PostSourcesIDRoles has not yet been implemented")
})
api.PostUsersHandler = op.PostUsersHandlerFunc(func(ctx context.Context, params op.PostUsersParams) middleware.Responder {
return middleware.NotImplemented("operation .PostUsers has not yet been implemented")
})
api.GetMappingsHandler = op.GetMappingsHandlerFunc(mockHandler.GetMappings)
api.GetSourcesIDMonitoredHandler = op.GetSourcesIDMonitoredHandlerFunc(mockHandler.MonitoredServices)
api.ServerShutdown = func() {}
handler := setupGlobalMiddleware(api.Serve(setupMiddlewares))
return handler
}
// The TLS configuration before HTTPS server starts.
func configureTLS(tlsConfig *tls.Config) {
// Make all necessary changes to the TLS configuration here.
}
// The middleware configuration is for the handler executors. These do not apply to the swagger.json document.
// The middleware executes after routing but before authentication, binding and validation
func setupMiddlewares(handler http.Handler) http.Handler {
return handler
}
// The middleware configuration happens before anything, this middleware also applies to serving the swagger.json document.
// So this is a good place to plug in a panic handling middleware, logging and metrics
func setupGlobalMiddleware(handler http.Handler) http.Handler {
successURL := "/"
failureURL := "/login"
// TODO: Fix these routes when we use httprouter
assets := handlers.Assets(handlers.AssetsOpts{
Develop: devFlags.Develop,
Logger: logger,
})
if authFlags.TokenSecret != "" {
e := handlers.CookieExtractor{
Name: "session",
}
a := jwt.NewJWT(authFlags.TokenSecret)
handler = handlers.AuthorizedToken(&a, &e, logger, handler)
}
// TODO: Fix these routes when we use httprouter
auth := jwt.NewJWT(authFlags.TokenSecret)
gh := handlers.NewGithub(
authFlags.GithubClientID,
authFlags.GithubClientSecret,
successURL,
failureURL,
&auth,
logger,
)
login := gh.Login()
logout := gh.Logout()
callback := gh.Callback()
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
l := logger.
WithField("component", "server").
WithField("remote_addr", r.RemoteAddr).
WithField("method", r.Method).
WithField("url", r.URL)
// TODO: Warning keep these paths in this order until
// we have a real router.
if strings.Contains(r.URL.Path, "/chronograf/v1") {
l.Info("Serving API Request")
handler.ServeHTTP(w, r)
return
} else if strings.Contains(r.URL.Path, "/oauth/github/callback") {
l.Info("Auth callback")
callback.ServeHTTP(w, r)
return
} else if strings.HasPrefix(r.URL.Path, "/oauth/logout") {
l.Info("Login request")
logout.ServeHTTP(w, r)
return
} else if strings.HasPrefix(r.URL.Path, "/oauth") {
l.Info("Login request")
login.ServeHTTP(w, r)
return
} else if r.URL.Path == "//" {
l.Info("Serving root redirect")
http.Redirect(w, r, "/index.html", http.StatusFound)
} else {
assets.ServeHTTP(w, r)
}
})
// TODO: When we use httprouter clean up these routes
spec := handlers.Spec("/", SwaggerJSON, h)
redoc := handlers.Redoc(spec)
return redoc
}