2019-07-12 09:10:03 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"net/http"
|
|
|
|
"reflect"
|
|
|
|
|
2020-09-16 13:46:04 +00:00
|
|
|
"github.com/traefik/traefik/v2/pkg/config/runtime"
|
|
|
|
"github.com/traefik/traefik/v2/pkg/config/static"
|
|
|
|
"github.com/traefik/traefik/v2/pkg/log"
|
2019-07-12 09:10:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type schemeOverview struct {
|
|
|
|
Routers *section `json:"routers,omitempty"`
|
|
|
|
Services *section `json:"services,omitempty"`
|
|
|
|
Middlewares *section `json:"middlewares,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type section struct {
|
|
|
|
Total int `json:"total"`
|
|
|
|
Warnings int `json:"warnings"`
|
|
|
|
Errors int `json:"errors"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type features struct {
|
|
|
|
Tracing string `json:"tracing"`
|
|
|
|
Metrics string `json:"metrics"`
|
|
|
|
AccessLog bool `json:"accessLog"`
|
|
|
|
// TODO add certificates resolvers
|
|
|
|
}
|
|
|
|
|
|
|
|
type overview struct {
|
|
|
|
HTTP schemeOverview `json:"http"`
|
|
|
|
TCP schemeOverview `json:"tcp"`
|
2020-02-26 10:12:06 +00:00
|
|
|
UDP schemeOverview `json:"udp"`
|
2019-07-12 09:10:03 +00:00
|
|
|
Features features `json:"features,omitempty"`
|
|
|
|
Providers []string `json:"providers,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h Handler) getOverview(rw http.ResponseWriter, request *http.Request) {
|
|
|
|
result := overview{
|
|
|
|
HTTP: schemeOverview{
|
|
|
|
Routers: getHTTPRouterSection(h.runtimeConfiguration.Routers),
|
|
|
|
Services: getHTTPServiceSection(h.runtimeConfiguration.Services),
|
|
|
|
Middlewares: getHTTPMiddlewareSection(h.runtimeConfiguration.Middlewares),
|
|
|
|
},
|
|
|
|
TCP: schemeOverview{
|
2021-06-11 13:30:05 +00:00
|
|
|
Routers: getTCPRouterSection(h.runtimeConfiguration.TCPRouters),
|
|
|
|
Services: getTCPServiceSection(h.runtimeConfiguration.TCPServices),
|
|
|
|
Middlewares: getTCPMiddlewareSection(h.runtimeConfiguration.TCPMiddlewares),
|
2019-07-12 09:10:03 +00:00
|
|
|
},
|
2020-02-26 10:12:06 +00:00
|
|
|
UDP: schemeOverview{
|
|
|
|
Routers: getUDPRouterSection(h.runtimeConfiguration.UDPRouters),
|
|
|
|
Services: getUDPServiceSection(h.runtimeConfiguration.UDPServices),
|
|
|
|
},
|
2019-07-12 09:10:03 +00:00
|
|
|
Features: getFeatures(h.staticConfig),
|
|
|
|
Providers: getProviders(h.staticConfig),
|
|
|
|
}
|
|
|
|
|
|
|
|
rw.Header().Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
err := json.NewEncoder(rw).Encode(result)
|
|
|
|
if err != nil {
|
|
|
|
log.FromContext(request.Context()).Error(err)
|
2019-09-02 09:38:04 +00:00
|
|
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
2019-07-12 09:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-15 15:04:04 +00:00
|
|
|
func getHTTPRouterSection(routers map[string]*runtime.RouterInfo) *section {
|
2019-07-12 09:10:03 +00:00
|
|
|
var countErrors int
|
2019-07-15 15:04:04 +00:00
|
|
|
var countWarnings int
|
2019-07-12 09:10:03 +00:00
|
|
|
for _, rt := range routers {
|
2019-07-15 15:04:04 +00:00
|
|
|
switch rt.Status {
|
|
|
|
case runtime.StatusDisabled:
|
2019-07-12 09:10:03 +00:00
|
|
|
countErrors++
|
2019-07-15 15:04:04 +00:00
|
|
|
case runtime.StatusWarning:
|
|
|
|
countWarnings++
|
2019-07-12 09:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return §ion{
|
|
|
|
Total: len(routers),
|
2019-07-15 15:04:04 +00:00
|
|
|
Warnings: countWarnings,
|
2019-07-12 09:10:03 +00:00
|
|
|
Errors: countErrors,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-15 15:04:04 +00:00
|
|
|
func getHTTPServiceSection(services map[string]*runtime.ServiceInfo) *section {
|
2019-07-12 09:10:03 +00:00
|
|
|
var countErrors int
|
2019-07-15 15:04:04 +00:00
|
|
|
var countWarnings int
|
2019-07-12 09:10:03 +00:00
|
|
|
for _, svc := range services {
|
2019-07-15 15:04:04 +00:00
|
|
|
switch svc.Status {
|
|
|
|
case runtime.StatusDisabled:
|
2019-07-12 09:10:03 +00:00
|
|
|
countErrors++
|
2019-07-15 15:04:04 +00:00
|
|
|
case runtime.StatusWarning:
|
|
|
|
countWarnings++
|
2019-07-12 09:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return §ion{
|
|
|
|
Total: len(services),
|
2019-07-15 15:04:04 +00:00
|
|
|
Warnings: countWarnings,
|
2019-07-12 09:10:03 +00:00
|
|
|
Errors: countErrors,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-15 15:04:04 +00:00
|
|
|
func getHTTPMiddlewareSection(middlewares map[string]*runtime.MiddlewareInfo) *section {
|
2019-07-12 09:10:03 +00:00
|
|
|
var countErrors int
|
2019-07-19 14:42:04 +00:00
|
|
|
var countWarnings int
|
|
|
|
for _, mid := range middlewares {
|
|
|
|
switch mid.Status {
|
|
|
|
case runtime.StatusDisabled:
|
2019-07-12 09:10:03 +00:00
|
|
|
countErrors++
|
2019-07-19 14:42:04 +00:00
|
|
|
case runtime.StatusWarning:
|
|
|
|
countWarnings++
|
2019-07-12 09:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return §ion{
|
|
|
|
Total: len(middlewares),
|
2019-07-19 14:42:04 +00:00
|
|
|
Warnings: countWarnings,
|
2019-07-12 09:10:03 +00:00
|
|
|
Errors: countErrors,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-15 15:04:04 +00:00
|
|
|
func getTCPRouterSection(routers map[string]*runtime.TCPRouterInfo) *section {
|
2019-07-12 09:10:03 +00:00
|
|
|
var countErrors int
|
2019-07-18 13:56:04 +00:00
|
|
|
var countWarnings int
|
2019-07-12 09:10:03 +00:00
|
|
|
for _, rt := range routers {
|
2019-07-18 13:56:04 +00:00
|
|
|
switch rt.Status {
|
|
|
|
case runtime.StatusDisabled:
|
2019-07-12 09:10:03 +00:00
|
|
|
countErrors++
|
2019-07-18 13:56:04 +00:00
|
|
|
case runtime.StatusWarning:
|
|
|
|
countWarnings++
|
2019-07-12 09:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return §ion{
|
|
|
|
Total: len(routers),
|
2019-07-18 13:56:04 +00:00
|
|
|
Warnings: countWarnings,
|
2019-07-12 09:10:03 +00:00
|
|
|
Errors: countErrors,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-15 15:04:04 +00:00
|
|
|
func getTCPServiceSection(services map[string]*runtime.TCPServiceInfo) *section {
|
2019-07-12 09:10:03 +00:00
|
|
|
var countErrors int
|
2019-07-18 13:56:04 +00:00
|
|
|
var countWarnings int
|
2019-07-12 09:10:03 +00:00
|
|
|
for _, svc := range services {
|
2019-07-18 13:56:04 +00:00
|
|
|
switch svc.Status {
|
|
|
|
case runtime.StatusDisabled:
|
2019-07-12 09:10:03 +00:00
|
|
|
countErrors++
|
2019-07-18 13:56:04 +00:00
|
|
|
case runtime.StatusWarning:
|
|
|
|
countWarnings++
|
2019-07-12 09:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return §ion{
|
|
|
|
Total: len(services),
|
2019-07-18 13:56:04 +00:00
|
|
|
Warnings: countWarnings,
|
2019-07-12 09:10:03 +00:00
|
|
|
Errors: countErrors,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-11 13:30:05 +00:00
|
|
|
func getTCPMiddlewareSection(middlewares map[string]*runtime.TCPMiddlewareInfo) *section {
|
|
|
|
var countErrors int
|
|
|
|
var countWarnings int
|
|
|
|
for _, mid := range middlewares {
|
|
|
|
switch mid.Status {
|
|
|
|
case runtime.StatusDisabled:
|
|
|
|
countErrors++
|
|
|
|
case runtime.StatusWarning:
|
|
|
|
countWarnings++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return §ion{
|
|
|
|
Total: len(middlewares),
|
|
|
|
Warnings: countWarnings,
|
|
|
|
Errors: countErrors,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-26 10:12:06 +00:00
|
|
|
func getUDPRouterSection(routers map[string]*runtime.UDPRouterInfo) *section {
|
|
|
|
var countErrors int
|
|
|
|
var countWarnings int
|
|
|
|
for _, rt := range routers {
|
|
|
|
switch rt.Status {
|
|
|
|
case runtime.StatusDisabled:
|
|
|
|
countErrors++
|
|
|
|
case runtime.StatusWarning:
|
|
|
|
countWarnings++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return §ion{
|
|
|
|
Total: len(routers),
|
|
|
|
Warnings: countWarnings,
|
|
|
|
Errors: countErrors,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func getUDPServiceSection(services map[string]*runtime.UDPServiceInfo) *section {
|
|
|
|
var countErrors int
|
|
|
|
var countWarnings int
|
|
|
|
for _, svc := range services {
|
|
|
|
switch svc.Status {
|
|
|
|
case runtime.StatusDisabled:
|
|
|
|
countErrors++
|
|
|
|
case runtime.StatusWarning:
|
|
|
|
countWarnings++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return §ion{
|
|
|
|
Total: len(services),
|
|
|
|
Warnings: countWarnings,
|
|
|
|
Errors: countErrors,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-12 09:10:03 +00:00
|
|
|
func getProviders(conf static.Configuration) []string {
|
|
|
|
if conf.Providers == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var providers []string
|
|
|
|
|
|
|
|
v := reflect.ValueOf(conf.Providers).Elem()
|
|
|
|
for i := 0; i < v.NumField(); i++ {
|
|
|
|
field := v.Field(i)
|
|
|
|
if field.Kind() == reflect.Ptr && field.Elem().Kind() == reflect.Struct {
|
|
|
|
if !field.IsNil() {
|
|
|
|
providers = append(providers, v.Type().Field(i).Name)
|
|
|
|
}
|
2021-05-11 14:14:10 +00:00
|
|
|
} else if field.Kind() == reflect.Map && field.Type().Elem() == reflect.TypeOf(static.PluginConf{}) {
|
|
|
|
for _, value := range field.MapKeys() {
|
|
|
|
providers = append(providers, "plugin-"+value.String())
|
|
|
|
}
|
2019-07-12 09:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return providers
|
|
|
|
}
|
|
|
|
|
|
|
|
func getFeatures(conf static.Configuration) features {
|
|
|
|
return features{
|
|
|
|
Tracing: getTracing(conf),
|
|
|
|
Metrics: getMetrics(conf),
|
|
|
|
AccessLog: conf.AccessLog != nil,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func getMetrics(conf static.Configuration) string {
|
|
|
|
if conf.Metrics == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
v := reflect.ValueOf(conf.Metrics).Elem()
|
|
|
|
for i := 0; i < v.NumField(); i++ {
|
|
|
|
field := v.Field(i)
|
|
|
|
if field.Kind() == reflect.Ptr && field.Elem().Kind() == reflect.Struct {
|
|
|
|
if !field.IsNil() {
|
|
|
|
return v.Type().Field(i).Name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
func getTracing(conf static.Configuration) string {
|
|
|
|
if conf.Tracing == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
v := reflect.ValueOf(conf.Tracing).Elem()
|
|
|
|
for i := 0; i < v.NumField(); i++ {
|
|
|
|
field := v.Field(i)
|
|
|
|
if field.Kind() == reflect.Ptr && field.Elem().Kind() == reflect.Struct {
|
|
|
|
if !field.IsNil() {
|
|
|
|
return v.Type().Field(i).Name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|