2017-11-09 18:12:04 +03:00
package api
import (
2019-06-19 19:34:04 +03:00
"encoding/json"
"fmt"
2017-11-09 18:12:04 +03:00
"net/http"
2019-06-19 19:34:04 +03:00
"strconv"
"strings"
2017-11-09 18:12:04 +03:00
"github.com/containous/mux"
2019-07-15 18:04:04 +03:00
"github.com/containous/traefik/pkg/config/runtime"
2019-05-16 11:58:06 +03:00
"github.com/containous/traefik/pkg/config/static"
2019-03-15 11:42:03 +03:00
"github.com/containous/traefik/pkg/log"
"github.com/containous/traefik/pkg/version"
2019-02-18 09:52:03 +03:00
assetfs "github.com/elazarl/go-bindata-assetfs"
2017-11-09 18:12:04 +03:00
)
2019-06-19 19:34:04 +03:00
const (
defaultPerPage = 100
defaultPage = 1
)
2018-11-14 12:18:03 +03:00
2019-06-19 19:34:04 +03:00
const nextPageHeader = "X-Next-Page"
2018-11-14 12:18:03 +03:00
2019-05-16 11:58:06 +03:00
type serviceInfoRepresentation struct {
2019-07-15 18:04:04 +03:00
* runtime . ServiceInfo
2019-05-16 11:58:06 +03:00
ServerStatus map [ string ] string ` json:"serverStatus,omitempty" `
2018-11-14 12:18:03 +03:00
}
2019-05-16 11:58:06 +03:00
// RunTimeRepresentation is the configuration information exposed by the API handler.
type RunTimeRepresentation struct {
2019-07-15 18:04:04 +03:00
Routers map [ string ] * runtime . RouterInfo ` json:"routers,omitempty" `
Middlewares map [ string ] * runtime . MiddlewareInfo ` json:"middlewares,omitempty" `
2019-05-16 11:58:06 +03:00
Services map [ string ] * serviceInfoRepresentation ` json:"services,omitempty" `
2019-07-15 18:04:04 +03:00
TCPRouters map [ string ] * runtime . TCPRouterInfo ` json:"tcpRouters,omitempty" `
TCPServices map [ string ] * runtime . TCPServiceInfo ` json:"tcpServices,omitempty" `
2018-11-14 12:18:03 +03:00
}
2019-06-19 19:34:04 +03:00
type pageInfo struct {
startIndex int
endIndex int
nextPage int
}
2019-05-16 11:58:06 +03:00
// Handler serves the configuration and status of Traefik on API endpoints.
2017-11-09 18:12:04 +03:00
type Handler struct {
2019-05-16 11:58:06 +03:00
dashboard bool
debug bool
// runtimeConfiguration is the data set used to create all the data representations exposed by the API.
2019-07-15 18:04:04 +03:00
runtimeConfiguration * runtime . Configuration
2019-07-12 12:10:03 +03:00
staticConfig static . Configuration
2019-07-19 13:28:07 +03:00
// statistics *types.Statistics
2019-05-16 11:58:06 +03:00
// stats *thoasstats.Stats // FIXME stats
2018-11-14 12:18:03 +03:00
// StatsRecorder *middlewares.StatsRecorder // FIXME stats
2019-05-16 11:58:06 +03:00
dashboardAssets * assetfs . AssetFS
2017-11-09 18:12:04 +03:00
}
2019-05-16 11:58:06 +03:00
// New returns a Handler defined by staticConfig, and if provided, by runtimeConfig.
// It finishes populating the information provided in the runtimeConfig.
2019-07-15 18:04:04 +03:00
func New ( staticConfig static . Configuration , runtimeConfig * runtime . Configuration ) * Handler {
2019-05-16 11:58:06 +03:00
rConfig := runtimeConfig
if rConfig == nil {
2019-07-15 18:04:04 +03:00
rConfig = & runtime . Configuration { }
2019-05-16 11:58:06 +03:00
}
2018-11-14 12:18:03 +03:00
2019-05-16 11:58:06 +03:00
return & Handler {
2019-07-19 13:28:07 +03:00
dashboard : staticConfig . API . Dashboard ,
// statistics: staticConfig.API.Statistics,
2019-05-16 11:58:06 +03:00
dashboardAssets : staticConfig . API . DashboardAssets ,
runtimeConfiguration : rConfig ,
2019-07-12 12:10:03 +03:00
staticConfig : staticConfig ,
2019-06-19 19:34:04 +03:00
debug : staticConfig . API . Debug ,
2019-05-16 11:58:06 +03:00
}
2018-11-14 12:18:03 +03:00
}
2017-11-09 18:12:04 +03:00
2018-11-14 12:18:03 +03:00
// Append add api routes on a router
2019-03-14 11:30:04 +03:00
func ( h Handler ) Append ( router * mux . Router ) {
2019-05-16 11:58:06 +03:00
if h . debug {
2018-11-14 12:18:03 +03:00
DebugHandler { } . Append ( router )
2017-11-09 18:12:04 +03:00
}
2019-05-16 11:58:06 +03:00
router . Methods ( http . MethodGet ) . Path ( "/api/rawdata" ) . HandlerFunc ( h . getRuntimeConfiguration )
2017-11-09 18:12:04 +03:00
2019-07-12 12:10:03 +03:00
// Experimental endpoint
router . Methods ( http . MethodGet ) . Path ( "/api/overview" ) . HandlerFunc ( h . getOverview )
router . Methods ( http . MethodGet ) . Path ( "/api/entrypoints" ) . HandlerFunc ( h . getEntryPoints )
router . Methods ( http . MethodGet ) . Path ( "/api/entrypoints/{entryPointID}" ) . HandlerFunc ( h . getEntryPoint )
2019-06-19 19:34:04 +03:00
router . Methods ( http . MethodGet ) . Path ( "/api/http/routers" ) . HandlerFunc ( h . getRouters )
router . Methods ( http . MethodGet ) . Path ( "/api/http/routers/{routerID}" ) . HandlerFunc ( h . getRouter )
router . Methods ( http . MethodGet ) . Path ( "/api/http/services" ) . HandlerFunc ( h . getServices )
router . Methods ( http . MethodGet ) . Path ( "/api/http/services/{serviceID}" ) . HandlerFunc ( h . getService )
router . Methods ( http . MethodGet ) . Path ( "/api/http/middlewares" ) . HandlerFunc ( h . getMiddlewares )
router . Methods ( http . MethodGet ) . Path ( "/api/http/middlewares/{middlewareID}" ) . HandlerFunc ( h . getMiddleware )
router . Methods ( http . MethodGet ) . Path ( "/api/tcp/routers" ) . HandlerFunc ( h . getTCPRouters )
router . Methods ( http . MethodGet ) . Path ( "/api/tcp/routers/{routerID}" ) . HandlerFunc ( h . getTCPRouter )
router . Methods ( http . MethodGet ) . Path ( "/api/tcp/services" ) . HandlerFunc ( h . getTCPServices )
router . Methods ( http . MethodGet ) . Path ( "/api/tcp/services/{serviceID}" ) . HandlerFunc ( h . getTCPService )
2018-11-14 12:18:03 +03:00
// FIXME stats
2017-11-09 18:12:04 +03:00
// health route
2019-06-19 19:34:04 +03:00
// router.Methods(http.MethodGet).Path("/health").HandlerFunc(p.getHealthHandler)
2017-11-09 18:12:04 +03:00
2018-11-14 12:18:03 +03:00
version . Handler { } . Append ( router )
2017-11-09 18:12:04 +03:00
2019-05-16 11:58:06 +03:00
if h . dashboard {
DashboardHandler { Assets : h . dashboardAssets } . Append ( router )
2017-11-09 18:12:04 +03:00
}
}
2019-05-16 11:58:06 +03:00
func ( h Handler ) getRuntimeConfiguration ( rw http . ResponseWriter , request * http . Request ) {
siRepr := make ( map [ string ] * serviceInfoRepresentation , len ( h . runtimeConfiguration . Services ) )
for k , v := range h . runtimeConfiguration . Services {
siRepr [ k ] = & serviceInfoRepresentation {
ServiceInfo : v ,
ServerStatus : v . GetAllStatus ( ) ,
2019-03-14 11:30:04 +03:00
}
}
2019-06-19 19:34:04 +03:00
result := RunTimeRepresentation {
2019-05-16 11:58:06 +03:00
Routers : h . runtimeConfiguration . Routers ,
Middlewares : h . runtimeConfiguration . Middlewares ,
Services : siRepr ,
TCPRouters : h . runtimeConfiguration . TCPRouters ,
TCPServices : h . runtimeConfiguration . TCPServices ,
2017-11-09 18:12:04 +03:00
}
2018-11-14 12:18:03 +03:00
2019-06-25 18:44:03 +03:00
rw . Header ( ) . Set ( "Content-Type" , "application/json" )
2019-06-19 19:34:04 +03:00
err := json . NewEncoder ( rw ) . Encode ( result )
2017-11-09 18:12:04 +03:00
if err != nil {
2018-11-14 12:18:03 +03:00
log . FromContext ( request . Context ( ) ) . Error ( err )
http . Error ( rw , err . Error ( ) , http . StatusInternalServerError )
2017-11-09 18:12:04 +03:00
}
}
2019-06-19 19:34:04 +03:00
func pagination ( request * http . Request , max int ) ( pageInfo , error ) {
perPage , err := getIntParam ( request , "per_page" , defaultPerPage )
if err != nil {
return pageInfo { } , err
}
page , err := getIntParam ( request , "page" , defaultPage )
if err != nil {
return pageInfo { } , err
}
startIndex := ( page - 1 ) * perPage
if startIndex != 0 && startIndex >= max {
return pageInfo { } , fmt . Errorf ( "invalid request: page: %d, per_page: %d" , page , perPage )
}
endIndex := startIndex + perPage
if endIndex >= max {
endIndex = max
}
nextPage := 1
if page * perPage < max {
nextPage = page + 1
}
return pageInfo { startIndex : startIndex , endIndex : endIndex , nextPage : nextPage } , nil
}
func getIntParam ( request * http . Request , key string , defaultValue int ) ( int , error ) {
raw := request . URL . Query ( ) . Get ( key )
if raw == "" {
return defaultValue , nil
}
value , err := strconv . Atoi ( raw )
if err != nil || value <= 0 {
return 0 , fmt . Errorf ( "invalid request: %s: %d" , key , value )
}
return value , nil
}
func getProviderName ( id string ) string {
2019-06-21 10:54:04 +03:00
return strings . SplitN ( id , "@" , 2 ) [ 1 ]
2019-06-19 19:34:04 +03:00
}