From 1b13df40321e3383099ca1d93bc8e570d8e67e53 Mon Sep 17 00:00:00 2001 From: noroot Date: Fri, 11 Sep 2026 12:25:40 +0200 Subject: [PATCH] =?UTF-8?q?fix(cluster):=20pg=5Frole=20fehlte=20im=20SELEC?= =?UTF-8?q?T=20=E2=80=94=20Feld=20kam=20nie=20beim=20Client=20an?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit baseSelect in cluster/store.go selektierte pg_role nicht. HANode.PGRole war dadurch ueberall ein leerer String, wo Store.List/Get benutzt wird: /cluster/nodes, /cluster/status und damit auch die pg_role-Spalte der Cluster-Seite. Aufgefallen ist es erst, als die Dashboard-Cluster-Karte in v1.3.33 auf pg_role umgestellt wurde und daraufhin bei beiden Knoten "—" zeigte — der Fehler lag aber schon vorher im Store. pg_role ist jetzt in baseSelect, im RETURNING von UpsertSelf und in scanNode ergaenzt; die drei muessen spaltenweise zueinander passen. UpsertSelf SCHREIBT pg_role weiterhin bewusst nicht (ON CONFLICT laesst die Spalte unangetastet, damit eine Self-Registrierung den per promote gesetzten Wert nicht ueberbuegelt) — liest sie aber im RETURNING mit, sonst stimmt die Scan-Reihenfolge nicht. Co-Authored-By: Claude Opus 5 --- internal/cluster/store.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/internal/cluster/store.go b/internal/cluster/store.go index f288691..1555636 100644 --- a/internal/cluster/store.go +++ b/internal/cluster/store.go @@ -25,8 +25,15 @@ type Store struct { func NewStore(pool *pgxpool.Pool) *Store { return &Store{Pool: pool} } +// baseSelect MUSS spaltenweise zu scanNode passen. pg_role fehlte hier +// urspruenglich (Befund 2026-09-11): HANode.PGRole kam dadurch ueberall als +// leerer String an, wo Store.List/Get benutzt wird — /cluster/nodes, +// /cluster/status und damit auch die pg_role-Spalte der Cluster-Seite. +// UpsertSelf schreibt pg_role bewusst NICHT (ON CONFLICT laesst die Spalte +// unangetastet), liest sie aber im RETURNING mit — sonst passt die +// Scan-Reihenfolge nicht. const baseSelect = ` -SELECT id, name, fqdn, api_url, public_ip, internal_ip, mgmt_ip, role, +SELECT id, name, fqdn, api_url, public_ip, internal_ip, mgmt_ip, role, pg_role, version, config_hash, status, last_seen, joined_at, created_at, updated_at FROM ha_nodes @@ -90,7 +97,7 @@ ON CONFLICT (id) DO UPDATE SET last_seen = EXCLUDED.last_seen, updated_at = NOW() RETURNING id, name, fqdn, api_url, public_ip, internal_ip, mgmt_ip, - role, version, config_hash, status, + role, pg_role, version, config_hash, status, last_seen, joined_at, created_at, updated_at`, n.ID, n.Name, n.FQDN, n.APIURL, n.PublicIP, n.InternalIP, n.MgmtIP, @@ -181,7 +188,7 @@ func scanNode(row interface{ Scan(...any) error }) (*models.HANode, error) { if err := row.Scan( &n.ID, &n.Name, &n.FQDN, &n.APIURL, &n.PublicIP, &n.InternalIP, &n.MgmtIP, - &n.Role, &n.Version, &n.ConfigHash, &n.Status, + &n.Role, &n.PGRole, &n.Version, &n.ConfigHash, &n.Status, &n.LastSeen, &n.JoinedAt, &n.CreatedAt, &n.UpdatedAt, ); err != nil {