// A provisioner, in the form the mesh expects one. // // The mesh generated a password, sealed it to the machine that must accept it, and discarded the // plaintext — so it cannot tell PostgreSQL to start accepting it. Something on that machine reads // what the host wrote and makes it true. This is that something. // // **It is an example, not part of the control plane.** The control plane decides and never // touches a machine; this runs on the machine and touches it. A real one ships with the module // that ships PostgreSQL (novox/hq ADR 0001 — third-party software runs *on* the mesh, not *of* // it). What lives here is the contract, written as something that runs so it can be read rather // than described. // // What it is given, both written by the host from an ordinary declaration: // // $GRANTS/mesh.json every consumer, what it asked for, and where its credential is // $GRANTS/.secret one consumer's password, alone in the file // // Two files because the mesh discarded the value and could not compose a document containing it. package main import ( "context" "encoding/json" "fmt" "os" "path/filepath" "sort" "strings" "github.com/jackc/pgx/v5" ) // mark is what this provisioner names the roles it owns. // // So it never removes one a person made by hand — the mesh's own rule about origins, one level // down (novox/hq 04-ISSUES/010). A provisioner that dropped every role it did not recognise would // be a provisioner nobody could safely run on a database that predates it. const mark = "mesh_" // contribution is one consumer, as the mesh described it. type contribution struct { From string `json:"from"` // Node is empty for a module on this machine, which is asking for something local and is not // this provisioner's business. Node string `json:"node"` Secret string `json:"secret"` Values map[string]any `json:"values"` } type manifest struct { Requirement string `json:"requirement"` Given []contribution `json:"given"` } func main() { if err := run(context.Background()); err != nil { fmt.Fprintf(os.Stderr, "mesh-provision-postgres: %v\n", err) os.Exit(1) } } func run(ctx context.Context) error { grants := os.Getenv("GRANTS") if grants == "" { grants = "/var/lib/postgres/grants" } raw, err := os.ReadFile(filepath.Join(grants, "mesh.json")) if err != nil { if os.IsNotExist(err) { // Nothing has been granted here. Not a failure: a provider with no consumers is an // ordinary state, and one this must be able to reach from any other. fmt.Printf("nothing has been granted to this machine\n") return nil } return err } var m manifest if err := json.Unmarshal(raw, &m); err != nil { return fmt.Errorf("the manifest at %s is not readable: %w", grants, err) } db, err := pgx.Connect(ctx, os.Getenv("MESH_PROVISION_POSTGRES")) if err != nil { return err } defer db.Close(ctx) // **Reconciling, not applying a change.** It runs after every declaration and is never told // what changed, so it must reach the same state from wherever it starts. wanted := map[string]bool{} for _, c := range sorted(m.Given) { if c.Node == "" { continue } name, _ := c.Values["name"].(string) if name == "" { return fmt.Errorf("%s asked for a database and did not name it", c.Node) } password, err := os.ReadFile(c.Secret) if err != nil { // The manifest says there is a credential and the host has not written it. Refused // rather than creating a role with no password — a login nothing can use, which // nothing would report until something tried to connect. return fmt.Errorf("%s's credential should be at %s and is not there", c.Node, c.Secret) } role := mark + c.Node wanted[role] = true if err := ensureRole(ctx, db, role, strings.TrimSpace(string(password))); err != nil { return err } if err := ensureDatabase(ctx, db, name, role); err != nil { return err } } // And everything this provisioner made that nobody asks for any more. **The half usually // missing**: a consumer that goes away otherwise keeps a working login for ever and nothing // says so. return revokeOrphans(ctx, db, wanted) } func ensureRole(ctx context.Context, db *pgx.Conn, role, password string) error { var exists bool if err := db.QueryRow(ctx, `select true from pg_roles where rolname = $1`, role).Scan(&exists); err != nil && err != pgx.ErrNoRows { return err } // Set every time rather than only on creation. The mesh replaces the file when it rotates, // and a provisioner that only ever created would leave the old password working — a rotation // that reports success and changes nothing. verb := "create" if exists { verb = "alter" } _, err := db.Exec(ctx, fmt.Sprintf("%s role %s with login password %s", verb, quoteName(role), quoteString(password))) if err != nil { return err } if !exists { fmt.Printf("created %s\n", role) } return nil } func ensureDatabase(ctx context.Context, db *pgx.Conn, name, owner string) error { var exists bool if err := db.QueryRow(ctx, `select true from pg_database where datname = $1`, name).Scan(&exists); err != nil && err != pgx.ErrNoRows { return err } if exists { return nil } if _, err := db.Exec(ctx, fmt.Sprintf("create database %s owner %s", quoteName(name), quoteName(owner))); err != nil { return err } fmt.Printf("created database %s owned by %s\n", name, owner) return nil } func revokeOrphans(ctx context.Context, db *pgx.Conn, wanted map[string]bool) error { rows, err := db.Query(ctx, `select rolname from pg_roles where rolname like $1 and rolcanlogin order by rolname`, mark+"%") if err != nil { return err } var found []string for rows.Next() { var role string if err := rows.Scan(&role); err != nil { rows.Close() return err } found = append(found, role) } rows.Close() if err := rows.Err(); err != nil { return err } for _, role := range found { if wanted[role] { continue } // Login removed rather than the role dropped. Dropping fails while the role owns // anything, and a provisioner that failed there would stop reconciling everything else — // so the credential stops working immediately and what it owns is somebody's to decide // about. if _, err := db.Exec(ctx, fmt.Sprintf("alter role %s with nologin", quoteName(role))); err != nil { return err } fmt.Printf("revoked %s — nothing in the mesh asks for it\n", role) } return nil } // sorted puts consumers in a stable order, so two runs do the same work in the same sequence and // the output of one can be compared with another. func sorted(given []contribution) []contribution { out := append([]contribution{}, given...) sort.Slice(out, func(i, j int) bool { return out[i].Node < out[j].Node }) return out } // quoteName and quoteString exist because PostgreSQL takes no parameters in DDL. // // Both double the quote character, which is the whole of the escaping rule. Worth doing properly // even here: a password is chosen by the mesh and a node name by a person, and "the value happens // to be safe today" is not a property anything should rest on. func quoteName(s string) string { return `"` + strings.ReplaceAll(s, `"`, `""`) + `"` } func quoteString(s string) string { return `'` + strings.ReplaceAll(s, `'`, `''`) + `'` }