2017-11-09 18:12:04 +03:00
package api
import (
2018-11-14 12:18:03 +03:00
"io"
2017-11-09 18:12:04 +03:00
"net/http"
"github.com/containous/mux"
2018-11-14 12:18:03 +03:00
"github.com/containous/traefik/config"
2017-11-09 18:12:04 +03:00
"github.com/containous/traefik/log"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
2019-02-18 09:52:03 +03:00
assetfs "github.com/elazarl/go-bindata-assetfs"
2018-11-14 12:18:03 +03:00
thoasstats "github.com/thoas/stats"
2017-11-09 18:12:04 +03:00
"github.com/unrolled/render"
)
2018-11-14 12:18:03 +03:00
// ResourceIdentifier a resource identifier
type ResourceIdentifier struct {
ID string ` json:"id" `
Path string ` json:"path" `
}
// ProviderRepresentation a provider with resource identifiers
type ProviderRepresentation struct {
Routers [ ] ResourceIdentifier ` json:"routers,omitempty" `
Middlewares [ ] ResourceIdentifier ` json:"middlewares,omitempty" `
Services [ ] ResourceIdentifier ` json:"services,omitempty" `
}
// RouterRepresentation extended version of a router configuration with an ID
type RouterRepresentation struct {
* config . Router
ID string ` json:"id" `
}
// MiddlewareRepresentation extended version of a middleware configuration with an ID
type MiddlewareRepresentation struct {
* config . Middleware
ID string ` json:"id" `
}
// ServiceRepresentation extended version of a service configuration with an ID
type ServiceRepresentation struct {
* config . Service
ID string ` json:"id" `
}
2017-11-09 18:12:04 +03:00
// Handler expose api routes
type Handler struct {
2018-11-14 12:18:03 +03:00
EntryPoint string
Dashboard bool
Debug bool
2017-11-09 18:12:04 +03:00
CurrentConfigurations * safe . Safe
2018-11-14 12:18:03 +03:00
Statistics * types . Statistics
Stats * thoasstats . Stats
// StatsRecorder *middlewares.StatsRecorder // FIXME stats
DashboardAssets * assetfs . AssetFS
2017-11-09 18:12:04 +03:00
}
2018-11-14 12:18:03 +03:00
var templateRenderer jsonRenderer = render . New ( render . Options { Directory : "nowhere" } )
type jsonRenderer interface {
JSON ( w io . Writer , status int , v interface { } ) error
}
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 ) {
if h . Debug {
2018-11-14 12:18:03 +03:00
DebugHandler { } . Append ( router )
2017-11-09 18:12:04 +03:00
}
2019-03-14 11:30:04 +03:00
router . Methods ( http . MethodGet ) . Path ( "/api/rawdata" ) . HandlerFunc ( h . getRawData )
router . Methods ( http . MethodGet ) . Path ( "/api/providers" ) . HandlerFunc ( h . getProvidersHandler )
router . Methods ( http . MethodGet ) . Path ( "/api/providers/{provider}" ) . HandlerFunc ( h . getProviderHandler )
router . Methods ( http . MethodGet ) . Path ( "/api/providers/{provider}/routers" ) . HandlerFunc ( h . getRoutersHandler )
router . Methods ( http . MethodGet ) . Path ( "/api/providers/{provider}/routers/{router}" ) . HandlerFunc ( h . getRouterHandler )
router . Methods ( http . MethodGet ) . Path ( "/api/providers/{provider}/middlewares" ) . HandlerFunc ( h . getMiddlewaresHandler )
router . Methods ( http . MethodGet ) . Path ( "/api/providers/{provider}/middlewares/{middleware}" ) . HandlerFunc ( h . getMiddlewareHandler )
router . Methods ( http . MethodGet ) . Path ( "/api/providers/{provider}/services" ) . HandlerFunc ( h . getServicesHandler )
router . Methods ( http . MethodGet ) . Path ( "/api/providers/{provider}/services/{service}" ) . HandlerFunc ( h . getServiceHandler )
2017-11-09 18:12:04 +03:00
2018-11-14 12:18:03 +03:00
// FIXME stats
2017-11-09 18:12:04 +03:00
// health route
2018-11-14 12:18:03 +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-03-14 11:30:04 +03:00
if h . Dashboard {
DashboardHandler { Assets : h . DashboardAssets } . Append ( router )
2017-11-09 18:12:04 +03:00
}
}
2019-03-14 11:30:04 +03:00
func ( h Handler ) getRawData ( rw http . ResponseWriter , request * http . Request ) {
if h . CurrentConfigurations != nil {
currentConfigurations , ok := h . CurrentConfigurations . Get ( ) . ( config . Configurations )
if ! ok {
rw . WriteHeader ( http . StatusOK )
return
}
err := templateRenderer . JSON ( rw , http . StatusOK , currentConfigurations )
if err != nil {
log . FromContext ( request . Context ( ) ) . Error ( err )
http . Error ( rw , err . Error ( ) , http . StatusInternalServerError )
}
}
}
func ( h Handler ) getProvidersHandler ( rw http . ResponseWriter , request * http . Request ) {
2018-11-14 12:18:03 +03:00
// FIXME handle currentConfiguration
2019-03-14 11:30:04 +03:00
if h . CurrentConfigurations != nil {
currentConfigurations , ok := h . CurrentConfigurations . Get ( ) . ( config . Configurations )
2018-11-14 12:18:03 +03:00
if ! ok {
rw . WriteHeader ( http . StatusOK )
return
}
var providers [ ] ResourceIdentifier
for name := range currentConfigurations {
providers = append ( providers , ResourceIdentifier {
ID : name ,
Path : "/api/providers/" + name ,
} )
}
err := templateRenderer . JSON ( rw , http . StatusOK , providers )
if err != nil {
log . FromContext ( request . Context ( ) ) . Error ( err )
http . Error ( rw , err . Error ( ) , http . StatusInternalServerError )
}
2017-11-09 18:12:04 +03:00
}
}
2019-03-14 11:30:04 +03:00
func ( h Handler ) getProviderHandler ( rw http . ResponseWriter , request * http . Request ) {
2018-11-14 12:18:03 +03:00
providerID := mux . Vars ( request ) [ "provider" ]
2019-03-14 11:30:04 +03:00
currentConfigurations := h . CurrentConfigurations . Get ( ) . ( config . Configurations )
2018-11-14 12:18:03 +03:00
provider , ok := currentConfigurations [ providerID ]
if ! ok {
http . NotFound ( rw , request )
return
}
2019-03-14 11:30:04 +03:00
if provider . HTTP == nil {
http . NotFound ( rw , request )
return
}
2018-11-14 12:18:03 +03:00
var routers [ ] ResourceIdentifier
2019-03-14 11:30:04 +03:00
for name := range provider . HTTP . Routers {
2018-11-14 12:18:03 +03:00
routers = append ( routers , ResourceIdentifier {
ID : name ,
Path : "/api/providers/" + providerID + "/routers" ,
} )
}
var services [ ] ResourceIdentifier
2019-03-14 11:30:04 +03:00
for name := range provider . HTTP . Services {
2018-11-14 12:18:03 +03:00
services = append ( services , ResourceIdentifier {
ID : name ,
Path : "/api/providers/" + providerID + "/services" ,
} )
}
var middlewares [ ] ResourceIdentifier
2019-03-14 11:30:04 +03:00
for name := range provider . HTTP . Middlewares {
2018-11-14 12:18:03 +03:00
middlewares = append ( middlewares , ResourceIdentifier {
ID : name ,
Path : "/api/providers/" + providerID + "/middlewares" ,
} )
}
providers := ProviderRepresentation { Routers : routers , Middlewares : middlewares , Services : services }
err := templateRenderer . JSON ( rw , http . StatusOK , providers )
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-03-14 11:30:04 +03:00
func ( h Handler ) getRoutersHandler ( rw http . ResponseWriter , request * http . Request ) {
2018-11-14 12:18:03 +03:00
providerID := mux . Vars ( request ) [ "provider" ]
2017-11-09 18:12:04 +03:00
2019-03-14 11:30:04 +03:00
currentConfigurations := h . CurrentConfigurations . Get ( ) . ( config . Configurations )
2018-11-14 12:18:03 +03:00
provider , ok := currentConfigurations [ providerID ]
if ! ok {
http . NotFound ( rw , request )
return
2017-11-09 18:12:04 +03:00
}
2019-03-14 11:30:04 +03:00
if provider . HTTP == nil {
http . NotFound ( rw , request )
return
}
2018-11-14 12:18:03 +03:00
var routers [ ] RouterRepresentation
2019-03-14 11:30:04 +03:00
for name , router := range provider . HTTP . Routers {
2018-11-14 12:18:03 +03:00
routers = append ( routers , RouterRepresentation { Router : router , ID : name } )
}
2017-11-09 18:12:04 +03:00
2018-11-14 12:18:03 +03:00
err := templateRenderer . JSON ( rw , http . StatusOK , routers )
if err != nil {
log . FromContext ( request . Context ( ) ) . Error ( err )
http . Error ( rw , err . Error ( ) , http . StatusInternalServerError )
2017-11-09 18:12:04 +03:00
}
}
2019-03-14 11:30:04 +03:00
func ( h Handler ) getRouterHandler ( rw http . ResponseWriter , request * http . Request ) {
2018-11-14 12:18:03 +03:00
providerID := mux . Vars ( request ) [ "provider" ]
routerID := mux . Vars ( request ) [ "router" ]
2017-11-09 18:12:04 +03:00
2019-03-14 11:30:04 +03:00
currentConfigurations := h . CurrentConfigurations . Get ( ) . ( config . Configurations )
2018-11-14 12:18:03 +03:00
provider , ok := currentConfigurations [ providerID ]
if ! ok {
http . NotFound ( rw , request )
return
}
2019-03-14 11:30:04 +03:00
if provider . HTTP == nil {
http . NotFound ( rw , request )
return
}
router , ok := provider . HTTP . Routers [ routerID ]
2018-11-14 12:18:03 +03:00
if ! ok {
http . NotFound ( rw , request )
return
}
err := templateRenderer . JSON ( rw , http . StatusOK , router )
if err != nil {
log . FromContext ( request . Context ( ) ) . Error ( err )
http . Error ( rw , err . Error ( ) , http . StatusInternalServerError )
2017-11-09 18:12:04 +03:00
}
}
2019-03-14 11:30:04 +03:00
func ( h Handler ) getMiddlewaresHandler ( rw http . ResponseWriter , request * http . Request ) {
2018-11-14 12:18:03 +03:00
providerID := mux . Vars ( request ) [ "provider" ]
2017-11-09 18:12:04 +03:00
2019-03-14 11:30:04 +03:00
currentConfigurations := h . CurrentConfigurations . Get ( ) . ( config . Configurations )
2018-11-14 12:18:03 +03:00
provider , ok := currentConfigurations [ providerID ]
if ! ok {
http . NotFound ( rw , request )
return
2017-11-09 18:12:04 +03:00
}
2018-11-14 12:18:03 +03:00
2019-03-14 11:30:04 +03:00
if provider . HTTP == nil {
http . NotFound ( rw , request )
return
}
2018-11-14 12:18:03 +03:00
var middlewares [ ] MiddlewareRepresentation
2019-03-14 11:30:04 +03:00
for name , middleware := range provider . HTTP . Middlewares {
2018-11-14 12:18:03 +03:00
middlewares = append ( middlewares , MiddlewareRepresentation { Middleware : middleware , ID : name } )
}
err := templateRenderer . JSON ( rw , http . StatusOK , middlewares )
if err != nil {
log . FromContext ( request . Context ( ) ) . Error ( err )
http . Error ( rw , err . Error ( ) , http . StatusInternalServerError )
2017-11-09 18:12:04 +03:00
}
}
2019-03-14 11:30:04 +03:00
func ( h Handler ) getMiddlewareHandler ( rw http . ResponseWriter , request * http . Request ) {
2018-11-14 12:18:03 +03:00
providerID := mux . Vars ( request ) [ "provider" ]
middlewareID := mux . Vars ( request ) [ "middleware" ]
2017-11-09 18:12:04 +03:00
2019-03-14 11:30:04 +03:00
currentConfigurations := h . CurrentConfigurations . Get ( ) . ( config . Configurations )
2018-11-14 12:18:03 +03:00
provider , ok := currentConfigurations [ providerID ]
if ! ok {
http . NotFound ( rw , request )
return
2017-11-09 18:12:04 +03:00
}
2019-03-14 11:30:04 +03:00
if provider . HTTP == nil {
http . NotFound ( rw , request )
return
}
middleware , ok := provider . HTTP . Middlewares [ middlewareID ]
2018-11-14 12:18:03 +03:00
if ! ok {
http . NotFound ( rw , request )
return
}
2017-11-09 18:12:04 +03:00
2018-11-14 12:18:03 +03:00
err := templateRenderer . JSON ( rw , http . StatusOK , middleware )
if err != nil {
log . FromContext ( request . Context ( ) ) . Error ( err )
http . Error ( rw , err . Error ( ) , http . StatusInternalServerError )
2017-11-09 18:12:04 +03:00
}
}
2019-03-14 11:30:04 +03:00
func ( h Handler ) getServicesHandler ( rw http . ResponseWriter , request * http . Request ) {
2018-11-14 12:18:03 +03:00
providerID := mux . Vars ( request ) [ "provider" ]
2017-11-09 18:12:04 +03:00
2019-03-14 11:30:04 +03:00
currentConfigurations := h . CurrentConfigurations . Get ( ) . ( config . Configurations )
2018-11-14 12:18:03 +03:00
provider , ok := currentConfigurations [ providerID ]
if ! ok {
http . NotFound ( rw , request )
return
2017-11-09 18:12:04 +03:00
}
2018-11-14 12:18:03 +03:00
2019-03-14 11:30:04 +03:00
if provider . HTTP == nil {
http . NotFound ( rw , request )
return
}
2018-11-14 12:18:03 +03:00
var services [ ] ServiceRepresentation
2019-03-14 11:30:04 +03:00
for name , service := range provider . HTTP . Services {
2018-11-14 12:18:03 +03:00
services = append ( services , ServiceRepresentation { Service : service , ID : name } )
2017-11-09 18:12:04 +03:00
}
2018-11-14 12:18:03 +03:00
err := templateRenderer . JSON ( rw , http . StatusOK , services )
if err != nil {
log . FromContext ( request . Context ( ) ) . Error ( err )
http . Error ( rw , err . Error ( ) , http . StatusInternalServerError )
}
2017-11-09 18:12:04 +03:00
}
2019-03-14 11:30:04 +03:00
func ( h Handler ) getServiceHandler ( rw http . ResponseWriter , request * http . Request ) {
2018-11-14 12:18:03 +03:00
providerID := mux . Vars ( request ) [ "provider" ]
serviceID := mux . Vars ( request ) [ "service" ]
2019-03-14 11:30:04 +03:00
currentConfigurations := h . CurrentConfigurations . Get ( ) . ( config . Configurations )
2018-11-14 12:18:03 +03:00
provider , ok := currentConfigurations [ providerID ]
if ! ok {
http . NotFound ( rw , request )
return
}
2019-03-14 11:30:04 +03:00
if provider . HTTP == nil {
http . NotFound ( rw , request )
return
}
service , ok := provider . HTTP . Services [ serviceID ]
2018-11-14 12:18:03 +03:00
if ! ok {
http . NotFound ( rw , request )
return
2017-11-09 18:12:04 +03:00
}
2018-11-14 12:18:03 +03:00
err := templateRenderer . JSON ( rw , http . StatusOK , service )
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
}
}