2017-11-09 18:12:04 +03:00
package api
import (
2019-06-19 19:34:04 +03:00
"encoding/json"
2017-11-09 18:12:04 +03:00
"net/http"
2019-09-02 12:38:04 +03:00
"reflect"
2019-06-19 19:34:04 +03:00
"strings"
2017-11-09 18:12:04 +03:00
2019-08-03 04:58:23 +03:00
"github.com/gorilla/mux"
2022-11-21 20:36:05 +03:00
"github.com/rs/zerolog/log"
2023-02-03 17:24:05 +03:00
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/config/runtime"
"github.com/traefik/traefik/v3/pkg/config/static"
"github.com/traefik/traefik/v3/pkg/version"
2017-11-09 18:12:04 +03:00
)
2019-09-02 12:38:04 +03: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 12:18:03 +03:00
2019-09-02 12:38:04 +03:00
http . Error ( rw , string ( data ) , code )
}
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 {
2021-06-11 16:30:05 +03: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 12:18:03 +03:00
}
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 {
2021-09-15 11:36:14 +03:00
staticConfig static . Configuration
2019-11-14 18:40:05 +03:00
2019-05-16 11:58:06 +03:00
// 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
2017-11-09 18:12:04 +03:00
}
2020-05-11 13:06:07 +03:00
// NewBuilder returns a http.Handler builder based on runtime.Configuration.
2019-09-06 16:08:04 +03:00
func NewBuilder ( staticConfig static . Configuration ) func ( * runtime . Configuration ) http . Handler {
return func ( configuration * runtime . Configuration ) http . Handler {
2019-11-14 18:40:05 +03:00
return New ( staticConfig , configuration ) . createRouter ( )
2019-09-06 16:08: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 {
runtimeConfiguration : rConfig ,
2019-07-12 12:10:03 +03:00
staticConfig : staticConfig ,
2019-05-16 11:58:06 +03:00
}
2018-11-14 12:18:03 +03:00
}
2017-11-09 18:12:04 +03:00
2019-11-14 18:40:05 +03:00
// createRouter creates API routes and router.
func ( h Handler ) createRouter ( ) * mux . Router {
2024-01-25 11:56:05 +03:00
router := mux . NewRouter ( ) . UseEncodedPath ( )
2019-11-14 18:40:05 +03:00
2021-09-15 11:36:14 +03:00
if h . staticConfig . API . 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 )
2021-06-11 16:30:05 +03: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 19:34:04 +03:00
2020-02-11 03:26:04 +03: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 12:18:03 +03:00
version . Handler { } . Append ( router )
2017-11-09 18:12:04 +03:00
2019-11-14 18:40:05 +03:00
return 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 {
2021-06-11 16:30:05 +03: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 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 {
2022-11-21 20:36:05 +03:00
log . Ctx ( request . Context ( ) ) . Error ( ) . Err ( err ) . Send ( )
2018-11-14 12:18:03 +03:00
http . Error ( rw , err . Error ( ) , http . StatusInternalServerError )
2017-11-09 18:12:04 +03:00
}
}
2019-06-19 19:34:04 +03:00
2019-09-02 12:38:04 +03:00
func getProviderName ( id string ) string {
return strings . SplitN ( id , "@" , 2 ) [ 1 ]
2019-06-19 19:34:04 +03:00
}
2019-09-02 12:38:04 +03:00
func extractType ( element interface { } ) string {
v := reflect . ValueOf ( element ) . Elem ( )
2024-02-19 17:44:03 +03:00
for i := range v . NumField ( ) {
2019-09-02 12:38:04 +03:00
field := v . Field ( i )
2021-01-25 13:08:04 +03: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 12:38:04 +03:00
if field . Kind ( ) == reflect . Ptr && field . Elem ( ) . Kind ( ) == reflect . Struct {
if ! field . IsNil ( ) {
return v . Type ( ) . Field ( i ) . Name
}
}
2019-06-19 19:34:04 +03:00
}
2019-09-02 12:38:04 +03:00
return ""
2019-06-19 19:34:04 +03:00
}