446 lines
No EOL
13 KiB
Go
446 lines
No EOL
13 KiB
Go
package traefik
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/traefik/traefik-gui/backend/internal/models"
|
|
)
|
|
|
|
type MockClient struct{}
|
|
|
|
func NewMockClient() *MockClient {
|
|
return &MockClient{}
|
|
}
|
|
|
|
func (m *MockClient) GetRouters(ctx context.Context) ([]models.Router, error) {
|
|
return []models.Router{
|
|
{
|
|
Name: "api@internal",
|
|
Provider: "internal",
|
|
Rule: "PathPrefix(`/api`) || PathPrefix(`/dashboard`)",
|
|
EntryPoints: []string{"traefik"},
|
|
Service: "api@internal",
|
|
Middlewares: []string{},
|
|
Priority: 0,
|
|
TLS: nil,
|
|
Status: "enabled",
|
|
Using: []string{},
|
|
},
|
|
{
|
|
Name: "dashboard@internal",
|
|
Provider: "internal",
|
|
Rule: "PathPrefix(`/dashboard`)",
|
|
EntryPoints: []string{"traefik"},
|
|
Service: "dashboard@internal",
|
|
Middlewares: []string{},
|
|
Priority: 0,
|
|
TLS: nil,
|
|
Status: "enabled",
|
|
Using: []string{},
|
|
},
|
|
{
|
|
Name: "web-router@docker",
|
|
Provider: "docker",
|
|
Rule: "Host(`web.example.com`)",
|
|
EntryPoints: []string{"web", "websecure"},
|
|
Service: "web-service@docker",
|
|
Middlewares: []string{"secure-headers@docker", "redirect-https@docker"},
|
|
Priority: 10,
|
|
TLS: &models.RouterTLSConfig{
|
|
Options: "default@default",
|
|
CertResolver: "letsencrypt",
|
|
Domains: []models.Domain{
|
|
{Main: "web.example.com", SANs: []string{"www.web.example.com"}},
|
|
},
|
|
},
|
|
Status: "enabled",
|
|
Using: []string{"secure-headers@docker", "redirect-https@docker"},
|
|
},
|
|
{
|
|
Name: "api-router@file",
|
|
Provider: "file",
|
|
Rule: "Host(`api.example.com`) && PathPrefix(`/v1`)",
|
|
EntryPoints: []string{"websecure"},
|
|
Service: "api-service@file",
|
|
Middlewares: []string{"rate-limit@file", "cors@file"},
|
|
Priority: 20,
|
|
TLS: &models.RouterTLSConfig{
|
|
Options: "modern@default",
|
|
CertResolver: "letsencrypt",
|
|
},
|
|
Status: "enabled",
|
|
Using: []string{"rate-limit@file", "cors@file"},
|
|
},
|
|
{
|
|
Name: "disabled-router@file",
|
|
Provider: "file",
|
|
Rule: "Host(`old.example.com`)",
|
|
EntryPoints: []string{"web"},
|
|
Service: "old-service@file",
|
|
Middlewares: []string{},
|
|
Priority: 5,
|
|
TLS: nil,
|
|
Status: "disabled",
|
|
Using: []string{},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (m *MockClient) GetServices(ctx context.Context) ([]models.Service, error) {
|
|
return []models.Service{
|
|
{
|
|
Name: "api@internal",
|
|
Provider: "internal",
|
|
Type: "loadbalancer",
|
|
LoadBalancer: &models.LoadBalancer{
|
|
Servers: []models.Server{
|
|
{URL: "http://127.0.0.1:8080", Weight: ptr(1)},
|
|
},
|
|
Strategy: "wrr",
|
|
},
|
|
ServerStatus: map[string]string{"http://127.0.0.1:8080": "UP"},
|
|
Status: "enabled",
|
|
},
|
|
{
|
|
Name: "dashboard@internal",
|
|
Provider: "internal",
|
|
Type: "loadbalancer",
|
|
LoadBalancer: &models.LoadBalancer{
|
|
Servers: []models.Server{
|
|
{URL: "http://127.0.0.1:8080", Weight: ptr(1)},
|
|
},
|
|
Strategy: "wrr",
|
|
},
|
|
ServerStatus: map[string]string{"http://127.0.0.1:8080": "UP"},
|
|
Status: "enabled",
|
|
},
|
|
{
|
|
Name: "web-service@docker",
|
|
Provider: "docker",
|
|
Type: "loadbalancer",
|
|
LoadBalancer: &models.LoadBalancer{
|
|
Servers: []models.Server{
|
|
{URL: "http://172.17.0.2:80", Weight: ptr(1)},
|
|
{URL: "http://172.17.0.3:80", Weight: ptr(1)},
|
|
},
|
|
Strategy: "wrr",
|
|
PassHostHeader: ptr(true),
|
|
HealthCheck: &models.HealthCheck{
|
|
Scheme: "http",
|
|
Path: "/health",
|
|
Method: "GET",
|
|
Status: 200,
|
|
Interval: "30s",
|
|
Timeout: "5s",
|
|
},
|
|
},
|
|
ServerStatus: map[string]string{
|
|
"http://172.17.0.2:80": "UP",
|
|
"http://172.17.0.3:80": "UP",
|
|
},
|
|
Status: "enabled",
|
|
},
|
|
{
|
|
Name: "api-service@file",
|
|
Provider: "file",
|
|
Type: "loadbalancer",
|
|
LoadBalancer: &models.LoadBalancer{
|
|
Servers: []models.Server{
|
|
{URL: "http://10.0.0.10:8080", Weight: ptr(3)},
|
|
{URL: "http://10.0.0.11:8080", Weight: ptr(1)},
|
|
},
|
|
Strategy: "wrr",
|
|
PassHostHeader: ptr(true),
|
|
HealthCheck: &models.HealthCheck{
|
|
Scheme: "http",
|
|
Path: "/health",
|
|
Method: "GET",
|
|
Status: 200,
|
|
Interval: "30s",
|
|
Timeout: "5s",
|
|
},
|
|
},
|
|
ServerStatus: map[string]string{
|
|
"http://10.0.0.10:8080": "UP",
|
|
"http://10.0.0.11:8080": "UP",
|
|
},
|
|
Status: "enabled",
|
|
},
|
|
{
|
|
Name: "old-service@file",
|
|
Provider: "file",
|
|
Type: "loadbalancer",
|
|
LoadBalancer: &models.LoadBalancer{
|
|
Servers: []models.Server{
|
|
{URL: "http://192.168.1.100:80", Weight: ptr(1)},
|
|
},
|
|
Strategy: "wrr",
|
|
},
|
|
ServerStatus: map[string]string{"http://192.168.1.100:80": "DOWN"},
|
|
Status: "warning",
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (m *MockClient) GetMiddlewares(ctx context.Context) ([]models.Middleware, error) {
|
|
return []models.Middleware{
|
|
{
|
|
Name: "secure-headers@docker",
|
|
Provider: "docker",
|
|
Type: "headers",
|
|
Spec: map[string]interface{}{
|
|
"customResponseHeaders": map[string]string{
|
|
"X-Content-Type-Options": "nosniff",
|
|
"X-Frame-Options": "DENY",
|
|
},
|
|
},
|
|
Status: "enabled",
|
|
},
|
|
{
|
|
Name: "redirect-https@docker",
|
|
Provider: "docker",
|
|
Type: "redirectscheme",
|
|
Spec: map[string]interface{}{
|
|
"scheme": "https",
|
|
"permanent": true,
|
|
},
|
|
Status: "enabled",
|
|
},
|
|
{
|
|
Name: "rate-limit@file",
|
|
Provider: "file",
|
|
Type: "ratelimit",
|
|
Spec: map[string]interface{}{
|
|
"average": 100,
|
|
"burst": 50,
|
|
},
|
|
Status: "enabled",
|
|
},
|
|
{
|
|
Name: "cors@file",
|
|
Provider: "file",
|
|
Type: "headers",
|
|
Spec: map[string]interface{}{
|
|
"accessControlAllowMethods": []string{"GET", "POST", "PUT", "DELETE"},
|
|
"accessControlAllowOriginList": []string{"https://app.example.com"},
|
|
"accessControlAllowHeaders": []string{"Authorization", "Content-Type"},
|
|
},
|
|
Status: "enabled",
|
|
},
|
|
{
|
|
Name: "strip-prefix@file",
|
|
Provider: "file",
|
|
Type: "stripprefix",
|
|
Spec: map[string]interface{}{
|
|
"prefixes": []string{"/v1"},
|
|
},
|
|
Status: "enabled",
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (m *MockClient) GetCertificates(ctx context.Context) ([]models.Certificate, error) {
|
|
now := time.Now()
|
|
return []models.Certificate{
|
|
{
|
|
Name: "letsencrypt-web-example-com",
|
|
CommonName: "web.example.com",
|
|
SANs: []string{"web.example.com", "www.web.example.com"},
|
|
IssuerOrg: "Let's Encrypt",
|
|
IssuerCN: "R3",
|
|
NotBefore: now.AddDate(0, -2, 0),
|
|
NotAfter: now.AddDate(0, 1, 0),
|
|
Status: "valid",
|
|
Provider: "letsencrypt",
|
|
},
|
|
{
|
|
Name: "letsencrypt-api-example-com",
|
|
CommonName: "api.example.com",
|
|
SANs: []string{"api.example.com"},
|
|
IssuerOrg: "Let's Encrypt",
|
|
IssuerCN: "R3",
|
|
NotBefore: now.AddDate(0, -1, -15),
|
|
NotAfter: now.AddDate(0, 2, -15),
|
|
Status: "valid",
|
|
Provider: "letsencrypt",
|
|
},
|
|
{
|
|
Name: "self-signed-local",
|
|
CommonName: "local.example.com",
|
|
SANs: []string{"local.example.com", "*.local.example.com"},
|
|
IssuerOrg: "Local CA",
|
|
IssuerCN: "Local Root CA",
|
|
NotBefore: now.AddDate(-1, 0, 0),
|
|
NotAfter: now.AddDate(1, 0, 0),
|
|
Status: "valid",
|
|
Provider: "file",
|
|
},
|
|
{
|
|
Name: "expired-cert",
|
|
CommonName: "old.example.com",
|
|
SANs: []string{"old.example.com"},
|
|
IssuerOrg: "Let's Encrypt",
|
|
IssuerCN: "R3",
|
|
NotBefore: now.AddDate(0, -4, 0),
|
|
NotAfter: now.AddDate(0, -1, 0),
|
|
Status: "expired",
|
|
Provider: "letsencrypt",
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (m *MockClient) GetEntryPoints(ctx context.Context) ([]models.EntryPoint, error) {
|
|
return []models.EntryPoint{
|
|
{
|
|
Name: "web",
|
|
Address: ":80",
|
|
HTTP: &models.EntryPointHTTP{
|
|
Middlewares: []string{"redirect-https@docker"},
|
|
RedirectToHTTPS: true,
|
|
},
|
|
},
|
|
{
|
|
Name: "websecure",
|
|
Address: ":443",
|
|
HTTP: &models.EntryPointHTTP{
|
|
TLS: &models.EntryPointTLS{
|
|
CertResolver: "letsencrypt",
|
|
Options: "default@default",
|
|
},
|
|
Middlewares: []string{"secure-headers@docker"},
|
|
},
|
|
},
|
|
{
|
|
Name: "traefik",
|
|
Address: ":8080",
|
|
HTTP: &models.EntryPointHTTP{
|
|
Middlewares: []string{},
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (m *MockClient) GetOverview(ctx context.Context) (*models.Overview, error) {
|
|
return &models.Overview{
|
|
HTTP: struct {
|
|
Routers models.Section `json:"routers"`
|
|
Services models.Section `json:"services"`
|
|
Middlewares models.Section `json:"middlewares"`
|
|
}{
|
|
Routers: models.Section{Total: 4, Warnings: 0, Errors: 1},
|
|
Services: models.Section{Total: 5, Warnings: 1, Errors: 0},
|
|
Middlewares: models.Section{Total: 5, Warnings: 0, Errors: 0},
|
|
},
|
|
TCP: struct {
|
|
Routers models.Section `json:"routers"`
|
|
Services models.Section `json:"services"`
|
|
Middlewares models.Section `json:"middlewares"`
|
|
}{
|
|
Routers: models.Section{Total: 0, Warnings: 0, Errors: 0},
|
|
Services: models.Section{Total: 0, Warnings: 0, Errors: 0},
|
|
Middlewares: models.Section{Total: 0, Warnings: 0, Errors: 0},
|
|
},
|
|
UDP: struct {
|
|
Routers models.Section `json:"routers"`
|
|
Services models.Section `json:"services"`
|
|
}{
|
|
Routers: models.Section{Total: 0, Warnings: 0, Errors: 0},
|
|
Services: models.Section{Total: 0, Warnings: 0, Errors: 0},
|
|
},
|
|
Certificates: &models.Section{Total: 4, Warnings: 1, Errors: 1},
|
|
Providers: []string{"docker", "file", "internal"},
|
|
}, nil
|
|
}
|
|
|
|
func ptr[T any](v T) *T {
|
|
return &v
|
|
}
|
|
|
|
// MockAPIClient implements the new TraefikAPI interface with v3.7 types
|
|
type MockAPIClient struct{}
|
|
|
|
func NewMockAPIClient() *MockAPIClient { return &MockAPIClient{} }
|
|
|
|
func (m *MockAPIClient) GetHealthz(ctx context.Context) (*HealthResponse, error) {
|
|
return &HealthResponse{Status: "OK", Version: "3.7.0"}, nil
|
|
}
|
|
|
|
func (m *MockAPIClient) GetOverview(ctx context.Context) (*Overview, error) {
|
|
return &Overview{
|
|
HTTP: struct {
|
|
Routers Section `json:"routers"`
|
|
Services Section `json:"services"`
|
|
Middlewares Section `json:"middlewares"`
|
|
}{
|
|
Routers: Section{Total: 4, Warnings: 0, Errors: 1},
|
|
Services: Section{Total: 5, Warnings: 1, Errors: 0},
|
|
Middlewares: Section{Total: 5, Warnings: 0, Errors: 0},
|
|
},
|
|
TCP: struct {
|
|
Routers Section `json:"routers"`
|
|
Services Section `json:"services"`
|
|
Middlewares Section `json:"middlewares"`
|
|
}{
|
|
Routers: Section{Total: 0, Warnings: 0, Errors: 0},
|
|
Services: Section{Total: 0, Warnings: 0, Errors: 0},
|
|
Middlewares: Section{Total: 0, Warnings: 0, Errors: 0},
|
|
},
|
|
UDP: struct {
|
|
Routers Section `json:"routers"`
|
|
Services Section `json:"services"`
|
|
}{
|
|
Routers: Section{Total: 0, Warnings: 0, Errors: 0},
|
|
Services: Section{Total: 0, Warnings: 0, Errors: 0},
|
|
},
|
|
Providers: []string{"docker", "file", "internal"},
|
|
TotalRouters: 4,
|
|
TotalServices: 5,
|
|
TotalMiddlewares: 5,
|
|
TraefikVersion: "3.7.0",
|
|
TraefikCodename: "lascaux",
|
|
}, nil
|
|
}
|
|
|
|
func (m *MockAPIClient) GetEntrypoints(ctx context.Context) ([]Entrypoint, error) {
|
|
return []Entrypoint{
|
|
{Name: "web", Address: ":80"},
|
|
{Name: "websecure", Address: ":443"},
|
|
{Name: "traefik", Address: ":8080"},
|
|
}, nil
|
|
}
|
|
|
|
func (m *MockAPIClient) GetRouters(ctx context.Context) ([]Router, error) {
|
|
return []Router{
|
|
{Name: "api@internal", Provider: "internal", Rule: "PathPrefix(`/api`)", EntryPoints: []string{"traefik"}, Service: "api@internal", Status: "enabled"},
|
|
{Name: "web@docker", Provider: "docker", Rule: "Host(`web.example.com`)", EntryPoints: []string{"web"}, Service: "web@docker", Status: "enabled"},
|
|
}, nil
|
|
}
|
|
|
|
func (m *MockAPIClient) GetServices(ctx context.Context) ([]Service, error) {
|
|
return []Service{
|
|
{Name: "web@docker", Provider: "docker", Type: "loadbalancer", Status: "enabled", Middlewares: []string{"auth@docker"}},
|
|
{Name: "api@internal", Provider: "internal", Type: "loadbalancer", Status: "enabled"},
|
|
}, nil
|
|
}
|
|
|
|
func (m *MockAPIClient) GetMiddlewares(ctx context.Context) ([]Middleware, error) {
|
|
return []Middleware{
|
|
{Name: "auth@docker", Provider: "docker", Type: "forwardAuth", Status: "enabled"},
|
|
}, nil
|
|
}
|
|
|
|
func (m *MockAPIClient) GetProviders(ctx context.Context) ([]Provider, error) {
|
|
return []Provider{{Name: "docker"}, {Name: "file"}, {Name: "internal"}}, nil
|
|
}
|
|
|
|
func (m *MockAPIClient) GetCertificates(ctx context.Context) ([]Certificate, error) {
|
|
now := time.Now()
|
|
return []Certificate{
|
|
{Store: "default", Names: []string{"example.com"}, SANs: []string{"example.com"}, Issuer: "CN=Test CA", NotAfter: now.Add(24 * time.Hour), NotBefore: now.Add(-24 * time.Hour), SerialNumber: "1"},
|
|
{Store: "default", Names: []string{"expired.com"}, SANs: []string{"expired.com"}, Issuer: "CN=Test CA", NotAfter: now.Add(-24 * time.Hour), NotBefore: now.Add(-48 * time.Hour), SerialNumber: "2"},
|
|
}, nil
|
|
}
|
|
|
|
var _ TraefikAPI = (*MockAPIClient)(nil)
|
|
var _ TraefikAPI = (*Client)(nil) |