mirror of
https://github.com/hhftechnology/middleware-manager.git
synced 2026-04-28 03:29:42 +00:00
Merge pull request #104 from hhftechnology/dev
Fix: serversTransports from Pangolin config not passed through to Tra…
This commit is contained in:
commit
7eb1378d82
4 changed files with 132 additions and 44 deletions
|
|
@ -6,36 +6,36 @@ import (
|
|||
|
||||
// Resource represents a Pangolin resource
|
||||
type Resource struct {
|
||||
ID string `json:"id"` // Internal UUID (stable, never changes)
|
||||
PangolinRouterID string `json:"pangolin_router_id"` // Pangolin's router ID (can change)
|
||||
Host string `json:"host"`
|
||||
ServiceID string `json:"service_id"`
|
||||
OrgID string `json:"org_id"`
|
||||
SiteID string `json:"site_id"`
|
||||
Status string `json:"status"`
|
||||
ID string `json:"id"` // Internal UUID (stable, never changes)
|
||||
PangolinRouterID string `json:"pangolin_router_id"` // Pangolin's router ID (can change)
|
||||
Host string `json:"host"`
|
||||
ServiceID string `json:"service_id"`
|
||||
OrgID string `json:"org_id"`
|
||||
SiteID string `json:"site_id"`
|
||||
Status string `json:"status"`
|
||||
|
||||
// HTTP router configuration
|
||||
Entrypoints string `json:"entrypoints"`
|
||||
|
||||
Entrypoints string `json:"entrypoints"`
|
||||
|
||||
// TLS certificate configuration
|
||||
TLSDomains string `json:"tls_domains"`
|
||||
|
||||
TLSDomains string `json:"tls_domains"`
|
||||
|
||||
// TCP SNI routing configuration
|
||||
TCPEnabled bool `json:"tcp_enabled"`
|
||||
TCPEntrypoints string `json:"tcp_entrypoints"`
|
||||
TCPSNIRule string `json:"tcp_sni_rule"`
|
||||
|
||||
TCPEnabled bool `json:"tcp_enabled"`
|
||||
TCPEntrypoints string `json:"tcp_entrypoints"`
|
||||
TCPSNIRule string `json:"tcp_sni_rule"`
|
||||
|
||||
// Custom headers configuration
|
||||
CustomHeaders string `json:"custom_headers"`
|
||||
|
||||
CustomHeaders string `json:"custom_headers"`
|
||||
|
||||
// Router priority configuration
|
||||
RouterPriority int `json:"router_priority"`
|
||||
RouterPriority int `json:"router_priority"`
|
||||
|
||||
// Source type for tracking data origin
|
||||
SourceType string `json:"source_type"`
|
||||
SourceType string `json:"source_type"`
|
||||
|
||||
// mTLS configuration
|
||||
MTLSEnabled bool `json:"mtls_enabled"`
|
||||
MTLSEnabled bool `json:"mtls_enabled"`
|
||||
|
||||
// TLS Hardening configuration (standalone, disabled when mTLS is active)
|
||||
TLSHardeningEnabled bool `json:"tls_hardening_enabled"`
|
||||
|
|
@ -43,8 +43,8 @@ type Resource struct {
|
|||
// Secure Headers configuration
|
||||
SecureHeadersEnabled bool `json:"secure_headers_enabled"`
|
||||
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// PangolinResource represents the format of a resource from Pangolin API
|
||||
|
|
@ -58,9 +58,10 @@ type PangolinResource struct {
|
|||
// PangolinTraefikConfig represents the Traefik configuration from Pangolin API
|
||||
type PangolinTraefikConfig struct {
|
||||
HTTP struct {
|
||||
Routers map[string]PangolinRouter `json:"routers"`
|
||||
Services map[string]PangolinService `json:"services"`
|
||||
Middlewares map[string]map[string]interface{} `json:"middlewares"`
|
||||
Routers map[string]PangolinRouter `json:"routers"`
|
||||
Services map[string]PangolinService `json:"services"`
|
||||
Middlewares map[string]map[string]interface{} `json:"middlewares"`
|
||||
ServersTransports map[string]interface{} `json:"serversTransports"`
|
||||
} `json:"http"`
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +97,7 @@ type PangolinServiceConfig struct {
|
|||
type TraefikService struct {
|
||||
Name string `json:"name"`
|
||||
Provider string `json:"provider"`
|
||||
|
||||
|
||||
// Service types - only one will be populated based on service type
|
||||
LoadBalancer *struct {
|
||||
Servers []struct {
|
||||
|
|
@ -108,7 +109,7 @@ type TraefikService struct {
|
|||
Sticky interface{} `json:"sticky,omitempty"`
|
||||
HealthCheck interface{} `json:"healthCheck,omitempty"`
|
||||
} `json:"loadBalancer,omitempty"`
|
||||
|
||||
|
||||
Weighted *struct {
|
||||
Services []struct {
|
||||
Name string `json:"name"`
|
||||
|
|
@ -117,10 +118,10 @@ type TraefikService struct {
|
|||
Sticky interface{} `json:"sticky,omitempty"`
|
||||
HealthCheck interface{} `json:"healthCheck,omitempty"`
|
||||
} `json:"weighted,omitempty"`
|
||||
|
||||
|
||||
Mirroring *struct {
|
||||
Service string `json:"service"`
|
||||
Mirrors []struct {
|
||||
Service string `json:"service"`
|
||||
Mirrors []struct {
|
||||
Name string `json:"name"`
|
||||
Percent int `json:"percent"`
|
||||
} `json:"mirrors,omitempty"`
|
||||
|
|
@ -128,10 +129,10 @@ type TraefikService struct {
|
|||
MirrorBody *bool `json:"mirrorBody,omitempty"`
|
||||
HealthCheck interface{} `json:"healthCheck,omitempty"`
|
||||
} `json:"mirroring,omitempty"`
|
||||
|
||||
|
||||
Failover *struct {
|
||||
Service string `json:"service"`
|
||||
Fallback string `json:"fallback"`
|
||||
HealthCheck interface{} `json:"healthCheck,omitempty"`
|
||||
} `json:"failover,omitempty"`
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,10 @@ type ProxiedTraefikConfig struct {
|
|||
|
||||
// HTTPConfig represents HTTP configuration section
|
||||
type HTTPConfig struct {
|
||||
Middlewares map[string]interface{} `json:"middlewares,omitempty"`
|
||||
Routers map[string]interface{} `json:"routers,omitempty"`
|
||||
Services map[string]interface{} `json:"services,omitempty"`
|
||||
Middlewares map[string]interface{} `json:"middlewares,omitempty"`
|
||||
Routers map[string]interface{} `json:"routers,omitempty"`
|
||||
Services map[string]interface{} `json:"services,omitempty"`
|
||||
ServersTransports map[string]interface{} `json:"serversTransports,omitempty"`
|
||||
}
|
||||
|
||||
// TCPConfig represents TCP configuration section
|
||||
|
|
@ -53,12 +54,12 @@ type TLSConfig struct {
|
|||
// OrderedRouter represents a Traefik HTTP router with fields in Pangolin's order.
|
||||
// The JSON field order matches Pangolin API output for consistency.
|
||||
type OrderedRouter struct {
|
||||
EntryPoints []string `json:"entryPoints,omitempty"`
|
||||
Middlewares []string `json:"middlewares,omitempty"`
|
||||
Service string `json:"service,omitempty"`
|
||||
Rule string `json:"rule,omitempty"`
|
||||
Priority int `json:"priority,omitempty"`
|
||||
TLS *OrderedTLSConfig `json:"tls,omitempty"`
|
||||
EntryPoints []string `json:"entryPoints,omitempty"`
|
||||
Middlewares []string `json:"middlewares,omitempty"`
|
||||
Service string `json:"service,omitempty"`
|
||||
Rule string `json:"rule,omitempty"`
|
||||
Priority int `json:"priority,omitempty"`
|
||||
TLS *OrderedTLSConfig `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// OrderedTLSConfig represents TLS config for a router with Pangolin's field order.
|
||||
|
|
@ -146,7 +147,7 @@ func NewConfigProxy(db *database.DB, configManager *ConfigManager, pangolinURL s
|
|||
db: db,
|
||||
configManager: configManager,
|
||||
pangolinURL: pangolinURL,
|
||||
httpClient: HTTPClientWithTimeout(10 * time.Second),
|
||||
httpClient: HTTPClientWithTimeout(10 * time.Second),
|
||||
cacheDuration: 5 * time.Second, // Match typical Traefik poll interval
|
||||
}
|
||||
}
|
||||
|
|
@ -266,6 +267,9 @@ func (cp *ConfigProxy) initializeConfigMaps(config *ProxiedTraefikConfig) {
|
|||
if config.HTTP.Services == nil {
|
||||
config.HTTP.Services = make(map[string]interface{})
|
||||
}
|
||||
if config.HTTP.ServersTransports == nil {
|
||||
config.HTTP.ServersTransports = make(map[string]interface{})
|
||||
}
|
||||
|
||||
if config.TCP == nil {
|
||||
config.TCP = &TCPConfig{}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,89 @@ func TestConfigProxyCachesAndInvalidates(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestConfigProxyPreservesServersTransports(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
cm := newTestConfigManager(t)
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"http": map[string]interface{}{
|
||||
"middlewares": map[string]interface{}{},
|
||||
"routers": map[string]interface{}{},
|
||||
"services": map[string]interface{}{
|
||||
"14-example-service": map[string]interface{}{
|
||||
"loadBalancer": map[string]interface{}{
|
||||
"servers": []map[string]interface{}{
|
||||
{"url": "https://10.0.0.1:12345"},
|
||||
},
|
||||
"serversTransport": "14-transport",
|
||||
},
|
||||
},
|
||||
},
|
||||
"serversTransports": map[string]interface{}{
|
||||
"14-transport": map[string]interface{}{
|
||||
"serverName": "example.com",
|
||||
"insecureSkipVerify": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
cp := NewConfigProxy(db, cm, server.URL)
|
||||
cp.httpClient = server.Client()
|
||||
|
||||
config, err := cp.GetMergedConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("GetMergedConfig() error = %v", err)
|
||||
}
|
||||
|
||||
if config.HTTP == nil {
|
||||
t.Fatal("config.HTTP is nil")
|
||||
}
|
||||
|
||||
transportRaw, exists := config.HTTP.ServersTransports["14-transport"]
|
||||
if !exists {
|
||||
t.Fatalf("serversTransport %q was not preserved", "14-transport")
|
||||
}
|
||||
|
||||
transport, ok := transportRaw.(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("serversTransport has type %T, want map[string]interface{}", transportRaw)
|
||||
}
|
||||
|
||||
if got, ok := transport["serverName"].(string); !ok || got != "example.com" {
|
||||
t.Fatalf("serverName = %#v, want %q", transport["serverName"], "example.com")
|
||||
}
|
||||
if got, ok := transport["insecureSkipVerify"].(bool); !ok || !got {
|
||||
t.Fatalf("insecureSkipVerify = %#v, want true", transport["insecureSkipVerify"])
|
||||
}
|
||||
|
||||
serviceRaw, exists := config.HTTP.Services["14-example-service"]
|
||||
if !exists {
|
||||
t.Fatalf("service %q not found", "14-example-service")
|
||||
}
|
||||
service, ok := serviceRaw.(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("service has type %T, want map[string]interface{}", serviceRaw)
|
||||
}
|
||||
|
||||
loadBalancerRaw, exists := service["loadBalancer"]
|
||||
if !exists {
|
||||
t.Fatalf("service %q missing loadBalancer", "14-example-service")
|
||||
}
|
||||
loadBalancer, ok := loadBalancerRaw.(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("loadBalancer has type %T, want map[string]interface{}", loadBalancerRaw)
|
||||
}
|
||||
|
||||
if got, ok := loadBalancer["serversTransport"].(string); !ok || got != "14-transport" {
|
||||
t.Fatalf("loadBalancer.serversTransport = %#v, want %q", loadBalancer["serversTransport"], "14-transport")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigGeneratorWritesConfigFile(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
cm := newTestConfigManager(t)
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ export function DataSourceSettings() {
|
|||
Data Source Settings
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
Configure your data source connections for Pangolin or Traefik API
|
||||
Configure your data source connections for Pangolin or Traefik API --Traefik api will not function on pangolin stack/api,dont switch
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ export function DataSourceSettings() {
|
|||
<Input
|
||||
value={editUrl}
|
||||
onChange={(e) => setEditUrl(e.target.value)}
|
||||
placeholder="http://localhost:8080"
|
||||
placeholder="http://gerbil:8080"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue