2015-09-08 14:33:10 +03:00
package main
import (
2015-09-09 01:22:34 +03:00
"encoding/json"
2016-05-19 21:06:49 +03:00
"expvar"
2015-09-12 16:10:03 +03:00
"fmt"
2015-09-24 18:16:13 +03:00
"io/ioutil"
"net/http"
2016-05-19 21:06:49 +03:00
"runtime"
2015-09-24 18:16:13 +03:00
2016-09-15 16:24:22 +03:00
"github.com/codegangsta/negroni"
2016-06-03 18:58:33 +03:00
"github.com/containous/mux"
2016-02-24 18:43:39 +03:00
"github.com/containous/traefik/autogen"
2016-09-23 19:27:01 +03:00
"github.com/containous/traefik/log"
2016-09-15 16:24:22 +03:00
"github.com/containous/traefik/middlewares"
2016-04-13 21:36:23 +03:00
"github.com/containous/traefik/safe"
2016-02-24 18:43:39 +03:00
"github.com/containous/traefik/types"
2016-10-02 21:07:25 +03:00
"github.com/containous/traefik/version"
2015-09-11 19:47:54 +03:00
"github.com/elazarl/go-bindata-assetfs"
2016-01-14 00:46:44 +03:00
"github.com/thoas/stats"
2015-10-22 15:02:14 +03:00
"github.com/unrolled/render"
2015-09-08 14:33:10 +03:00
)
2016-01-14 00:46:44 +03:00
var metrics = stats . New ( )
2015-11-06 20:11:57 +03:00
// WebProvider is a provider.Provider implementation that provides the UI.
// FIXME to be handled another way.
2015-09-08 14:33:10 +03:00
type WebProvider struct {
2016-05-03 17:52:14 +03:00
Address string ` description:"Web administration port" `
CertFile string ` description:"SSL certificate" `
KeyFile string ` description:"SSL certificate" `
ReadOnly bool ` description:"Enable read only API" `
server * Server
2016-09-15 16:24:22 +03:00
Auth * types . Auth
2015-09-08 14:33:10 +03:00
}
2015-10-22 15:02:14 +03:00
var (
templatesRenderer = render . New ( render . Options {
Directory : "nowhere" ,
} )
)
2016-05-19 21:06:49 +03:00
func init ( ) {
expvar . Publish ( "Goroutines" , expvar . Func ( goroutines ) )
}
func goroutines ( ) interface { } {
return runtime . NumGoroutine ( )
}
2015-11-06 20:11:57 +03:00
// Provide allows the provider to provide configurations to traefik
// using the given configuration channel.
2016-05-31 10:54:42 +03:00
func ( provider * WebProvider ) Provide ( configurationChan chan <- types . ConfigMessage , pool * safe . Pool , _ [ ] types . Constraint ) error {
2016-09-15 16:24:22 +03:00
2015-09-08 14:33:10 +03:00
systemRouter := mux . NewRouter ( )
2015-09-23 02:17:21 +03:00
2015-10-05 17:01:34 +03:00
// health route
2016-01-14 00:45:49 +03:00
systemRouter . Methods ( "GET" ) . Path ( "/health" ) . HandlerFunc ( provider . getHealthHandler )
2015-10-05 17:01:34 +03:00
2016-08-19 19:02:26 +03:00
// ping route
systemRouter . Methods ( "GET" ) . Path ( "/ping" ) . HandlerFunc ( provider . getPingHandler )
2015-10-05 17:01:34 +03:00
// API routes
2016-01-14 00:45:49 +03:00
systemRouter . Methods ( "GET" ) . Path ( "/api" ) . HandlerFunc ( provider . getConfigHandler )
2016-10-02 21:07:25 +03:00
systemRouter . Methods ( "GET" ) . Path ( "/api/version" ) . HandlerFunc ( provider . getVersionHandler )
2016-01-14 00:45:49 +03:00
systemRouter . Methods ( "GET" ) . Path ( "/api/providers" ) . HandlerFunc ( provider . getConfigHandler )
systemRouter . Methods ( "GET" ) . Path ( "/api/providers/{provider}" ) . HandlerFunc ( provider . getProviderHandler )
2015-10-05 17:01:34 +03:00
systemRouter . Methods ( "PUT" ) . Path ( "/api/providers/{provider}" ) . HandlerFunc ( func ( response http . ResponseWriter , request * http . Request ) {
2016-01-03 22:42:09 +03:00
if provider . ReadOnly {
response . WriteHeader ( http . StatusForbidden )
fmt . Fprintf ( response , "REST API is in read-only mode" )
return
}
2015-10-05 17:01:34 +03:00
vars := mux . Vars ( request )
if vars [ "provider" ] != "web" {
response . WriteHeader ( http . StatusBadRequest )
fmt . Fprintf ( response , "Only 'web' provider can be updated through the REST API" )
return
}
2015-11-01 18:35:01 +03:00
configuration := new ( types . Configuration )
2015-10-05 17:01:34 +03:00
body , _ := ioutil . ReadAll ( request . Body )
err := json . Unmarshal ( body , configuration )
if err == nil {
2016-09-23 19:27:01 +03:00
configurationChan <- types . ConfigMessage { ProviderName : "web" , Configuration : configuration }
2016-01-14 00:45:49 +03:00
provider . getConfigHandler ( response , request )
2015-10-05 17:01:34 +03:00
} else {
log . Errorf ( "Error parsing configuration %+v" , err )
http . Error ( response , fmt . Sprintf ( "%+v" , err ) , http . StatusBadRequest )
}
} )
2016-01-14 00:45:49 +03:00
systemRouter . Methods ( "GET" ) . Path ( "/api/providers/{provider}/backends" ) . HandlerFunc ( provider . getBackendsHandler )
systemRouter . Methods ( "GET" ) . Path ( "/api/providers/{provider}/backends/{backend}" ) . HandlerFunc ( provider . getBackendHandler )
systemRouter . Methods ( "GET" ) . Path ( "/api/providers/{provider}/backends/{backend}/servers" ) . HandlerFunc ( provider . getServersHandler )
systemRouter . Methods ( "GET" ) . Path ( "/api/providers/{provider}/backends/{backend}/servers/{server}" ) . HandlerFunc ( provider . getServerHandler )
systemRouter . Methods ( "GET" ) . Path ( "/api/providers/{provider}/frontends" ) . HandlerFunc ( provider . getFrontendsHandler )
systemRouter . Methods ( "GET" ) . Path ( "/api/providers/{provider}/frontends/{frontend}" ) . HandlerFunc ( provider . getFrontendHandler )
systemRouter . Methods ( "GET" ) . Path ( "/api/providers/{provider}/frontends/{frontend}/routes" ) . HandlerFunc ( provider . getRoutesHandler )
systemRouter . Methods ( "GET" ) . Path ( "/api/providers/{provider}/frontends/{frontend}/routes/{route}" ) . HandlerFunc ( provider . getRouteHandler )
2015-10-05 17:01:34 +03:00
// Expose dashboard
systemRouter . Methods ( "GET" ) . Path ( "/" ) . HandlerFunc ( func ( response http . ResponseWriter , request * http . Request ) {
http . Redirect ( response , request , "/dashboard/" , 302 )
} )
2016-05-24 18:29:56 +03:00
systemRouter . Methods ( "GET" ) . PathPrefix ( "/dashboard/" ) . Handler ( http . StripPrefix ( "/dashboard/" , http . FileServer ( & assetfs . AssetFS { Asset : autogen . Asset , AssetInfo : autogen . AssetInfo , AssetDir : autogen . AssetDir , Prefix : "static" } ) ) )
2015-09-08 14:33:10 +03:00
2016-05-19 21:09:01 +03:00
// expvars
if provider . server . globalConfiguration . Debug {
systemRouter . Methods ( "GET" ) . Path ( "/debug/vars" ) . HandlerFunc ( expvarHandler )
}
2015-09-22 22:00:29 +03:00
go func ( ) {
2016-09-19 18:00:12 +03:00
var err error
var negroni = negroni . New ( )
2016-09-15 16:24:22 +03:00
if provider . Auth != nil {
authMiddleware , err := middlewares . NewAuthenticator ( provider . Auth )
if err != nil {
log . Fatal ( "Error creating Auth: " , err )
}
negroni . Use ( authMiddleware )
2016-09-19 18:00:12 +03:00
}
negroni . UseHandler ( systemRouter )
2016-09-15 16:24:22 +03:00
2016-09-19 18:00:12 +03:00
if len ( provider . CertFile ) > 0 && len ( provider . KeyFile ) > 0 {
err = http . ListenAndServeTLS ( provider . Address , provider . CertFile , provider . KeyFile , negroni )
2015-09-22 22:00:29 +03:00
} else {
2016-09-19 18:00:12 +03:00
err = http . ListenAndServe ( provider . Address , negroni )
}
2016-09-15 16:24:22 +03:00
2016-09-19 18:00:12 +03:00
if err != nil {
log . Fatal ( "Error creating server: " , err )
2015-09-22 22:00:29 +03:00
}
} ( )
2015-10-01 13:04:25 +03:00
return nil
2015-09-08 14:33:10 +03:00
}
2016-01-14 00:45:49 +03:00
func ( provider * WebProvider ) getHealthHandler ( response http . ResponseWriter , request * http . Request ) {
2015-10-05 17:01:34 +03:00
templatesRenderer . JSON ( response , http . StatusOK , metrics . Data ( ) )
2015-09-08 14:33:10 +03:00
}
2016-08-19 19:02:26 +03:00
func ( provider * WebProvider ) getPingHandler ( response http . ResponseWriter , request * http . Request ) {
fmt . Fprintf ( response , "OK" )
}
2016-01-14 00:45:49 +03:00
func ( provider * WebProvider ) getConfigHandler ( response http . ResponseWriter , request * http . Request ) {
2016-04-13 21:36:23 +03:00
currentConfigurations := provider . server . currentConfigurations . Get ( ) . ( configs )
templatesRenderer . JSON ( response , http . StatusOK , currentConfigurations )
2015-09-08 14:33:10 +03:00
}
2015-09-12 14:20:54 +03:00
2016-10-02 21:07:25 +03:00
func ( provider * WebProvider ) getVersionHandler ( response http . ResponseWriter , request * http . Request ) {
v := struct {
Version string
Codename string
} {
Version : version . Version ,
Codename : version . Codename ,
}
templatesRenderer . JSON ( response , http . StatusOK , v )
}
2016-01-14 00:45:49 +03:00
func ( provider * WebProvider ) getProviderHandler ( response http . ResponseWriter , request * http . Request ) {
2015-10-05 17:01:34 +03:00
vars := mux . Vars ( request )
providerID := vars [ "provider" ]
2016-04-13 21:36:23 +03:00
currentConfigurations := provider . server . currentConfigurations . Get ( ) . ( configs )
if provider , ok := currentConfigurations [ providerID ] ; ok {
2015-10-05 17:01:34 +03:00
templatesRenderer . JSON ( response , http . StatusOK , provider )
} else {
http . NotFound ( response , request )
}
2015-10-03 17:50:53 +03:00
}
2016-01-14 00:45:49 +03:00
func ( provider * WebProvider ) getBackendsHandler ( response http . ResponseWriter , request * http . Request ) {
2015-10-05 17:01:34 +03:00
vars := mux . Vars ( request )
providerID := vars [ "provider" ]
2016-04-13 21:36:23 +03:00
currentConfigurations := provider . server . currentConfigurations . Get ( ) . ( configs )
if provider , ok := currentConfigurations [ providerID ] ; ok {
2015-10-05 17:01:34 +03:00
templatesRenderer . JSON ( response , http . StatusOK , provider . Backends )
2015-09-23 08:48:32 +03:00
} else {
2015-10-05 17:01:34 +03:00
http . NotFound ( response , request )
2015-09-23 08:48:32 +03:00
}
2015-09-15 19:35:32 +03:00
}
2016-01-14 00:45:49 +03:00
func ( provider * WebProvider ) getBackendHandler ( response http . ResponseWriter , request * http . Request ) {
2015-10-05 17:01:34 +03:00
vars := mux . Vars ( request )
providerID := vars [ "provider" ]
backendID := vars [ "backend" ]
2016-04-13 21:36:23 +03:00
currentConfigurations := provider . server . currentConfigurations . Get ( ) . ( configs )
if provider , ok := currentConfigurations [ providerID ] ; ok {
2015-10-05 17:01:34 +03:00
if backend , ok := provider . Backends [ backendID ] ; ok {
templatesRenderer . JSON ( response , http . StatusOK , backend )
2015-09-23 08:48:32 +03:00
return
}
2015-09-16 20:08:01 +03:00
}
2015-10-05 17:01:34 +03:00
http . NotFound ( response , request )
2015-09-15 19:35:32 +03:00
}
2016-01-14 00:45:49 +03:00
func ( provider * WebProvider ) getServersHandler ( response http . ResponseWriter , request * http . Request ) {
2015-10-08 12:16:40 +03:00
vars := mux . Vars ( request )
providerID := vars [ "provider" ]
backendID := vars [ "backend" ]
2016-04-13 21:36:23 +03:00
currentConfigurations := provider . server . currentConfigurations . Get ( ) . ( configs )
if provider , ok := currentConfigurations [ providerID ] ; ok {
2015-10-08 12:16:40 +03:00
if backend , ok := provider . Backends [ backendID ] ; ok {
templatesRenderer . JSON ( response , http . StatusOK , backend . Servers )
return
}
}
http . NotFound ( response , request )
}
2016-01-14 00:45:49 +03:00
func ( provider * WebProvider ) getServerHandler ( response http . ResponseWriter , request * http . Request ) {
2015-10-08 12:16:40 +03:00
vars := mux . Vars ( request )
providerID := vars [ "provider" ]
backendID := vars [ "backend" ]
serverID := vars [ "server" ]
2016-04-13 21:36:23 +03:00
currentConfigurations := provider . server . currentConfigurations . Get ( ) . ( configs )
if provider , ok := currentConfigurations [ providerID ] ; ok {
2015-10-08 12:16:40 +03:00
if backend , ok := provider . Backends [ backendID ] ; ok {
if server , ok := backend . Servers [ serverID ] ; ok {
templatesRenderer . JSON ( response , http . StatusOK , server )
return
}
}
}
http . NotFound ( response , request )
}
2016-01-14 00:45:49 +03:00
func ( provider * WebProvider ) getFrontendsHandler ( response http . ResponseWriter , request * http . Request ) {
2015-10-05 17:01:34 +03:00
vars := mux . Vars ( request )
providerID := vars [ "provider" ]
2016-04-13 21:36:23 +03:00
currentConfigurations := provider . server . currentConfigurations . Get ( ) . ( configs )
if provider , ok := currentConfigurations [ providerID ] ; ok {
2015-10-05 17:01:34 +03:00
templatesRenderer . JSON ( response , http . StatusOK , provider . Frontends )
2015-09-23 08:48:32 +03:00
} else {
2015-10-05 17:01:34 +03:00
http . NotFound ( response , request )
2015-09-23 08:48:32 +03:00
}
2015-09-15 19:35:32 +03:00
}
2016-01-14 00:45:49 +03:00
func ( provider * WebProvider ) getFrontendHandler ( response http . ResponseWriter , request * http . Request ) {
2015-10-05 17:01:34 +03:00
vars := mux . Vars ( request )
providerID := vars [ "provider" ]
frontendID := vars [ "frontend" ]
2016-04-13 21:36:23 +03:00
currentConfigurations := provider . server . currentConfigurations . Get ( ) . ( configs )
if provider , ok := currentConfigurations [ providerID ] ; ok {
2015-10-05 17:01:34 +03:00
if frontend , ok := provider . Frontends [ frontendID ] ; ok {
templatesRenderer . JSON ( response , http . StatusOK , frontend )
2015-09-23 08:48:32 +03:00
return
}
2015-09-16 20:08:01 +03:00
}
2015-10-05 17:01:34 +03:00
http . NotFound ( response , request )
2015-09-15 19:35:32 +03:00
}
2015-09-16 20:08:01 +03:00
2016-01-14 00:45:49 +03:00
func ( provider * WebProvider ) getRoutesHandler ( response http . ResponseWriter , request * http . Request ) {
2015-10-05 17:01:34 +03:00
vars := mux . Vars ( request )
providerID := vars [ "provider" ]
2015-10-08 12:16:40 +03:00
frontendID := vars [ "frontend" ]
2016-04-13 21:36:23 +03:00
currentConfigurations := provider . server . currentConfigurations . Get ( ) . ( configs )
if provider , ok := currentConfigurations [ providerID ] ; ok {
2015-10-08 12:16:40 +03:00
if frontend , ok := provider . Frontends [ frontendID ] ; ok {
templatesRenderer . JSON ( response , http . StatusOK , frontend . Routes )
2015-09-23 08:48:32 +03:00
return
}
2015-09-16 20:08:01 +03:00
}
2015-10-05 17:01:34 +03:00
http . NotFound ( response , request )
2015-09-16 20:08:01 +03:00
}
2016-01-14 00:45:49 +03:00
func ( provider * WebProvider ) getRouteHandler ( response http . ResponseWriter , request * http . Request ) {
2016-09-15 16:24:22 +03:00
2015-10-05 17:01:34 +03:00
vars := mux . Vars ( request )
providerID := vars [ "provider" ]
2015-10-08 12:16:40 +03:00
frontendID := vars [ "frontend" ]
routeID := vars [ "route" ]
2016-04-13 21:36:23 +03:00
currentConfigurations := provider . server . currentConfigurations . Get ( ) . ( configs )
if provider , ok := currentConfigurations [ providerID ] ; ok {
2015-10-08 12:16:40 +03:00
if frontend , ok := provider . Frontends [ frontendID ] ; ok {
if route , ok := frontend . Routes [ routeID ] ; ok {
templatesRenderer . JSON ( response , http . StatusOK , route )
2015-09-23 08:48:32 +03:00
return
}
2015-09-16 20:08:01 +03:00
}
}
2015-10-05 17:01:34 +03:00
http . NotFound ( response , request )
2015-09-22 11:33:37 +03:00
}
2016-05-19 21:06:49 +03:00
func expvarHandler ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json; charset=utf-8" )
fmt . Fprintf ( w , "{\n" )
first := true
expvar . Do ( func ( kv expvar . KeyValue ) {
if ! first {
fmt . Fprintf ( w , ",\n" )
}
first = false
fmt . Fprintf ( w , "%q: %s" , kv . Key , kv . Value )
} )
fmt . Fprintf ( w , "\n}\n" )
}