Improve API for the web UI
This commit is contained in:
parent
17554202f6
commit
af9762cf32
41 changed files with 1200 additions and 199 deletions
35
integration/testdata/rawdata-crd.json
vendored
35
integration/testdata/rawdata-crd.json
vendored
|
@ -10,7 +10,10 @@
|
||||||
"tls": {
|
"tls": {
|
||||||
"options": "default/mytlsoption"
|
"options": "default/mytlsoption"
|
||||||
},
|
},
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"default/test2.route-23c7f4c450289ee29016@kubernetescrd": {
|
"default/test2.route-23c7f4c450289ee29016@kubernetescrd": {
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
|
@ -21,7 +24,10 @@
|
||||||
],
|
],
|
||||||
"service": "default/test2.route-23c7f4c450289ee29016",
|
"service": "default/test2.route-23c7f4c450289ee29016",
|
||||||
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/tobestripped`)",
|
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/tobestripped`)",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"middlewares": {
|
"middlewares": {
|
||||||
|
@ -42,10 +48,10 @@
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.4:80"
|
"url": "http://10.42.0.2:80"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.5:80"
|
"url": "http://10.42.0.6:80"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"passHostHeader": true
|
"passHostHeader": true
|
||||||
|
@ -55,18 +61,18 @@
|
||||||
"default/test.route-6b204d94623b3df4370c@kubernetescrd"
|
"default/test.route-6b204d94623b3df4370c@kubernetescrd"
|
||||||
],
|
],
|
||||||
"serverStatus": {
|
"serverStatus": {
|
||||||
"http://10.42.0.4:80": "UP",
|
"http://10.42.0.2:80": "UP",
|
||||||
"http://10.42.0.5:80": "UP"
|
"http://10.42.0.6:80": "UP"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default/test2.route-23c7f4c450289ee29016@kubernetescrd": {
|
"default/test2.route-23c7f4c450289ee29016@kubernetescrd": {
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.4:80"
|
"url": "http://10.42.0.2:80"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.5:80"
|
"url": "http://10.42.0.6:80"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"passHostHeader": true
|
"passHostHeader": true
|
||||||
|
@ -76,8 +82,8 @@
|
||||||
"default/test2.route-23c7f4c450289ee29016@kubernetescrd"
|
"default/test2.route-23c7f4c450289ee29016@kubernetescrd"
|
||||||
],
|
],
|
||||||
"serverStatus": {
|
"serverStatus": {
|
||||||
"http://10.42.0.4:80": "UP",
|
"http://10.42.0.2:80": "UP",
|
||||||
"http://10.42.0.5:80": "UP"
|
"http://10.42.0.6:80": "UP"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -92,7 +98,10 @@
|
||||||
"passthrough": false,
|
"passthrough": false,
|
||||||
"options": "default/mytlsoption"
|
"options": "default/mytlsoption"
|
||||||
},
|
},
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"footcp"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tcpServices": {
|
"tcpServices": {
|
||||||
|
@ -100,10 +109,10 @@
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"address": "10.42.0.3:8080"
|
"address": "10.42.0.4:8080"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "10.42.0.6:8080"
|
"address": "10.42.0.5:8080"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
26
integration/testdata/rawdata-ingress.json
vendored
26
integration/testdata/rawdata-ingress.json
vendored
|
@ -4,17 +4,29 @@
|
||||||
"service": "default/whoami/http",
|
"service": "default/whoami/http",
|
||||||
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
|
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||||
"tls": {},
|
"tls": {},
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"traefik",
|
||||||
|
"web"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"whoami-test-https/whoami@kubernetes": {
|
"whoami-test-https/whoami@kubernetes": {
|
||||||
"service": "default/whoami/http",
|
"service": "default/whoami/http",
|
||||||
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
|
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"traefik",
|
||||||
|
"web"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"whoami-test/whoami@kubernetes": {
|
"whoami-test/whoami@kubernetes": {
|
||||||
"service": "default/whoami/http",
|
"service": "default/whoami/http",
|
||||||
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
|
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"traefik",
|
||||||
|
"web"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
@ -22,10 +34,10 @@
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.4:80"
|
"url": "http://10.42.0.2:80"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.5:80"
|
"url": "http://10.42.0.4:80"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"passHostHeader": true
|
"passHostHeader": true
|
||||||
|
@ -37,8 +49,8 @@
|
||||||
"whoami-test/whoami@kubernetes"
|
"whoami-test/whoami@kubernetes"
|
||||||
],
|
],
|
||||||
"serverStatus": {
|
"serverStatus": {
|
||||||
"http://10.42.0.4:80": "UP",
|
"http://10.42.0.2:80": "UP",
|
||||||
"http://10.42.0.5:80": "UP"
|
"http://10.42.0.4:80": "UP"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
102
pkg/api/criterion.go
Normal file
102
pkg/api/criterion.go
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultPerPage = 100
|
||||||
|
defaultPage = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
const nextPageHeader = "X-Next-Page"
|
||||||
|
|
||||||
|
type pageInfo struct {
|
||||||
|
startIndex int
|
||||||
|
endIndex int
|
||||||
|
nextPage int
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchCriterion struct {
|
||||||
|
Search string `url:"search"`
|
||||||
|
Status string `url:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSearchCriterion(query url.Values) *searchCriterion {
|
||||||
|
if len(query) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
search := query.Get("search")
|
||||||
|
status := query.Get("status")
|
||||||
|
|
||||||
|
if status == "" && search == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &searchCriterion{Search: search, Status: status}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *searchCriterion) withStatus(name string) bool {
|
||||||
|
return c.Status == "" || strings.EqualFold(name, c.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *searchCriterion) searchIn(values ...string) bool {
|
||||||
|
if c.Search == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range values {
|
||||||
|
if strings.Contains(strings.ToLower(v), strings.ToLower(c.Search)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
|
@ -2,9 +2,8 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containous/traefik/v2/pkg/config/runtime"
|
"github.com/containous/traefik/v2/pkg/config/runtime"
|
||||||
|
@ -15,12 +14,19 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type apiError struct {
|
||||||
defaultPerPage = 100
|
Message string `json:"message"`
|
||||||
defaultPage = 1
|
}
|
||||||
)
|
|
||||||
|
|
||||||
const nextPageHeader = "X-Next-Page"
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Error(rw, string(data), code)
|
||||||
|
}
|
||||||
|
|
||||||
type serviceInfoRepresentation struct {
|
type serviceInfoRepresentation struct {
|
||||||
*runtime.ServiceInfo
|
*runtime.ServiceInfo
|
||||||
|
@ -36,12 +42,6 @@ type RunTimeRepresentation struct {
|
||||||
TCPServices map[string]*runtime.TCPServiceInfo `json:"tcpServices,omitempty"`
|
TCPServices map[string]*runtime.TCPServiceInfo `json:"tcpServices,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type pageInfo struct {
|
|
||||||
startIndex int
|
|
||||||
endIndex int
|
|
||||||
nextPage int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handler serves the configuration and status of Traefik on API endpoints.
|
// Handler serves the configuration and status of Traefik on API endpoints.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
dashboard bool
|
dashboard bool
|
||||||
|
@ -136,48 +136,19 @@ func (h Handler) getRuntimeConfiguration(rw http.ResponseWriter, request *http.R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
func getProviderName(id string) string {
|
||||||
return strings.SplitN(id, "@", 2)[1]
|
return strings.SplitN(id, "@", 2)[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractType(element interface{}) string {
|
||||||
|
v := reflect.ValueOf(element).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 ""
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -30,28 +31,31 @@ func (h Handler) getEntryPoints(rw http.ResponseWriter, request *http.Request) {
|
||||||
return results[i].Name < results[j].Name
|
return results[i].Name < results[j].Name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
pageInfo, err := pagination(request, len(results))
|
pageInfo, err := pagination(request, len(results))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||||
|
|
||||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getEntryPoint(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getEntryPoint(rw http.ResponseWriter, request *http.Request) {
|
||||||
entryPointID := mux.Vars(request)["entryPointID"]
|
entryPointID := mux.Vars(request)["entryPointID"]
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
ep, ok := h.staticConfig.EntryPoints[entryPointID]
|
ep, ok := h.staticConfig.EntryPoints[entryPointID]
|
||||||
if !ok {
|
if !ok {
|
||||||
http.NotFound(rw, request)
|
writeError(rw, fmt.Sprintf("entry point not found: %s", entryPointID), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,11 +64,9 @@ func (h Handler) getEntryPoint(rw http.ResponseWriter, request *http.Request) {
|
||||||
Name: entryPointID,
|
Name: entryPointID,
|
||||||
}
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err := json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,11 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/containous/traefik/v2/pkg/config/runtime"
|
"github.com/containous/traefik/v2/pkg/config/runtime"
|
||||||
"github.com/containous/traefik/v2/pkg/log"
|
"github.com/containous/traefik/v2/pkg/log"
|
||||||
|
@ -17,182 +19,224 @@ type routerRepresentation struct {
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newRouterRepresentation(name string, rt *runtime.RouterInfo) routerRepresentation {
|
||||||
|
return routerRepresentation{
|
||||||
|
RouterInfo: rt,
|
||||||
|
Name: name,
|
||||||
|
Provider: getProviderName(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type serviceRepresentation struct {
|
type serviceRepresentation struct {
|
||||||
*runtime.ServiceInfo
|
*runtime.ServiceInfo
|
||||||
ServerStatus map[string]string `json:"serverStatus,omitempty"`
|
ServerStatus map[string]string `json:"serverStatus,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func newServiceRepresentation(name string, si *runtime.ServiceInfo) serviceRepresentation {
|
||||||
|
return serviceRepresentation{
|
||||||
|
ServiceInfo: si,
|
||||||
|
Name: name,
|
||||||
|
Provider: getProviderName(name),
|
||||||
|
ServerStatus: si.GetAllStatus(),
|
||||||
|
Type: strings.ToLower(extractType(si.Service)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type middlewareRepresentation struct {
|
type middlewareRepresentation struct {
|
||||||
*runtime.MiddlewareInfo
|
*runtime.MiddlewareInfo
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMiddlewareRepresentation(name string, mi *runtime.MiddlewareInfo) middlewareRepresentation {
|
||||||
|
return middlewareRepresentation{
|
||||||
|
MiddlewareInfo: mi,
|
||||||
|
Name: name,
|
||||||
|
Provider: getProviderName(name),
|
||||||
|
Type: strings.ToLower(extractType(mi.Middleware)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getRouters(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getRouters(rw http.ResponseWriter, request *http.Request) {
|
||||||
results := make([]routerRepresentation, 0, len(h.runtimeConfiguration.Routers))
|
results := make([]routerRepresentation, 0, len(h.runtimeConfiguration.Routers))
|
||||||
|
|
||||||
|
criterion := newSearchCriterion(request.URL.Query())
|
||||||
|
|
||||||
for name, rt := range h.runtimeConfiguration.Routers {
|
for name, rt := range h.runtimeConfiguration.Routers {
|
||||||
results = append(results, routerRepresentation{
|
if keepRouter(name, rt, criterion) {
|
||||||
RouterInfo: rt,
|
results = append(results, newRouterRepresentation(name, rt))
|
||||||
Name: name,
|
}
|
||||||
Provider: getProviderName(name),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(results, func(i, j int) bool {
|
sort.Slice(results, func(i, j int) bool {
|
||||||
return results[i].Name < results[j].Name
|
return results[i].Name < results[j].Name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
pageInfo, err := pagination(request, len(results))
|
pageInfo, err := pagination(request, len(results))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||||
|
|
||||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getRouter(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getRouter(rw http.ResponseWriter, request *http.Request) {
|
||||||
routerID := mux.Vars(request)["routerID"]
|
routerID := mux.Vars(request)["routerID"]
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
router, ok := h.runtimeConfiguration.Routers[routerID]
|
router, ok := h.runtimeConfiguration.Routers[routerID]
|
||||||
if !ok {
|
if !ok {
|
||||||
http.NotFound(rw, request)
|
writeError(rw, fmt.Sprintf("router not found: %s", routerID), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result := routerRepresentation{
|
result := newRouterRepresentation(routerID, router)
|
||||||
RouterInfo: router,
|
|
||||||
Name: routerID,
|
|
||||||
Provider: getProviderName(routerID),
|
|
||||||
}
|
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err := json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getServices(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getServices(rw http.ResponseWriter, request *http.Request) {
|
||||||
results := make([]serviceRepresentation, 0, len(h.runtimeConfiguration.Services))
|
results := make([]serviceRepresentation, 0, len(h.runtimeConfiguration.Services))
|
||||||
|
|
||||||
|
criterion := newSearchCriterion(request.URL.Query())
|
||||||
|
|
||||||
for name, si := range h.runtimeConfiguration.Services {
|
for name, si := range h.runtimeConfiguration.Services {
|
||||||
results = append(results, serviceRepresentation{
|
if keepService(name, si, criterion) {
|
||||||
ServiceInfo: si,
|
results = append(results, newServiceRepresentation(name, si))
|
||||||
Name: name,
|
}
|
||||||
Provider: getProviderName(name),
|
|
||||||
ServerStatus: si.GetAllStatus(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(results, func(i, j int) bool {
|
sort.Slice(results, func(i, j int) bool {
|
||||||
return results[i].Name < results[j].Name
|
return results[i].Name < results[j].Name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
pageInfo, err := pagination(request, len(results))
|
pageInfo, err := pagination(request, len(results))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||||
|
|
||||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getService(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getService(rw http.ResponseWriter, request *http.Request) {
|
||||||
serviceID := mux.Vars(request)["serviceID"]
|
serviceID := mux.Vars(request)["serviceID"]
|
||||||
|
|
||||||
|
rw.Header().Add("Content-Type", "application/json")
|
||||||
|
|
||||||
service, ok := h.runtimeConfiguration.Services[serviceID]
|
service, ok := h.runtimeConfiguration.Services[serviceID]
|
||||||
if !ok {
|
if !ok {
|
||||||
http.NotFound(rw, request)
|
writeError(rw, fmt.Sprintf("service not found: %s", serviceID), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result := serviceRepresentation{
|
result := newServiceRepresentation(serviceID, service)
|
||||||
ServiceInfo: service,
|
|
||||||
Name: serviceID,
|
|
||||||
Provider: getProviderName(serviceID),
|
|
||||||
ServerStatus: service.GetAllStatus(),
|
|
||||||
}
|
|
||||||
|
|
||||||
rw.Header().Add("Content-Type", "application/json")
|
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err := json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getMiddlewares(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getMiddlewares(rw http.ResponseWriter, request *http.Request) {
|
||||||
results := make([]middlewareRepresentation, 0, len(h.runtimeConfiguration.Middlewares))
|
results := make([]middlewareRepresentation, 0, len(h.runtimeConfiguration.Middlewares))
|
||||||
|
|
||||||
|
criterion := newSearchCriterion(request.URL.Query())
|
||||||
|
|
||||||
for name, mi := range h.runtimeConfiguration.Middlewares {
|
for name, mi := range h.runtimeConfiguration.Middlewares {
|
||||||
results = append(results, middlewareRepresentation{
|
if keepMiddleware(name, mi, criterion) {
|
||||||
MiddlewareInfo: mi,
|
results = append(results, newMiddlewareRepresentation(name, mi))
|
||||||
Name: name,
|
}
|
||||||
Provider: getProviderName(name),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(results, func(i, j int) bool {
|
sort.Slice(results, func(i, j int) bool {
|
||||||
return results[i].Name < results[j].Name
|
return results[i].Name < results[j].Name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
pageInfo, err := pagination(request, len(results))
|
pageInfo, err := pagination(request, len(results))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||||
|
|
||||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getMiddleware(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getMiddleware(rw http.ResponseWriter, request *http.Request) {
|
||||||
middlewareID := mux.Vars(request)["middlewareID"]
|
middlewareID := mux.Vars(request)["middlewareID"]
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
middleware, ok := h.runtimeConfiguration.Middlewares[middlewareID]
|
middleware, ok := h.runtimeConfiguration.Middlewares[middlewareID]
|
||||||
if !ok {
|
if !ok {
|
||||||
http.NotFound(rw, request)
|
writeError(rw, fmt.Sprintf("middleware not found: %s", middlewareID), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result := middlewareRepresentation{
|
result := newMiddlewareRepresentation(middlewareID, middleware)
|
||||||
MiddlewareInfo: middleware,
|
|
||||||
Name: middlewareID,
|
|
||||||
Provider: getProviderName(middlewareID),
|
|
||||||
}
|
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err := json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func keepRouter(name string, item *runtime.RouterInfo, criterion *searchCriterion) bool {
|
||||||
|
if criterion == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return criterion.withStatus(item.Status) && criterion.searchIn(item.Rule, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func keepService(name string, item *runtime.ServiceInfo, criterion *searchCriterion) bool {
|
||||||
|
if criterion == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return criterion.withStatus(item.Status) && criterion.searchIn(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func keepMiddleware(name string, item *runtime.MiddlewareInfo, criterion *searchCriterion) bool {
|
||||||
|
if criterion == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return criterion.withStatus(item.Status) && criterion.searchIn(name)
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -137,6 +138,68 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
statusCode: http.StatusBadRequest,
|
statusCode: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "routers filtered by status",
|
||||||
|
path: "/api/http/routers?status=enabled",
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
Routers: map[string]*runtime.RouterInfo{
|
||||||
|
"test@myprovider": {
|
||||||
|
Router: &dynamic.Router{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
Rule: "Host(`foo.bar.other`)",
|
||||||
|
Middlewares: []string{"addPrefixTest", "auth"},
|
||||||
|
},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
},
|
||||||
|
"bar@myprovider": {
|
||||||
|
Router: &dynamic.Router{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
Middlewares: []string{"auth", "addPrefixTest@anotherprovider"},
|
||||||
|
},
|
||||||
|
Status: runtime.StatusDisabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
nextPage: "1",
|
||||||
|
jsonFile: "testdata/routers-filtered-status.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "routers filtered by search",
|
||||||
|
path: "/api/http/routers?search=fii",
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
Routers: map[string]*runtime.RouterInfo{
|
||||||
|
"test@myprovider": {
|
||||||
|
Router: &dynamic.Router{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "fii-service@myprovider",
|
||||||
|
Rule: "Host(`fii.bar.other`)",
|
||||||
|
Middlewares: []string{"addPrefixTest", "auth"},
|
||||||
|
},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
},
|
||||||
|
"bar@myprovider": {
|
||||||
|
Router: &dynamic.Router{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
Middlewares: []string{"auth", "addPrefixTest@anotherprovider"},
|
||||||
|
},
|
||||||
|
Status: runtime.StatusDisabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
nextPage: "1",
|
||||||
|
jsonFile: "testdata/routers-filtered-search.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one router by id",
|
desc: "one router by id",
|
||||||
path: "/api/http/routers/bar@myprovider",
|
path: "/api/http/routers/bar@myprovider",
|
||||||
|
@ -232,6 +295,45 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
si.UpdateServerStatus("http://127.0.0.2", "UP")
|
si.UpdateServerStatus("http://127.0.0.2", "UP")
|
||||||
return si
|
return si
|
||||||
}(),
|
}(),
|
||||||
|
"canary@myprovider": {
|
||||||
|
Service: &dynamic.Service{
|
||||||
|
Weighted: &dynamic.WeightedRoundRobin{
|
||||||
|
Services: nil,
|
||||||
|
Sticky: &dynamic.Sticky{
|
||||||
|
Cookie: &dynamic.Cookie{
|
||||||
|
Name: "chocolat",
|
||||||
|
Secure: true,
|
||||||
|
HTTPOnly: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
UsedBy: []string{"foo@myprovider"},
|
||||||
|
},
|
||||||
|
"mirror@myprovider": {
|
||||||
|
Service: &dynamic.Service{
|
||||||
|
Mirroring: &dynamic.Mirroring{
|
||||||
|
Service: "one@myprovider",
|
||||||
|
Mirrors: []dynamic.MirrorService{
|
||||||
|
{
|
||||||
|
Name: "two@myprovider",
|
||||||
|
Percent: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "three@myprovider",
|
||||||
|
Percent: 15,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "four@myprovider",
|
||||||
|
Percent: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
UsedBy: []string{"foo@myprovider"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: expected{
|
expected: expected{
|
||||||
|
@ -301,6 +403,100 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
jsonFile: "testdata/services-page2.json",
|
jsonFile: "testdata/services-page2.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "services filtered by status",
|
||||||
|
path: "/api/http/services?status=enabled",
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
|
"bar@myprovider": func() *runtime.ServiceInfo {
|
||||||
|
si := &runtime.ServiceInfo{
|
||||||
|
Service: &dynamic.Service{
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://127.0.0.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider", "test@myprovider"},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
}
|
||||||
|
si.UpdateServerStatus("http://127.0.0.1", "UP")
|
||||||
|
return si
|
||||||
|
}(),
|
||||||
|
"baz@myprovider": func() *runtime.ServiceInfo {
|
||||||
|
si := &runtime.ServiceInfo{
|
||||||
|
Service: &dynamic.Service{
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://127.0.0.2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider"},
|
||||||
|
Status: runtime.StatusDisabled,
|
||||||
|
}
|
||||||
|
si.UpdateServerStatus("http://127.0.0.2", "UP")
|
||||||
|
return si
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
nextPage: "1",
|
||||||
|
jsonFile: "testdata/services-filtered-status.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "services filtered by search",
|
||||||
|
path: "/api/http/services?search=baz",
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
|
"bar@myprovider": func() *runtime.ServiceInfo {
|
||||||
|
si := &runtime.ServiceInfo{
|
||||||
|
Service: &dynamic.Service{
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://127.0.0.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider", "test@myprovider"},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
}
|
||||||
|
si.UpdateServerStatus("http://127.0.0.1", "UP")
|
||||||
|
return si
|
||||||
|
}(),
|
||||||
|
"baz@myprovider": func() *runtime.ServiceInfo {
|
||||||
|
si := &runtime.ServiceInfo{
|
||||||
|
Service: &dynamic.Service{
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://127.0.0.2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider"},
|
||||||
|
Status: runtime.StatusDisabled,
|
||||||
|
}
|
||||||
|
si.UpdateServerStatus("http://127.0.0.2", "UP")
|
||||||
|
return si
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
nextPage: "1",
|
||||||
|
jsonFile: "testdata/services-filtered-search.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one service by id",
|
desc: "one service by id",
|
||||||
path: "/api/http/services/bar@myprovider",
|
path: "/api/http/services/bar@myprovider",
|
||||||
|
@ -411,6 +607,86 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
jsonFile: "testdata/middlewares.json",
|
jsonFile: "testdata/middlewares.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "middlewares filtered by status",
|
||||||
|
path: "/api/http/middlewares?status=enabled",
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
Middlewares: map[string]*runtime.MiddlewareInfo{
|
||||||
|
"auth@myprovider": {
|
||||||
|
Middleware: &dynamic.Middleware{
|
||||||
|
BasicAuth: &dynamic.BasicAuth{
|
||||||
|
Users: []string{"admin:admin"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"bar@myprovider", "test@myprovider"},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
},
|
||||||
|
"addPrefixTest@myprovider": {
|
||||||
|
Middleware: &dynamic.Middleware{
|
||||||
|
AddPrefix: &dynamic.AddPrefix{
|
||||||
|
Prefix: "/titi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"test@myprovider"},
|
||||||
|
Status: runtime.StatusDisabled,
|
||||||
|
},
|
||||||
|
"addPrefixTest@anotherprovider": {
|
||||||
|
Middleware: &dynamic.Middleware{
|
||||||
|
AddPrefix: &dynamic.AddPrefix{
|
||||||
|
Prefix: "/toto",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"bar@myprovider"},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
nextPage: "1",
|
||||||
|
jsonFile: "testdata/middlewares-filtered-status.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "middlewares filtered by search",
|
||||||
|
path: "/api/http/middlewares?search=addprefixtest",
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
Middlewares: map[string]*runtime.MiddlewareInfo{
|
||||||
|
"auth@myprovider": {
|
||||||
|
Middleware: &dynamic.Middleware{
|
||||||
|
BasicAuth: &dynamic.BasicAuth{
|
||||||
|
Users: []string{"admin:admin"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"bar@myprovider", "test@myprovider"},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
},
|
||||||
|
"addPrefixTest@myprovider": {
|
||||||
|
Middleware: &dynamic.Middleware{
|
||||||
|
AddPrefix: &dynamic.AddPrefix{
|
||||||
|
Prefix: "/titi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"test@myprovider"},
|
||||||
|
Status: runtime.StatusDisabled,
|
||||||
|
},
|
||||||
|
"addPrefixTest@anotherprovider": {
|
||||||
|
Middleware: &dynamic.Middleware{
|
||||||
|
AddPrefix: &dynamic.AddPrefix{
|
||||||
|
Prefix: "/toto",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"bar@myprovider"},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
nextPage: "1",
|
||||||
|
jsonFile: "testdata/middlewares-filtered-search.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "all middlewares, 1 res per page, want page 2",
|
desc: "all middlewares, 1 res per page, want page 2",
|
||||||
path: "/api/http/middlewares?page=2&per_page=1",
|
path: "/api/http/middlewares?page=2&per_page=1",
|
||||||
|
@ -521,6 +797,8 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
rtConf := &test.conf
|
rtConf := &test.conf
|
||||||
// To lazily initialize the Statuses.
|
// To lazily initialize the Statuses.
|
||||||
rtConf.PopulateUsedBy()
|
rtConf.PopulateUsedBy()
|
||||||
|
rtConf.GetRoutersByEntryPoints(context.Background(), []string{"web"}, false)
|
||||||
|
|
||||||
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
|
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
handler.Append(router)
|
handler.Append(router)
|
||||||
|
|
|
@ -56,7 +56,7 @@ func (h Handler) getOverview(rw http.ResponseWriter, request *http.Request) {
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err := json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,11 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/containous/traefik/v2/pkg/config/runtime"
|
"github.com/containous/traefik/v2/pkg/config/runtime"
|
||||||
"github.com/containous/traefik/v2/pkg/log"
|
"github.com/containous/traefik/v2/pkg/log"
|
||||||
|
@ -17,118 +19,146 @@ type tcpRouterRepresentation struct {
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newTCPRouterRepresentation(name string, rt *runtime.TCPRouterInfo) tcpRouterRepresentation {
|
||||||
|
return tcpRouterRepresentation{
|
||||||
|
TCPRouterInfo: rt,
|
||||||
|
Name: name,
|
||||||
|
Provider: getProviderName(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type tcpServiceRepresentation struct {
|
type tcpServiceRepresentation struct {
|
||||||
*runtime.TCPServiceInfo
|
*runtime.TCPServiceInfo
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTCPServiceRepresentation(name string, si *runtime.TCPServiceInfo) tcpServiceRepresentation {
|
||||||
|
return tcpServiceRepresentation{
|
||||||
|
TCPServiceInfo: si,
|
||||||
|
Name: name,
|
||||||
|
Provider: getProviderName(name),
|
||||||
|
Type: strings.ToLower(extractType(si.TCPService)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getTCPRouters(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getTCPRouters(rw http.ResponseWriter, request *http.Request) {
|
||||||
results := make([]tcpRouterRepresentation, 0, len(h.runtimeConfiguration.TCPRouters))
|
results := make([]tcpRouterRepresentation, 0, len(h.runtimeConfiguration.TCPRouters))
|
||||||
|
|
||||||
|
criterion := newSearchCriterion(request.URL.Query())
|
||||||
|
|
||||||
for name, rt := range h.runtimeConfiguration.TCPRouters {
|
for name, rt := range h.runtimeConfiguration.TCPRouters {
|
||||||
results = append(results, tcpRouterRepresentation{
|
if keepTCPRouter(name, rt, criterion) {
|
||||||
TCPRouterInfo: rt,
|
results = append(results, newTCPRouterRepresentation(name, rt))
|
||||||
Name: name,
|
}
|
||||||
Provider: getProviderName(name),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(results, func(i, j int) bool {
|
sort.Slice(results, func(i, j int) bool {
|
||||||
return results[i].Name < results[j].Name
|
return results[i].Name < results[j].Name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
pageInfo, err := pagination(request, len(results))
|
pageInfo, err := pagination(request, len(results))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||||
|
|
||||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getTCPRouter(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getTCPRouter(rw http.ResponseWriter, request *http.Request) {
|
||||||
routerID := mux.Vars(request)["routerID"]
|
routerID := mux.Vars(request)["routerID"]
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
router, ok := h.runtimeConfiguration.TCPRouters[routerID]
|
router, ok := h.runtimeConfiguration.TCPRouters[routerID]
|
||||||
if !ok {
|
if !ok {
|
||||||
http.NotFound(rw, request)
|
writeError(rw, fmt.Sprintf("router not found: %s", routerID), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result := tcpRouterRepresentation{
|
result := newTCPRouterRepresentation(routerID, router)
|
||||||
TCPRouterInfo: router,
|
|
||||||
Name: routerID,
|
|
||||||
Provider: getProviderName(routerID),
|
|
||||||
}
|
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err := json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getTCPServices(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getTCPServices(rw http.ResponseWriter, request *http.Request) {
|
||||||
results := make([]tcpServiceRepresentation, 0, len(h.runtimeConfiguration.TCPServices))
|
results := make([]tcpServiceRepresentation, 0, len(h.runtimeConfiguration.TCPServices))
|
||||||
|
|
||||||
|
criterion := newSearchCriterion(request.URL.Query())
|
||||||
|
|
||||||
for name, si := range h.runtimeConfiguration.TCPServices {
|
for name, si := range h.runtimeConfiguration.TCPServices {
|
||||||
results = append(results, tcpServiceRepresentation{
|
if keepTCPService(name, si, criterion) {
|
||||||
TCPServiceInfo: si,
|
results = append(results, newTCPServiceRepresentation(name, si))
|
||||||
Name: name,
|
}
|
||||||
Provider: getProviderName(name),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(results, func(i, j int) bool {
|
sort.Slice(results, func(i, j int) bool {
|
||||||
return results[i].Name < results[j].Name
|
return results[i].Name < results[j].Name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
pageInfo, err := pagination(request, len(results))
|
pageInfo, err := pagination(request, len(results))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||||
|
|
||||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getTCPService(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getTCPService(rw http.ResponseWriter, request *http.Request) {
|
||||||
serviceID := mux.Vars(request)["serviceID"]
|
serviceID := mux.Vars(request)["serviceID"]
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
service, ok := h.runtimeConfiguration.TCPServices[serviceID]
|
service, ok := h.runtimeConfiguration.TCPServices[serviceID]
|
||||||
if !ok {
|
if !ok {
|
||||||
http.NotFound(rw, request)
|
writeError(rw, fmt.Sprintf("service not found: %s", serviceID), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result := tcpServiceRepresentation{
|
result := newTCPServiceRepresentation(serviceID, service)
|
||||||
TCPServiceInfo: service,
|
|
||||||
Name: serviceID,
|
|
||||||
Provider: getProviderName(serviceID),
|
|
||||||
}
|
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err := json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func keepTCPRouter(name string, item *runtime.TCPRouterInfo, criterion *searchCriterion) bool {
|
||||||
|
if criterion == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return criterion.withStatus(item.Status) && criterion.searchIn(item.Rule, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func keepTCPService(name string, item *runtime.TCPServiceInfo, criterion *searchCriterion) bool {
|
||||||
|
if criterion == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return criterion.withStatus(item.Status) && criterion.searchIn(name)
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -112,6 +113,86 @@ func TestHandler_TCP(t *testing.T) {
|
||||||
jsonFile: "testdata/tcprouters-page2.json",
|
jsonFile: "testdata/tcprouters-page2.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP routers filtered by status",
|
||||||
|
path: "/api/tcp/routers?status=enabled",
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
TCPRouters: map[string]*runtime.TCPRouterInfo{
|
||||||
|
"test@myprovider": {
|
||||||
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
Rule: "Host(`foo.bar.other`)",
|
||||||
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
|
Passthrough: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
},
|
||||||
|
"bar@myprovider": {
|
||||||
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
},
|
||||||
|
Status: runtime.StatusWarning,
|
||||||
|
},
|
||||||
|
"foo@myprovider": {
|
||||||
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
},
|
||||||
|
Status: runtime.StatusDisabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
nextPage: "1",
|
||||||
|
jsonFile: "testdata/tcprouters-filtered-status.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP routers filtered by search",
|
||||||
|
path: "/api/tcp/routers?search=bar@my",
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
TCPRouters: map[string]*runtime.TCPRouterInfo{
|
||||||
|
"test@myprovider": {
|
||||||
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
Rule: "Host(`foo.bar.other`)",
|
||||||
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
|
Passthrough: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
},
|
||||||
|
"bar@myprovider": {
|
||||||
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
},
|
||||||
|
Status: runtime.StatusWarning,
|
||||||
|
},
|
||||||
|
"foo@myprovider": {
|
||||||
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
},
|
||||||
|
Status: runtime.StatusDisabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
nextPage: "1",
|
||||||
|
jsonFile: "testdata/tcprouters-filtered-search.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one TCP router by id",
|
desc: "one TCP router by id",
|
||||||
path: "/api/tcp/routers/bar@myprovider",
|
path: "/api/tcp/routers/bar@myprovider",
|
||||||
|
@ -219,6 +300,110 @@ func TestHandler_TCP(t *testing.T) {
|
||||||
jsonFile: "testdata/tcpservices.json",
|
jsonFile: "testdata/tcpservices.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "tcp services filtered by status",
|
||||||
|
path: "/api/tcp/services?status=enabled",
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
TCPServices: map[string]*runtime.TCPServiceInfo{
|
||||||
|
"bar@myprovider": {
|
||||||
|
TCPService: &dynamic.TCPService{
|
||||||
|
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||||
|
Servers: []dynamic.TCPServer{
|
||||||
|
{
|
||||||
|
Address: "127.0.0.1:2345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider", "test@myprovider"},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
},
|
||||||
|
"baz@myprovider": {
|
||||||
|
TCPService: &dynamic.TCPService{
|
||||||
|
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||||
|
Servers: []dynamic.TCPServer{
|
||||||
|
{
|
||||||
|
Address: "127.0.0.2:2345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider"},
|
||||||
|
Status: runtime.StatusWarning,
|
||||||
|
},
|
||||||
|
"foz@myprovider": {
|
||||||
|
TCPService: &dynamic.TCPService{
|
||||||
|
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||||
|
Servers: []dynamic.TCPServer{
|
||||||
|
{
|
||||||
|
Address: "127.0.0.2:2345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider"},
|
||||||
|
Status: runtime.StatusDisabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
nextPage: "1",
|
||||||
|
jsonFile: "testdata/tcpservices-filtered-status.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "tcp services filtered by search",
|
||||||
|
path: "/api/tcp/services?search=baz@my",
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
TCPServices: map[string]*runtime.TCPServiceInfo{
|
||||||
|
"bar@myprovider": {
|
||||||
|
TCPService: &dynamic.TCPService{
|
||||||
|
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||||
|
Servers: []dynamic.TCPServer{
|
||||||
|
{
|
||||||
|
Address: "127.0.0.1:2345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider", "test@myprovider"},
|
||||||
|
Status: runtime.StatusEnabled,
|
||||||
|
},
|
||||||
|
"baz@myprovider": {
|
||||||
|
TCPService: &dynamic.TCPService{
|
||||||
|
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||||
|
Servers: []dynamic.TCPServer{
|
||||||
|
{
|
||||||
|
Address: "127.0.0.2:2345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider"},
|
||||||
|
Status: runtime.StatusWarning,
|
||||||
|
},
|
||||||
|
"foz@myprovider": {
|
||||||
|
TCPService: &dynamic.TCPService{
|
||||||
|
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||||
|
Servers: []dynamic.TCPServer{
|
||||||
|
{
|
||||||
|
Address: "127.0.0.2:2345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider"},
|
||||||
|
Status: runtime.StatusDisabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
nextPage: "1",
|
||||||
|
jsonFile: "testdata/tcpservices-filtered-search.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "all tcp services, 1 res per page, want page 2",
|
desc: "all tcp services, 1 res per page, want page 2",
|
||||||
path: "/api/tcp/services?page=2&per_page=1",
|
path: "/api/tcp/services?page=2&per_page=1",
|
||||||
|
@ -330,6 +515,10 @@ func TestHandler_TCP(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
rtConf := &test.conf
|
rtConf := &test.conf
|
||||||
|
// To lazily initialize the Statuses.
|
||||||
|
rtConf.PopulateUsedBy()
|
||||||
|
rtConf.GetTCPRoutersByEntryPoints(context.Background(), []string{"web"})
|
||||||
|
|
||||||
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
|
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
handler.Append(router)
|
handler.Append(router)
|
||||||
|
|
1
pkg/api/testdata/middleware-auth.json
vendored
1
pkg/api/testdata/middleware-auth.json
vendored
|
@ -7,6 +7,7 @@
|
||||||
"name": "auth@myprovider",
|
"name": "auth@myprovider",
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
"type": "basicauth",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"bar@myprovider",
|
"bar@myprovider",
|
||||||
"test@myprovider"
|
"test@myprovider"
|
||||||
|
|
26
pkg/api/testdata/middlewares-filtered-search.json
vendored
Normal file
26
pkg/api/testdata/middlewares-filtered-search.json
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"addPrefix": {
|
||||||
|
"prefix": "/toto"
|
||||||
|
},
|
||||||
|
"name": "addPrefixTest@anotherprovider",
|
||||||
|
"provider": "anotherprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "addprefix",
|
||||||
|
"usedBy": [
|
||||||
|
"bar@myprovider"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addPrefix": {
|
||||||
|
"prefix": "/titi"
|
||||||
|
},
|
||||||
|
"name": "addPrefixTest@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"status": "disabled",
|
||||||
|
"type": "addprefix",
|
||||||
|
"usedBy": [
|
||||||
|
"test@myprovider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
29
pkg/api/testdata/middlewares-filtered-status.json
vendored
Normal file
29
pkg/api/testdata/middlewares-filtered-status.json
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"addPrefix": {
|
||||||
|
"prefix": "/toto"
|
||||||
|
},
|
||||||
|
"name": "addPrefixTest@anotherprovider",
|
||||||
|
"provider": "anotherprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "addprefix",
|
||||||
|
"usedBy": [
|
||||||
|
"bar@myprovider"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"basicAuth": {
|
||||||
|
"users": [
|
||||||
|
"admin:admin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "auth@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "basicauth",
|
||||||
|
"usedBy": [
|
||||||
|
"bar@myprovider",
|
||||||
|
"test@myprovider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
1
pkg/api/testdata/middlewares-page2.json
vendored
1
pkg/api/testdata/middlewares-page2.json
vendored
|
@ -6,6 +6,7 @@
|
||||||
"name": "addPrefixTest@myprovider",
|
"name": "addPrefixTest@myprovider",
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
"type": "addprefix",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"test@myprovider"
|
"test@myprovider"
|
||||||
]
|
]
|
||||||
|
|
3
pkg/api/testdata/middlewares.json
vendored
3
pkg/api/testdata/middlewares.json
vendored
|
@ -6,6 +6,7 @@
|
||||||
"name": "addPrefixTest@anotherprovider",
|
"name": "addPrefixTest@anotherprovider",
|
||||||
"provider": "anotherprovider",
|
"provider": "anotherprovider",
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
"type": "addprefix",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"bar@myprovider"
|
"bar@myprovider"
|
||||||
]
|
]
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
"name": "addPrefixTest@myprovider",
|
"name": "addPrefixTest@myprovider",
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
"type": "addprefix",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"test@myprovider"
|
"test@myprovider"
|
||||||
]
|
]
|
||||||
|
@ -30,6 +32,7 @@
|
||||||
"name": "auth@myprovider",
|
"name": "auth@myprovider",
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
"type": "basicauth",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"bar@myprovider",
|
"bar@myprovider",
|
||||||
"test@myprovider"
|
"test@myprovider"
|
||||||
|
|
5
pkg/api/testdata/router-bar.json
vendored
5
pkg/api/testdata/router-bar.json
vendored
|
@ -10,5 +10,8 @@
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`foo.bar`)",
|
"rule": "Host(`foo.bar`)",
|
||||||
"service": "foo-service@myprovider",
|
"service": "foo-service@myprovider",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
}
|
}
|
19
pkg/api/testdata/routers-filtered-search.json
vendored
Normal file
19
pkg/api/testdata/routers-filtered-search.json
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"entryPoints": [
|
||||||
|
"web"
|
||||||
|
],
|
||||||
|
"middlewares": [
|
||||||
|
"addPrefixTest",
|
||||||
|
"auth"
|
||||||
|
],
|
||||||
|
"name": "test@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"rule": "Host(`fii.bar.other`)",
|
||||||
|
"service": "fii-service@myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
19
pkg/api/testdata/routers-filtered-status.json
vendored
Normal file
19
pkg/api/testdata/routers-filtered-status.json
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"entryPoints": [
|
||||||
|
"web"
|
||||||
|
],
|
||||||
|
"middlewares": [
|
||||||
|
"addPrefixTest",
|
||||||
|
"auth"
|
||||||
|
],
|
||||||
|
"name": "test@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"rule": "Host(`foo.bar.other`)",
|
||||||
|
"service": "foo-service@myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
25
pkg/api/testdata/routers-many-lastpage.json
vendored
25
pkg/api/testdata/routers-many-lastpage.json
vendored
|
@ -7,7 +7,10 @@
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`foo.bar14`)",
|
"rule": "Host(`foo.bar14`)",
|
||||||
"service": "foo-service@myprovider",
|
"service": "foo-service@myprovider",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
|
@ -17,7 +20,10 @@
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`foo.bar15`)",
|
"rule": "Host(`foo.bar15`)",
|
||||||
"service": "foo-service@myprovider",
|
"service": "foo-service@myprovider",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
|
@ -27,7 +33,10 @@
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`foo.bar16`)",
|
"rule": "Host(`foo.bar16`)",
|
||||||
"service": "foo-service@myprovider",
|
"service": "foo-service@myprovider",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
|
@ -37,7 +46,10 @@
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`foo.bar17`)",
|
"rule": "Host(`foo.bar17`)",
|
||||||
"service": "foo-service@myprovider",
|
"service": "foo-service@myprovider",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
|
@ -47,6 +59,9 @@
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`foo.bar18`)",
|
"rule": "Host(`foo.bar18`)",
|
||||||
"service": "foo-service@myprovider",
|
"service": "foo-service@myprovider",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
5
pkg/api/testdata/routers-page2.json
vendored
5
pkg/api/testdata/routers-page2.json
vendored
|
@ -7,6 +7,9 @@
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`toto.bar`)",
|
"rule": "Host(`toto.bar`)",
|
||||||
"service": "foo-service@myprovider",
|
"service": "foo-service@myprovider",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
10
pkg/api/testdata/routers.json
vendored
10
pkg/api/testdata/routers.json
vendored
|
@ -11,7 +11,10 @@
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`foo.bar`)",
|
"rule": "Host(`foo.bar`)",
|
||||||
"service": "foo-service@myprovider",
|
"service": "foo-service@myprovider",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
|
@ -25,6 +28,9 @@
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`foo.bar.other`)",
|
"rule": "Host(`foo.bar.other`)",
|
||||||
"service": "foo-service@myprovider",
|
"service": "foo-service@myprovider",
|
||||||
"status": "enabled"
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
1
pkg/api/testdata/service-bar.json
vendored
1
pkg/api/testdata/service-bar.json
vendored
|
@ -13,6 +13,7 @@
|
||||||
"http://127.0.0.1": "UP"
|
"http://127.0.0.1": "UP"
|
||||||
},
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"foo@myprovider",
|
"foo@myprovider",
|
||||||
"test@myprovider"
|
"test@myprovider"
|
||||||
|
|
22
pkg/api/testdata/services-filtered-search.json
vendored
Normal file
22
pkg/api/testdata/services-filtered-search.json
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"loadBalancer": {
|
||||||
|
"passHostHeader": false,
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "http://127.0.0.2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "baz@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"serverStatus": {
|
||||||
|
"http://127.0.0.2": "UP"
|
||||||
|
},
|
||||||
|
"status": "disabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
|
"usedBy": [
|
||||||
|
"foo@myprovider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
23
pkg/api/testdata/services-filtered-status.json
vendored
Normal file
23
pkg/api/testdata/services-filtered-status.json
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"loadBalancer": {
|
||||||
|
"passHostHeader": false,
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "http://127.0.0.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "bar@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"serverStatus": {
|
||||||
|
"http://127.0.0.1": "UP"
|
||||||
|
},
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
|
"usedBy": [
|
||||||
|
"foo@myprovider",
|
||||||
|
"test@myprovider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
1
pkg/api/testdata/services-page2.json
vendored
1
pkg/api/testdata/services-page2.json
vendored
|
@ -14,6 +14,7 @@
|
||||||
"http://127.0.0.2": "UP"
|
"http://127.0.0.2": "UP"
|
||||||
},
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"foo@myprovider"
|
"foo@myprovider"
|
||||||
]
|
]
|
||||||
|
|
46
pkg/api/testdata/services.json
vendored
46
pkg/api/testdata/services.json
vendored
|
@ -14,6 +14,7 @@
|
||||||
"http://127.0.0.1": "UP"
|
"http://127.0.0.1": "UP"
|
||||||
},
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"foo@myprovider",
|
"foo@myprovider",
|
||||||
"test@myprovider"
|
"test@myprovider"
|
||||||
|
@ -34,6 +35,51 @@
|
||||||
"http://127.0.0.2": "UP"
|
"http://127.0.0.2": "UP"
|
||||||
},
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
|
"usedBy": [
|
||||||
|
"foo@myprovider"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "canary@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "weighted",
|
||||||
|
"usedBy": [
|
||||||
|
"foo@myprovider"
|
||||||
|
],
|
||||||
|
"weighted": {
|
||||||
|
"sticky": {
|
||||||
|
"cookie": {
|
||||||
|
"httpOnly": true,
|
||||||
|
"name": "chocolat",
|
||||||
|
"secure": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mirroring": {
|
||||||
|
"mirrors": [
|
||||||
|
{
|
||||||
|
"name": "two@myprovider",
|
||||||
|
"percent": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "three@myprovider",
|
||||||
|
"percent": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "four@myprovider",
|
||||||
|
"percent": 80
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"service": "one@myprovider"
|
||||||
|
},
|
||||||
|
"name": "mirror@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "mirroring",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"foo@myprovider"
|
"foo@myprovider"
|
||||||
]
|
]
|
||||||
|
|
6
pkg/api/testdata/tcprouter-bar.json
vendored
6
pkg/api/testdata/tcprouter-bar.json
vendored
|
@ -5,5 +5,9 @@
|
||||||
"name": "bar@myprovider",
|
"name": "bar@myprovider",
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`foo.bar`)",
|
"rule": "Host(`foo.bar`)",
|
||||||
"service": "foo-service@myprovider"
|
"service": "foo-service@myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
}
|
}
|
15
pkg/api/testdata/tcprouters-filtered-search.json
vendored
Normal file
15
pkg/api/testdata/tcprouters-filtered-search.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"entryPoints": [
|
||||||
|
"web"
|
||||||
|
],
|
||||||
|
"name": "bar@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"rule": "Host(`foo.bar`)",
|
||||||
|
"service": "foo-service@myprovider",
|
||||||
|
"status": "warning",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
18
pkg/api/testdata/tcprouters-filtered-status.json
vendored
Normal file
18
pkg/api/testdata/tcprouters-filtered-status.json
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"entryPoints": [
|
||||||
|
"web"
|
||||||
|
],
|
||||||
|
"name": "test@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"rule": "Host(`foo.bar.other`)",
|
||||||
|
"service": "foo-service@myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"tls": {
|
||||||
|
"passthrough": false
|
||||||
|
},
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
6
pkg/api/testdata/tcprouters-page2.json
vendored
6
pkg/api/testdata/tcprouters-page2.json
vendored
|
@ -6,6 +6,10 @@
|
||||||
"name": "baz@myprovider",
|
"name": "baz@myprovider",
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`toto.bar`)",
|
"rule": "Host(`toto.bar`)",
|
||||||
"service": "foo-service@myprovider"
|
"service": "foo-service@myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
15
pkg/api/testdata/tcprouters.json
vendored
15
pkg/api/testdata/tcprouters.json
vendored
|
@ -7,7 +7,10 @@
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`foo.bar`)",
|
"rule": "Host(`foo.bar`)",
|
||||||
"service": "foo-service@myprovider",
|
"service": "foo-service@myprovider",
|
||||||
"status": "warning"
|
"status": "warning",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
|
@ -17,7 +20,10 @@
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"rule": "Host(`foo.bar`)",
|
"rule": "Host(`foo.bar`)",
|
||||||
"service": "foo-service@myprovider",
|
"service": "foo-service@myprovider",
|
||||||
"status": "disabled"
|
"status": "disabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
|
@ -30,6 +36,9 @@
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"tls": {
|
"tls": {
|
||||||
"passthrough": false
|
"passthrough": false
|
||||||
}
|
},
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
2
pkg/api/testdata/tcpservice-bar.json
vendored
2
pkg/api/testdata/tcpservice-bar.json
vendored
|
@ -8,6 +8,8 @@
|
||||||
},
|
},
|
||||||
"name": "bar@myprovider",
|
"name": "bar@myprovider",
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"foo@myprovider",
|
"foo@myprovider",
|
||||||
"test@myprovider"
|
"test@myprovider"
|
||||||
|
|
18
pkg/api/testdata/tcpservices-filtered-search.json
vendored
Normal file
18
pkg/api/testdata/tcpservices-filtered-search.json
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"loadBalancer": {
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"address": "127.0.0.2:2345"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "baz@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"status": "warning",
|
||||||
|
"type": "loadbalancer",
|
||||||
|
"usedBy": [
|
||||||
|
"foo@myprovider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
19
pkg/api/testdata/tcpservices-filtered-status.json
vendored
Normal file
19
pkg/api/testdata/tcpservices-filtered-status.json
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"loadBalancer": {
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"address": "127.0.0.1:2345"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "bar@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
|
"usedBy": [
|
||||||
|
"foo@myprovider",
|
||||||
|
"test@myprovider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
2
pkg/api/testdata/tcpservices-page2.json
vendored
2
pkg/api/testdata/tcpservices-page2.json
vendored
|
@ -9,6 +9,8 @@
|
||||||
},
|
},
|
||||||
"name": "baz@myprovider",
|
"name": "baz@myprovider",
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"foo@myprovider"
|
"foo@myprovider"
|
||||||
]
|
]
|
||||||
|
|
3
pkg/api/testdata/tcpservices.json
vendored
3
pkg/api/testdata/tcpservices.json
vendored
|
@ -10,6 +10,7 @@
|
||||||
"name": "bar@myprovider",
|
"name": "bar@myprovider",
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"foo@myprovider",
|
"foo@myprovider",
|
||||||
"test@myprovider"
|
"test@myprovider"
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
"name": "baz@myprovider",
|
"name": "baz@myprovider",
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"status": "warning",
|
"status": "warning",
|
||||||
|
"type": "loadbalancer",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"foo@myprovider"
|
"foo@myprovider"
|
||||||
]
|
]
|
||||||
|
@ -41,6 +43,7 @@
|
||||||
"name": "foz@myprovider",
|
"name": "foz@myprovider",
|
||||||
"provider": "myprovider",
|
"provider": "myprovider",
|
||||||
"status": "disabled",
|
"status": "disabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"foo@myprovider"
|
"foo@myprovider"
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,13 +3,14 @@ package runtime
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||||
"github.com/containous/traefik/v2/pkg/log"
|
"github.com/containous/traefik/v2/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetRoutersByEntryPoints returns all the http routers by entry points name and routers name
|
// GetRoutersByEntryPoints returns all the http routers by entry points name and routers name.
|
||||||
func (c *Configuration) GetRoutersByEntryPoints(ctx context.Context, entryPoints []string, tls bool) map[string]map[string]*RouterInfo {
|
func (c *Configuration) GetRoutersByEntryPoints(ctx context.Context, entryPoints []string, tls bool) map[string]map[string]*RouterInfo {
|
||||||
entryPointsRouters := make(map[string]map[string]*RouterInfo)
|
entryPointsRouters := make(map[string]map[string]*RouterInfo)
|
||||||
|
|
||||||
|
@ -19,11 +20,13 @@ func (c *Configuration) GetRoutersByEntryPoints(ctx context.Context, entryPoints
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := log.FromContext(log.With(ctx, log.Str(log.RouterName, rtName)))
|
logger := log.FromContext(log.With(ctx, log.Str(log.RouterName, rtName)))
|
||||||
|
|
||||||
eps := rt.EntryPoints
|
eps := rt.EntryPoints
|
||||||
if len(eps) == 0 {
|
if len(eps) == 0 {
|
||||||
logger.Debugf("No entrypoint defined for this router, using the default one(s) instead: %+v", entryPoints)
|
logger.Debugf("No entryPoint defined for this router, using the default one(s) instead: %+v", entryPoints)
|
||||||
eps = entryPoints
|
eps = entryPoints
|
||||||
}
|
}
|
||||||
|
|
||||||
entryPointsCount := 0
|
entryPointsCount := 0
|
||||||
for _, entryPointName := range eps {
|
for _, entryPointName := range eps {
|
||||||
if !contains(entryPoints, entryPointName) {
|
if !contains(entryPoints, entryPointName) {
|
||||||
|
@ -33,23 +36,44 @@ func (c *Configuration) GetRoutersByEntryPoints(ctx context.Context, entryPoints
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
entryPointsCount++
|
|
||||||
if _, ok := entryPointsRouters[entryPointName]; !ok {
|
if _, ok := entryPointsRouters[entryPointName]; !ok {
|
||||||
entryPointsRouters[entryPointName] = make(map[string]*RouterInfo)
|
entryPointsRouters[entryPointName] = make(map[string]*RouterInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entryPointsCount++
|
||||||
|
rt.Using = append(rt.Using, entryPointName)
|
||||||
|
|
||||||
entryPointsRouters[entryPointName][rtName] = rt
|
entryPointsRouters[entryPointName][rtName] = rt
|
||||||
}
|
}
|
||||||
|
|
||||||
if entryPointsCount == 0 {
|
if entryPointsCount == 0 {
|
||||||
rt.AddError(fmt.Errorf("no valid entryPoint for this router"), true)
|
rt.AddError(fmt.Errorf("no valid entryPoint for this router"), true)
|
||||||
logger.Error("no valid entryPoint for this router")
|
logger.Error("no valid entryPoint for this router")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rt.Using = unique(rt.Using)
|
||||||
}
|
}
|
||||||
|
|
||||||
return entryPointsRouters
|
return entryPointsRouters
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouterInfo holds information about a currently running HTTP router
|
func unique(src []string) []string {
|
||||||
|
var uniq []string
|
||||||
|
|
||||||
|
set := make(map[string]struct{})
|
||||||
|
for _, v := range src {
|
||||||
|
if _, exist := set[v]; !exist {
|
||||||
|
set[v] = struct{}{}
|
||||||
|
uniq = append(uniq, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(uniq)
|
||||||
|
|
||||||
|
return uniq
|
||||||
|
}
|
||||||
|
|
||||||
|
// RouterInfo holds information about a currently running HTTP router.
|
||||||
type RouterInfo struct {
|
type RouterInfo struct {
|
||||||
*dynamic.Router // dynamic configuration
|
*dynamic.Router // dynamic configuration
|
||||||
// Err contains all the errors that occurred during router's creation.
|
// Err contains all the errors that occurred during router's creation.
|
||||||
|
@ -57,7 +81,8 @@ type RouterInfo struct {
|
||||||
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
||||||
// If not in "enabled" state, the reason for it should be in the list of Err.
|
// If not in "enabled" state, the reason for it should be in the list of Err.
|
||||||
// It is the caller's responsibility to set the initial status.
|
// It is the caller's responsibility to set the initial status.
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
|
Using []string `json:"using,omitempty"` // Effective entry points used by that router.
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddError adds err to r.Err, if it does not already exist.
|
// AddError adds err to r.Err, if it does not already exist.
|
||||||
|
@ -81,13 +106,13 @@ func (r *RouterInfo) AddError(err error, critical bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MiddlewareInfo holds information about a currently running middleware
|
// MiddlewareInfo holds information about a currently running middleware.
|
||||||
type MiddlewareInfo struct {
|
type MiddlewareInfo struct {
|
||||||
*dynamic.Middleware // dynamic configuration
|
*dynamic.Middleware // dynamic configuration
|
||||||
// Err contains all the errors that occurred during service creation.
|
// Err contains all the errors that occurred during service creation.
|
||||||
Err []string `json:"error,omitempty"`
|
Err []string `json:"error,omitempty"`
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
UsedBy []string `json:"usedBy,omitempty"` // list of routers and services using that middleware
|
UsedBy []string `json:"usedBy,omitempty"` // list of routers and services using that middleware.
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddError adds err to s.Err, if it does not already exist.
|
// AddError adds err to s.Err, if it does not already exist.
|
||||||
|
@ -111,7 +136,7 @@ func (m *MiddlewareInfo) AddError(err error, critical bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceInfo holds information about a currently running service
|
// ServiceInfo holds information about a currently running service.
|
||||||
type ServiceInfo struct {
|
type ServiceInfo struct {
|
||||||
*dynamic.Service // dynamic configuration
|
*dynamic.Service // dynamic configuration
|
||||||
// Err contains all the errors that occurred during service creation.
|
// Err contains all the errors that occurred during service creation.
|
||||||
|
|
|
@ -104,6 +104,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||||
Rule: "Host(`bar.foo`)",
|
Rule: "Host(`bar.foo`)",
|
||||||
},
|
},
|
||||||
Status: "enabled",
|
Status: "enabled",
|
||||||
|
Using: []string{"web"},
|
||||||
},
|
},
|
||||||
"foobar": {
|
"foobar": {
|
||||||
Router: &dynamic.Router{
|
Router: &dynamic.Router{
|
||||||
|
@ -113,6 +114,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||||
},
|
},
|
||||||
Status: "warning",
|
Status: "warning",
|
||||||
Err: []string{`entryPoint "webs" doesn't exist`},
|
Err: []string{`entryPoint "webs" doesn't exist`},
|
||||||
|
Using: []string{"web"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -169,6 +171,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||||
Rule: "Host(`bar.foo`)",
|
Rule: "Host(`bar.foo`)",
|
||||||
},
|
},
|
||||||
Status: "enabled",
|
Status: "enabled",
|
||||||
|
Using: []string{"web"},
|
||||||
},
|
},
|
||||||
"foobar": {
|
"foobar": {
|
||||||
Router: &dynamic.Router{
|
Router: &dynamic.Router{
|
||||||
|
@ -177,6 +180,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||||
Rule: "Host(`bar.foobar`)",
|
Rule: "Host(`bar.foobar`)",
|
||||||
},
|
},
|
||||||
Status: "enabled",
|
Status: "enabled",
|
||||||
|
Using: []string{"web", "webs"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"webs": {
|
"webs": {
|
||||||
|
@ -188,6 +192,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||||
Rule: "Host(`foo.bar`)",
|
Rule: "Host(`foo.bar`)",
|
||||||
},
|
},
|
||||||
Status: "enabled",
|
Status: "enabled",
|
||||||
|
Using: []string{"webs"},
|
||||||
},
|
},
|
||||||
"foobar": {
|
"foobar": {
|
||||||
Router: &dynamic.Router{
|
Router: &dynamic.Router{
|
||||||
|
@ -196,6 +201,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||||
Rule: "Host(`bar.foobar`)",
|
Rule: "Host(`bar.foobar`)",
|
||||||
},
|
},
|
||||||
Status: "enabled",
|
Status: "enabled",
|
||||||
|
Using: []string{"web", "webs"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,24 +2,30 @@ package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||||
"github.com/containous/traefik/v2/pkg/log"
|
"github.com/containous/traefik/v2/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetTCPRoutersByEntryPoints returns all the tcp routers by entry points name and routers name
|
// GetTCPRoutersByEntryPoints returns all the tcp routers by entry points name and routers name.
|
||||||
func (c *Configuration) GetTCPRoutersByEntryPoints(ctx context.Context, entryPoints []string) map[string]map[string]*TCPRouterInfo {
|
func (c *Configuration) GetTCPRoutersByEntryPoints(ctx context.Context, entryPoints []string) map[string]map[string]*TCPRouterInfo {
|
||||||
entryPointsRouters := make(map[string]map[string]*TCPRouterInfo)
|
entryPointsRouters := make(map[string]map[string]*TCPRouterInfo)
|
||||||
|
|
||||||
for rtName, rt := range c.TCPRouters {
|
for rtName, rt := range c.TCPRouters {
|
||||||
|
logger := log.FromContext(log.With(ctx, log.Str(log.RouterName, rtName)))
|
||||||
|
|
||||||
eps := rt.EntryPoints
|
eps := rt.EntryPoints
|
||||||
if len(eps) == 0 {
|
if len(eps) == 0 {
|
||||||
|
logger.Debugf("No entryPoint defined for this router, using the default one(s) instead: %+v", entryPoints)
|
||||||
eps = entryPoints
|
eps = entryPoints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entryPointsCount := 0
|
||||||
for _, entryPointName := range eps {
|
for _, entryPointName := range eps {
|
||||||
if !contains(entryPoints, entryPointName) {
|
if !contains(entryPoints, entryPointName) {
|
||||||
log.FromContext(log.With(ctx, log.Str(log.EntryPointName, entryPointName))).
|
rt.AddError(fmt.Errorf("entryPoint %q doesn't exist", entryPointName), false)
|
||||||
|
logger.WithField(log.EntryPointName, entryPointName).
|
||||||
Errorf("entryPoint %q doesn't exist", entryPointName)
|
Errorf("entryPoint %q doesn't exist", entryPointName)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -28,21 +34,30 @@ func (c *Configuration) GetTCPRoutersByEntryPoints(ctx context.Context, entryPoi
|
||||||
entryPointsRouters[entryPointName] = make(map[string]*TCPRouterInfo)
|
entryPointsRouters[entryPointName] = make(map[string]*TCPRouterInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entryPointsCount++
|
||||||
|
rt.Using = append(rt.Using, entryPointName)
|
||||||
|
|
||||||
entryPointsRouters[entryPointName][rtName] = rt
|
entryPointsRouters[entryPointName][rtName] = rt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if entryPointsCount == 0 {
|
||||||
|
rt.AddError(fmt.Errorf("no valid entryPoint for this router"), true)
|
||||||
|
logger.Error("no valid entryPoint for this router")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return entryPointsRouters
|
return entryPointsRouters
|
||||||
}
|
}
|
||||||
|
|
||||||
// TCPRouterInfo holds information about a currently running TCP router
|
// TCPRouterInfo holds information about a currently running TCP router.
|
||||||
type TCPRouterInfo struct {
|
type TCPRouterInfo struct {
|
||||||
*dynamic.TCPRouter // dynamic configuration
|
*dynamic.TCPRouter // dynamic configuration
|
||||||
Err []string `json:"error,omitempty"` // initialization error
|
Err []string `json:"error,omitempty"` // initialization error
|
||||||
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
||||||
// If not in "enabled" state, the reason for it should be in the list of Err.
|
// If not in "enabled" state, the reason for it should be in the list of Err.
|
||||||
// It is the caller's responsibility to set the initial status.
|
// It is the caller's responsibility to set the initial status.
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
|
Using []string `json:"using,omitempty"` // Effective entry points used by that router.
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddError adds err to r.Err, if it does not already exist.
|
// AddError adds err to r.Err, if it does not already exist.
|
||||||
|
@ -66,7 +81,7 @@ func (r *TCPRouterInfo) AddError(err error, critical bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TCPServiceInfo holds information about a currently running TCP service
|
// TCPServiceInfo holds information about a currently running TCP service.
|
||||||
type TCPServiceInfo struct {
|
type TCPServiceInfo struct {
|
||||||
*dynamic.TCPService // dynamic configuration
|
*dynamic.TCPService // dynamic configuration
|
||||||
Err []string `json:"error,omitempty"` // initialization error
|
Err []string `json:"error,omitempty"` // initialization error
|
||||||
|
|
|
@ -104,6 +104,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||||
Rule: "HostSNI(`bar.foo`)",
|
Rule: "HostSNI(`bar.foo`)",
|
||||||
},
|
},
|
||||||
Status: "enabled",
|
Status: "enabled",
|
||||||
|
Using: []string{"web"},
|
||||||
},
|
},
|
||||||
"foobar": {
|
"foobar": {
|
||||||
TCPRouter: &dynamic.TCPRouter{
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
@ -111,7 +112,9 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||||
Service: "foobar-service@myprovider",
|
Service: "foobar-service@myprovider",
|
||||||
Rule: "HostSNI(`bar.foobar`)",
|
Rule: "HostSNI(`bar.foobar`)",
|
||||||
},
|
},
|
||||||
Status: "enabled",
|
Status: "warning",
|
||||||
|
Err: []string{`entryPoint "webs" doesn't exist`},
|
||||||
|
Using: []string{"web"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -168,6 +171,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||||
Rule: "HostSNI(`bar.foo`)",
|
Rule: "HostSNI(`bar.foo`)",
|
||||||
},
|
},
|
||||||
Status: "enabled",
|
Status: "enabled",
|
||||||
|
Using: []string{"web"},
|
||||||
},
|
},
|
||||||
"foobar": {
|
"foobar": {
|
||||||
TCPRouter: &dynamic.TCPRouter{
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
@ -176,6 +180,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||||
Rule: "HostSNI(`bar.foobar`)",
|
Rule: "HostSNI(`bar.foobar`)",
|
||||||
},
|
},
|
||||||
Status: "enabled",
|
Status: "enabled",
|
||||||
|
Using: []string{"web", "webs"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"webs": {
|
"webs": {
|
||||||
|
@ -187,6 +192,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||||
Rule: "HostSNI(`foo.bar`)",
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
},
|
},
|
||||||
Status: "enabled",
|
Status: "enabled",
|
||||||
|
Using: []string{"webs"},
|
||||||
},
|
},
|
||||||
"foobar": {
|
"foobar": {
|
||||||
TCPRouter: &dynamic.TCPRouter{
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
@ -195,6 +201,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||||
Rule: "HostSNI(`bar.foobar`)",
|
Rule: "HostSNI(`bar.foobar`)",
|
||||||
},
|
},
|
||||||
Status: "enabled",
|
Status: "enabled",
|
||||||
|
Using: []string{"web", "webs"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -144,7 +144,6 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
|
||||||
}
|
}
|
||||||
conf.Routers[serviceName].TLS = tlsConf
|
conf.Routers[serviceName].TLS = tlsConf
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue