feat(backends): Pool-Modell — Backend = Pool, N Server pro Backend
Migration 0016: backend_servers (id, backend_id, name, address, port, weight, backup, active) + backends.lb_algorithm. Daten-Migration kopiert bestehende backends.address/port als ersten Server, dann DROP COLUMN. HAProxy-Renderer: rendert pro Backend einen Block mit `balance <algo>` + N `server`-Zeilen (weight, backup-Flag, optional check inter 5s). LB-Algorithmen: roundrobin / leastconn / source. REST: /backends/:id/servers (GET/POST), /backend-servers/:id (PUT/DELETE). Re-rendert HAProxy nach jeder Server-Mutation. UI: address/port aus Backend-Form raus, lb_algorithm-Select rein. Server verwaltet ein expandable Sub-Panel pro Backend-Row (Tabelle + Add/Edit/ Delete-Modal). Domain-Attachment-Multi-Select bleibt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,21 @@ func renderView(t *testing.T, v View) string {
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func mkBackend(id int64, name string, hcp *string) models.Backend {
|
||||
return models.Backend{
|
||||
ID: id, Name: name, Scheme: "http",
|
||||
LBAlgorithm: "roundrobin", Active: true,
|
||||
HealthCheckPath: hcp,
|
||||
}
|
||||
}
|
||||
|
||||
func mkServer(backendID int64, name, addr string, port int) models.BackendServer {
|
||||
return models.BackendServer{
|
||||
BackendID: backendID, Name: name, Address: addr, Port: port,
|
||||
Weight: 100, Active: true,
|
||||
}
|
||||
}
|
||||
|
||||
func TestRender_BaselineHasFrontendsAndApiBackend(t *testing.T) {
|
||||
out := renderView(t, View{})
|
||||
for _, w := range []string{
|
||||
@@ -37,9 +52,13 @@ func TestRender_BaselineHasFrontendsAndApiBackend(t *testing.T) {
|
||||
|
||||
func TestRender_DomainRoutesEmitUseBackend(t *testing.T) {
|
||||
v := View{
|
||||
Backends: []models.Backend{
|
||||
{ID: 1, Name: "app", Address: "10.0.0.10", Port: 8080, Active: true},
|
||||
{ID: 2, Name: "api", Address: "10.0.0.20", Port: 9000, Active: true},
|
||||
Backends: []BackendView{
|
||||
{Backend: mkBackend(1, "app", nil), Servers: []models.BackendServer{
|
||||
mkServer(1, "app", "10.0.0.10", 8080),
|
||||
}},
|
||||
{Backend: mkBackend(2, "api", nil), Servers: []models.BackendServer{
|
||||
mkServer(2, "api", "10.0.0.20", 9000),
|
||||
}},
|
||||
},
|
||||
Domains: []DomainView{{
|
||||
Domain: models.Domain{ID: 1, Name: "example.com", Active: true},
|
||||
@@ -55,6 +74,7 @@ func TestRender_DomainRoutesEmitUseBackend(t *testing.T) {
|
||||
"server app 10.0.0.10:8080",
|
||||
"backend eg_backend_2",
|
||||
"server api 10.0.0.20:9000",
|
||||
"balance roundrobin",
|
||||
"use_backend eg_backend_1 if { hdr(host) -i example.com } { path_beg / }",
|
||||
"use_backend eg_backend_2 if { hdr(host) -i example.com } { path_beg /api }",
|
||||
} {
|
||||
@@ -67,12 +87,46 @@ func TestRender_DomainRoutesEmitUseBackend(t *testing.T) {
|
||||
func TestRender_HealthCheckPathAddsCheckInter(t *testing.T) {
|
||||
hcp := "/health"
|
||||
v := View{
|
||||
Backends: []models.Backend{
|
||||
{ID: 1, Name: "app", Address: "10.0.0.10", Port: 8080, Active: true, HealthCheckPath: &hcp},
|
||||
Backends: []BackendView{
|
||||
{Backend: mkBackend(1, "app", &hcp), Servers: []models.BackendServer{
|
||||
mkServer(1, "app", "10.0.0.10", 8080),
|
||||
}},
|
||||
},
|
||||
}
|
||||
out := renderView(t, v)
|
||||
if !strings.Contains(out, "server app 10.0.0.10:8080 check inter 5s") {
|
||||
t.Errorf("expected `check inter 5s` for backend with health_check_path:\n%s", out)
|
||||
}
|
||||
if !strings.Contains(out, "option httpchk") {
|
||||
t.Errorf("expected `option httpchk` when health_check_path set:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRender_MultiServerPool(t *testing.T) {
|
||||
v := View{
|
||||
Backends: []BackendView{
|
||||
{
|
||||
Backend: models.Backend{ID: 1, Name: "vmm", Scheme: "http", LBAlgorithm: "leastconn", Active: true},
|
||||
Servers: []models.BackendServer{
|
||||
{BackendID: 1, Name: "vmm-1", Address: "10.0.0.11", Port: 8080, Weight: 100, Active: true},
|
||||
{BackendID: 1, Name: "vmm-2", Address: "10.0.0.12", Port: 8080, Weight: 100, Active: true},
|
||||
{BackendID: 1, Name: "vmm-3", Address: "10.0.0.13", Port: 8080, Weight: 50, Backup: true, Active: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
out := renderView(t, v)
|
||||
for _, w := range []string{
|
||||
"backend eg_backend_1",
|
||||
"balance leastconn",
|
||||
"server vmm-1 10.0.0.11:8080",
|
||||
"server vmm-2 10.0.0.12:8080",
|
||||
"server vmm-3 10.0.0.13:8080",
|
||||
"weight 50",
|
||||
" backup",
|
||||
} {
|
||||
if !strings.Contains(out, w) {
|
||||
t.Errorf("missing %q in multi-server output:\n%s", w, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user