2017-11-09 16:12:04 +01:00
package api
import (
2019-06-19 18:34:04 +02:00
"encoding/json"
2017-11-09 16:12:04 +01:00
"net/http"
2019-09-02 11:38:04 +02:00
"reflect"
2019-06-19 18:34:04 +02:00
"strings"
2017-11-09 16:12:04 +01:00
2019-08-03 03:58:23 +02:00
"github.com/gorilla/mux"
2021-01-25 11:08:04 +01:00
"github.com/traefik/traefik/v2/pkg/config/dynamic"
2020-09-16 15:46:04 +02:00
"github.com/traefik/traefik/v2/pkg/config/runtime"
"github.com/traefik/traefik/v2/pkg/config/static"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/version"
2017-11-09 16:12:04 +01:00
)
2019-09-02 11:38:04 +02:00
type apiError struct {
Message string ` json:"message" `
}
func writeError ( rw http . ResponseWriter , msg string , code int ) {
data , err := json . Marshal ( apiError { Message : msg } )
if err != nil {
http . Error ( rw , msg , code )
return
}
2018-11-14 10:18:03 +01:00
2019-09-02 11:38:04 +02:00
http . Error ( rw , string ( data ) , code )
}
2018-11-14 10:18:03 +01:00
2019-05-16 10:58:06 +02:00
type serviceInfoRepresentation struct {
2019-07-15 17:04:04 +02:00
* runtime . ServiceInfo
2019-05-16 10:58:06 +02:00
ServerStatus map [ string ] string ` json:"serverStatus,omitempty" `
2018-11-14 10:18:03 +01:00
}
2019-05-16 10:58:06 +02:00
// RunTimeRepresentation is the configuration information exposed by the API handler.
type RunTimeRepresentation struct {
2021-06-11 15:30:05 +02:00
Routers map [ string ] * runtime . RouterInfo ` json:"routers,omitempty" `
Middlewares map [ string ] * runtime . MiddlewareInfo ` json:"middlewares,omitempty" `
Services map [ string ] * serviceInfoRepresentation ` json:"services,omitempty" `
TCPRouters map [ string ] * runtime . TCPRouterInfo ` json:"tcpRouters,omitempty" `
TCPMiddlewares map [ string ] * runtime . TCPMiddlewareInfo ` json:"tcpMiddlewares,omitempty" `
TCPServices map [ string ] * runtime . TCPServiceInfo ` json:"tcpServices,omitempty" `
UDPRouters map [ string ] * runtime . UDPRouterInfo ` json:"udpRouters,omitempty" `
UDPServices map [ string ] * runtime . UDPServiceInfo ` json:"udpServices,omitempty" `
2018-11-14 10:18:03 +01:00
}
2019-05-16 10:58:06 +02:00
// Handler serves the configuration and status of Traefik on API endpoints.
2017-11-09 16:12:04 +01:00
type Handler struct {
2021-09-15 10:36:14 +02:00
staticConfig static . Configuration
2019-11-14 16:40:05 +01:00
2019-05-16 10:58:06 +02:00
// runtimeConfiguration is the data set used to create all the data representations exposed by the API.
2019-07-15 17:04:04 +02:00
runtimeConfiguration * runtime . Configuration
2017-11-09 16:12:04 +01:00
}
2020-05-11 12:06:07 +02:00
// NewBuilder returns a http.Handler builder based on runtime.Configuration.
2019-09-06 15:08:04 +02:00
func NewBuilder ( staticConfig static . Configuration ) func ( * runtime . Configuration ) http . Handler {
return func ( configuration * runtime . Configuration ) http . Handler {
2019-11-14 16:40:05 +01:00
return New ( staticConfig , configuration ) . createRouter ( )
2019-09-06 15:08:04 +02:00
}
}
2019-05-16 10:58:06 +02: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 17:04:04 +02:00
func New ( staticConfig static . Configuration , runtimeConfig * runtime . Configuration ) * Handler {
2019-05-16 10:58:06 +02:00
rConfig := runtimeConfig
if rConfig == nil {
2019-07-15 17:04:04 +02:00
rConfig = & runtime . Configuration { }
2019-05-16 10:58:06 +02:00
}
2018-11-14 10:18:03 +01:00
2019-05-16 10:58:06 +02:00
return & Handler {
runtimeConfiguration : rConfig ,
2019-07-12 11:10:03 +02:00
staticConfig : staticConfig ,
2019-05-16 10:58:06 +02:00
}
2018-11-14 10:18:03 +01:00
}
2017-11-09 16:12:04 +01:00
2019-11-14 16:40:05 +01:00
// createRouter creates API routes and router.
func ( h Handler ) createRouter ( ) * mux . Router {
router := mux . NewRouter ( )
2021-09-15 10:36:14 +02:00
if h . staticConfig . API . Debug {
2018-11-14 10:18:03 +01:00
DebugHandler { } . Append ( router )
2017-11-09 16:12:04 +01:00
}
2019-05-16 10:58:06 +02:00
router . Methods ( http . MethodGet ) . Path ( "/api/rawdata" ) . HandlerFunc ( h . getRuntimeConfiguration )
2017-11-09 16:12:04 +01:00
2019-07-12 11:10:03 +02: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 18:34:04 +02: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 )
2021-06-11 15:30:05 +02:00
router . Methods ( http . MethodGet ) . Path ( "/api/tcp/middlewares" ) . HandlerFunc ( h . getTCPMiddlewares )
router . Methods ( http . MethodGet ) . Path ( "/api/tcp/middlewares/{middlewareID}" ) . HandlerFunc ( h . getTCPMiddleware )
2019-06-19 18:34:04 +02:00
2020-02-11 01:26:04 +01:00
router . Methods ( http . MethodGet ) . Path ( "/api/udp/routers" ) . HandlerFunc ( h . getUDPRouters )
router . Methods ( http . MethodGet ) . Path ( "/api/udp/routers/{routerID}" ) . HandlerFunc ( h . getUDPRouter )
router . Methods ( http . MethodGet ) . Path ( "/api/udp/services" ) . HandlerFunc ( h . getUDPServices )
router . Methods ( http . MethodGet ) . Path ( "/api/udp/services/{serviceID}" ) . HandlerFunc ( h . getUDPService )
2018-11-14 10:18:03 +01:00
version . Handler { } . Append ( router )
2017-11-09 16:12:04 +01:00
2019-11-14 16:40:05 +01:00
return router
2017-11-09 16:12:04 +01:00
}
2019-05-16 10:58:06 +02: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 09:30:04 +01:00
}
}
2019-06-19 18:34:04 +02:00
result := RunTimeRepresentation {
2021-06-11 15:30:05 +02:00
Routers : h . runtimeConfiguration . Routers ,
Middlewares : h . runtimeConfiguration . Middlewares ,
Services : siRepr ,
TCPRouters : h . runtimeConfiguration . TCPRouters ,
TCPMiddlewares : h . runtimeConfiguration . TCPMiddlewares ,
TCPServices : h . runtimeConfiguration . TCPServices ,
UDPRouters : h . runtimeConfiguration . UDPRouters ,
UDPServices : h . runtimeConfiguration . UDPServices ,
2017-11-09 16:12:04 +01:00
}
2018-11-14 10:18:03 +01:00
2019-06-26 01:44:03 +10:00
rw . Header ( ) . Set ( "Content-Type" , "application/json" )
2019-06-19 18:34:04 +02:00
err := json . NewEncoder ( rw ) . Encode ( result )
2017-11-09 16:12:04 +01:00
if err != nil {
2018-11-14 10:18:03 +01:00
log . FromContext ( request . Context ( ) ) . Error ( err )
http . Error ( rw , err . Error ( ) , http . StatusInternalServerError )
2017-11-09 16:12:04 +01:00
}
}
2019-06-19 18:34:04 +02:00
2019-09-02 11:38:04 +02:00
func getProviderName ( id string ) string {
return strings . SplitN ( id , "@" , 2 ) [ 1 ]
2019-06-19 18:34:04 +02:00
}
2019-09-02 11:38:04 +02:00
func extractType ( element interface { } ) string {
v := reflect . ValueOf ( element ) . Elem ( )
for i := 0 ; i < v . NumField ( ) ; i ++ {
field := v . Field ( i )
2021-01-25 11:08:04 +01:00
if field . Kind ( ) == reflect . Map && field . Type ( ) . Elem ( ) == reflect . TypeOf ( dynamic . PluginConf { } ) {
if keys := field . MapKeys ( ) ; len ( keys ) == 1 {
return keys [ 0 ] . String ( )
}
}
2019-09-02 11:38:04 +02:00
if field . Kind ( ) == reflect . Ptr && field . Elem ( ) . Kind ( ) == reflect . Struct {
if ! field . IsNil ( ) {
return v . Type ( ) . Field ( i ) . Name
}
}
2019-06-19 18:34:04 +02:00
}
2019-09-02 11:38:04 +02:00
return ""
2019-06-19 18:34:04 +02:00
}