Files
llmgw/internal/store/pghosts.go
T
Ilker ManapandClaude Opus 5.5 975c93994f Set up a replicated store with server init --patroni, and watch it
init --patroni user@host ... installs PostgreSQL, Patroni and etcd on the
given machines over ssh, with this one as the third etcd vote, makes the role
and database, and moves the store in use into the cluster. Each step checks
first, so it changes nothing on a cluster that is up. For a store of several
hosts the control plane publishes each member's role, state and lag from
Patroni, a stopped member as missing, prints it in ctl status, and alerts on
it. Making an administrator on PostgreSQL sent a bool to an integer column;
it sends an integer now.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-03 20:57:41 +02:00

45 lines
1.5 KiB
Go

package store
import (
"fmt"
"net/url"
"strings"
)
// SplitPostgres reads a PostgreSQL address that may name several hosts —
// "postgres://u:p@h1:5432,h2:5432/db?…", the members of a replicated cluster,
// as pgx and libpq both accept — into its hosts, their ports, and the rest of
// the address with one placeholder host, which url.Parse can read. url.Parse
// cannot read the list itself: it took everything before the last colon for
// one host name.
func SplitPostgres(dsn string) (hosts, ports []string, rest *url.URL, err error) {
scheme, after, ok := strings.Cut(dsn, "://")
if !ok {
return nil, nil, nil, fmt.Errorf("the store address is not a URL")
}
authority, tail := after, ""
if i := strings.IndexAny(after, "/?"); i >= 0 {
authority, tail = after[:i], after[i:]
}
userinfo, hostlist := "", authority
if i := strings.LastIndexByte(authority, '@'); i >= 0 {
userinfo, hostlist = authority[:i+1], authority[i+1:]
}
for _, hp := range strings.Split(hostlist, ",") {
u, err := url.Parse("x://" + hp)
if err != nil || u.Hostname() == "" {
return nil, nil, nil, fmt.Errorf("the store address has a host that is not one: %q", hp)
}
port := u.Port()
if port == "" {
port = "5432"
}
hosts, ports = append(hosts, u.Hostname()), append(ports, port)
}
rest, err = url.Parse(scheme + "://" + userinfo + "host" + tail)
if err != nil {
return nil, nil, nil, fmt.Errorf("the store address is not a URL")
}
return hosts, ports, rest, nil
}