Files
edgeguard-native/internal/database/migrations/0016_backend_servers.sql
Debian 8aac24b566 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>
2026-05-11 20:55:47 +02:00

82 lines
3.1 KiB
SQL

-- +goose Up
-- +goose StatementBegin
-- v1.0.49: backends wird vom Single-Server-Endpoint zum Pool.
-- Bisher: backends.address/port → genau ein Upstream.
-- Jetzt: backends = Pool-Definition (LB-Algo, Healthcheck), die
-- konkreten Upstreams leben in backend_servers (1:N).
-- Damit kann eine Domain → ein Backend → N Server (HAProxy macht
-- den Loadbalance laut backends.lb_algorithm).
CREATE TABLE IF NOT EXISTS backend_servers (
id BIGSERIAL PRIMARY KEY,
backend_id BIGINT NOT NULL REFERENCES backends(id) ON DELETE CASCADE,
name TEXT NOT NULL,
address TEXT NOT NULL,
port INTEGER NOT NULL,
weight INTEGER NOT NULL DEFAULT 100,
backup BOOLEAN NOT NULL DEFAULT FALSE,
active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT backend_servers_name_unique UNIQUE (backend_id, name),
CONSTRAINT backend_servers_port_check CHECK (port > 0 AND port < 65536),
CONSTRAINT backend_servers_weight_check CHECK (weight >= 0 AND weight <= 256)
);
CREATE INDEX IF NOT EXISTS idx_backend_servers_backend
ON backend_servers (backend_id);
CREATE INDEX IF NOT EXISTS idx_backend_servers_active
ON backend_servers (backend_id, active) WHERE active;
-- LB-Algorithmus pro Backend. Default roundrobin entspricht haproxy-
-- default; source = sticky-per-Source-IP (für stateful Apps ohne
-- shared session store).
ALTER TABLE backends
ADD COLUMN IF NOT EXISTS lb_algorithm TEXT NOT NULL DEFAULT 'roundrobin';
ALTER TABLE backends
DROP CONSTRAINT IF EXISTS backends_lb_check;
ALTER TABLE backends
ADD CONSTRAINT backends_lb_check
CHECK (lb_algorithm IN ('roundrobin', 'leastconn', 'source'));
-- Daten-Migration: jede bisherige backends-Row produziert genau eine
-- backend_servers-Row mit demselben address/port. name = backends.name
-- damit der HAProxy-server-id stabil bleibt (haproxy stats / logs
-- referenzieren ihn). Idempotent — bei Re-Apply gibt's einen Skip
-- über das Unique-Constraint.
INSERT INTO backend_servers (backend_id, name, address, port, active)
SELECT id, name, address, port, active
FROM backends
WHERE address IS NOT NULL AND port IS NOT NULL
ON CONFLICT (backend_id, name) DO NOTHING;
-- Erst nach erfolgreichem Insert die alten Spalten droppen. Wenn die
-- Migration mittendrin abbricht, sind die Daten in beiden Tabellen
-- vorhanden — wir verlieren nichts.
ALTER TABLE backends DROP COLUMN IF EXISTS address;
ALTER TABLE backends DROP COLUMN IF EXISTS port;
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
ALTER TABLE backends ADD COLUMN IF NOT EXISTS address TEXT;
ALTER TABLE backends ADD COLUMN IF NOT EXISTS port INTEGER;
UPDATE backends b
SET address = bs.address,
port = bs.port
FROM (
SELECT DISTINCT ON (backend_id) backend_id, address, port
FROM backend_servers
ORDER BY backend_id, id ASC
) bs
WHERE b.id = bs.backend_id;
ALTER TABLE backends DROP CONSTRAINT IF EXISTS backends_lb_check;
ALTER TABLE backends DROP COLUMN IF EXISTS lb_algorithm;
DROP TABLE IF EXISTS backend_servers;
-- +goose StatementEnd