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:
@@ -1,4 +1,7 @@
|
||||
// Package backends implements CRUD against the `backends` table.
|
||||
// Ein Backend ist ein Pool — Name, Scheme, Healthcheck, LB-Algorithm.
|
||||
// Die konkreten Upstream-Server liegen in backend_servers (siehe
|
||||
// services/backendservers).
|
||||
package backends
|
||||
|
||||
import (
|
||||
@@ -20,7 +23,7 @@ type Repo struct {
|
||||
func New(pool *pgxpool.Pool) *Repo { return &Repo{Pool: pool} }
|
||||
|
||||
const baseSelect = `
|
||||
SELECT id, name, scheme, address, port, health_check_path, active,
|
||||
SELECT id, name, scheme, health_check_path, lb_algorithm, active,
|
||||
created_at, updated_at
|
||||
FROM backends
|
||||
`
|
||||
@@ -55,29 +58,34 @@ func (r *Repo) Get(ctx context.Context, id int64) (*models.Backend, error) {
|
||||
}
|
||||
|
||||
func (r *Repo) Create(ctx context.Context, b models.Backend) (*models.Backend, error) {
|
||||
if b.LBAlgorithm == "" {
|
||||
b.LBAlgorithm = "roundrobin"
|
||||
}
|
||||
row := r.Pool.QueryRow(ctx, `
|
||||
INSERT INTO backends (name, scheme, address, port, health_check_path, active)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
RETURNING id, name, scheme, address, port, health_check_path, active,
|
||||
INSERT INTO backends (name, scheme, health_check_path, lb_algorithm, active)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, name, scheme, health_check_path, lb_algorithm, active,
|
||||
created_at, updated_at`,
|
||||
b.Name, b.Scheme, b.Address, b.Port, b.HealthCheckPath, b.Active)
|
||||
b.Name, b.Scheme, b.HealthCheckPath, b.LBAlgorithm, b.Active)
|
||||
return scanBackend(row)
|
||||
}
|
||||
|
||||
func (r *Repo) Update(ctx context.Context, id int64, b models.Backend) (*models.Backend, error) {
|
||||
if b.LBAlgorithm == "" {
|
||||
b.LBAlgorithm = "roundrobin"
|
||||
}
|
||||
row := r.Pool.QueryRow(ctx, `
|
||||
UPDATE backends SET
|
||||
name = $1,
|
||||
scheme = $2,
|
||||
address = $3,
|
||||
port = $4,
|
||||
health_check_path = $5,
|
||||
active = $6,
|
||||
health_check_path = $3,
|
||||
lb_algorithm = $4,
|
||||
active = $5,
|
||||
updated_at = NOW()
|
||||
WHERE id = $7
|
||||
RETURNING id, name, scheme, address, port, health_check_path, active,
|
||||
WHERE id = $6
|
||||
RETURNING id, name, scheme, health_check_path, lb_algorithm, active,
|
||||
created_at, updated_at`,
|
||||
b.Name, b.Scheme, b.Address, b.Port, b.HealthCheckPath, b.Active, id)
|
||||
b.Name, b.Scheme, b.HealthCheckPath, b.LBAlgorithm, b.Active, id)
|
||||
out, err := scanBackend(row)
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
@@ -102,8 +110,8 @@ func (r *Repo) Delete(ctx context.Context, id int64) error {
|
||||
func scanBackend(row interface{ Scan(...any) error }) (*models.Backend, error) {
|
||||
var b models.Backend
|
||||
if err := row.Scan(
|
||||
&b.ID, &b.Name, &b.Scheme, &b.Address, &b.Port,
|
||||
&b.HealthCheckPath, &b.Active,
|
||||
&b.ID, &b.Name, &b.Scheme,
|
||||
&b.HealthCheckPath, &b.LBAlgorithm, &b.Active,
|
||||
&b.CreatedAt, &b.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user