diff --git a/content/en/specs/bigfred/architecture/15-supervisord/01-overview-and-goals.md b/content/en/specs/bigfred/architecture/15-supervisord/01-overview-and-goals.md index ec0410b..809f40e 100644 --- a/content/en/specs/bigfred/architecture/15-supervisord/01-overview-and-goals.md +++ b/content/en/specs/bigfred/architecture/15-supervisord/01-overview-and-goals.md @@ -27,12 +27,12 @@ source of truth** for *what* should run. supervisord's built-in **`supervisorctl reread`** followed by **`supervisorctl update`**, which adds/removes/restarts individual programs without restarting the daemon. A full supervisord restart - is used only when global sections (`[supervisord]`, socket, …) + is used only when global sections (`[supervisord]`, HTTP listener, …) change — a rare case with stable hub paths. 4. **Non-root only** — no `/etc/supervisor`, no system-wide `/var/run` - for this instance, no privileged ports, no `user=root`. Config, socket, - pidfile and logs live under `/data/…` on the hub RW partition (or the - same paths when developing against a mounted `/data` tree). + for this instance, no privileged ports, no `user=root`. Config, HTTP + listener, pidfile and logs live under `/data/…` on the hub RW partition + (or the same paths when developing against a mounted `/data` tree). 5. **Observable** — the service exposes program/group status so higher layers (`ScriptService`, WS `system.status`, admin UI) can report health without re-implementing process tracking. @@ -100,14 +100,14 @@ the RW partition mounted at `/data`; `SupervisordService.Start` creates missing directories with mode `0700`. The scripts-executor Unix socket remains at `$XDG_RUNTIME_DIR/loco/exec.sock` -(§3a.7) — only supervisord's own config, control socket, pidfile and logs -use the `/data` tree: +(§3a.7) — only supervisord's own config, HTTP listener, pidfile and logs +use the `/data` tree (listener binds loopback; address is not a path): -| Path | Purpose | Mode | +| Path / address | Purpose | Mode | |---|---|---| | `/data/etc/supervisord/` | config dir; `directory=` for managed programs | `0700` | | `/data/etc/supervisord/supervisord.conf` | rendered config | `0600` | -| `/data/run/supervisord.sock` | `[unix_http_server]` socket | `0700` | +| `127.0.0.1:9001` | `[inet_http_server]` HTTP listener (`InetHTTPAddr`) | — | | `/data/run/supervisord.pid` | supervisord pidfile | `0600` | | `/data/log/` | supervisord main log + per-program logs | `0700` | diff --git a/content/en/specs/bigfred/architecture/15-supervisord/02-service-api-and-config.md b/content/en/specs/bigfred/architecture/15-supervisord/02-service-api-and-config.md index 2438b90..ed9497b 100644 --- a/content/en/specs/bigfred/architecture/15-supervisord/02-service-api-and-config.md +++ b/content/en/specs/bigfred/architecture/15-supervisord/02-service-api-and-config.md @@ -8,7 +8,7 @@ pkgs/bigfred/server/supervisord/ │ └── supervisord.conf.tmpl # embedded via //go:embed ├── config.go # ProgramSpec, GroupSpec, RenderConfig ├── render.go # text/template execution + atomic write -├── ctl.go # supervisorctl wrapper (unix socket) +├── ctl.go # supervisorctl wrapper (inet HTTP) └── daemon.go # spawn / wait / stop supervisord process pkgs/bigfred/server/service/supervisord.go @@ -28,7 +28,7 @@ awareness. // ProgramSpec is one supervisord [program:NAME] entry. type ProgramSpec struct { Name string // unique across the entire supervisord instance - Command string // passed to /bin/bash -c (see template); may contain pipes, env, etc. + Command string // wrapped as ` -c '…'` (see template / DefaultShell); may contain pipes, env, etc. Autostart bool Autorestart bool // Optional overrides (zero = template default) @@ -68,11 +68,11 @@ type SupervisordConfig struct { SupervisorctlBin string // Paths — default to hub locations under /data/etc/supervisord/, /data/run/, /data/log/ - ConfigDir string - ConfigPath string - SocketPath string - PIDFile string - LogDir string + ConfigDir string + ConfigPath string + InetHTTPAddr string // default 127.0.0.1:9001 + PIDFile string + LogDir string // Initial desired state (may be empty; callers add before Start) InitialState supervisord.DesiredState @@ -136,11 +136,12 @@ The template is embedded and executed with a single root struct: // pkgs/bigfred/server/supervisord/render.go type templateData struct { - RunAsUser string - SocketPath string - PIDFile string - LogDir string - Groups []GroupSpec + RunAsUser string + InetHTTPAddr string + PIDFile string + LogDir string + Shell string // empty → DefaultShell() (/bin/bash|/bin/sh|/system/bin/sh) + Groups []GroupSpec } ``` @@ -148,9 +149,8 @@ Example template (`supervisord.conf.tmpl`): ```ini ; Generated by BigFred — do not edit manually. -[unix_http_server] -file={{ .SocketPath }} -chmod=0700 +[inet_http_server] +port={{ .InetHTTPAddr }} [supervisord] logfile={{ .LogDir }}/supervisord.log @@ -163,7 +163,7 @@ user={{ .RunAsUser }} supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] -serverurl=unix://{{ .SocketPath }} +serverurl=http://{{ .InetHTTPAddr }} {{- range .Groups }} @@ -172,7 +172,7 @@ programs={{ joinProgramNames .Programs }} {{- range .Programs }} [program:{{ .Name }}] -command=/bin/bash -c {{ shellQuote .Command }} +command={{ $.Shell }} -c {{ shellQuote .Command }} directory={{ $.ConfigDir }} autostart={{ .Autostart }} autorestart={{ .Autorestart }} @@ -189,11 +189,13 @@ startsecs={{ or .StartSecs 1 }} Template helpers (registered in `render.go`): - `joinProgramNames` — comma-separated program list for `[group:…]`. -- `shellQuote` — single-quote escaping for safe `/bin/bash -c '…'` embedding. +- `shellQuote` — single-quote escaping for safe ` -c '…'` embedding. - `or` — default integers when struct field is zero. -Callers pass the **inner** shell command only; the template always wraps it -as `/bin/bash -c '…'`. Example: `Command: "/usr/bin/loco scripts-executor --executor-socket /run/…"`. +Callers pass the **inner** shell command only; the template wraps it as +`{{ $.Shell }} -c '…'`. `Shell` defaults via `DefaultShell()` to the first +existing of `/bin/bash`, `/bin/sh`, `/system/bin/sh` (Android). Example: +`Command: "/usr/bin/loco scripts-executor --executor-socket /run/…"`. `autostart` and `autorestart` render as lowercase `true` / `false` per supervisord INI conventions. diff --git a/content/en/specs/bigfred/architecture/15-supervisord/03-lifecycle-and-health.md b/content/en/specs/bigfred/architecture/15-supervisord/03-lifecycle-and-health.md index 4cef10b..2a2a406 100644 --- a/content/en/specs/bigfred/architecture/15-supervisord/03-lifecycle-and-health.md +++ b/content/en/specs/bigfred/architecture/15-supervisord/03-lifecycle-and-health.md @@ -10,7 +10,7 @@ server main │ └─ SupervisordService.Start(ctx) │ - ├─ MkdirAll ConfigDir, LogDir, socket parent dir (0700) + ├─ MkdirAll ConfigDir, LogDir, pidfile parent dir (0700) ├─ verify supervisord + supervisorctl binaries exist ├─ render → supervisord.conf (atomic write) │ @@ -62,8 +62,9 @@ program, change `command` / `autostart` / `autorestart`) touch only via `reread` + `update` while other programs keep running. **Full daemon restart** is the fallback when global sections change -(socket path, logfile, pidfile, `user=`, …). With stable hub paths set -at service construction this should be rare (essentially first boot only). +(HTTP listener address, logfile, pidfile, `user=`, …). With stable hub +paths set at service construction this should be rare (essentially first +boot only). ##### Full daemon restart (fallback) @@ -130,7 +131,7 @@ Subscribers: ##### Daemon respawn (supervisord crash) -If the health loop cannot reach the unix socket but `loco server` is +If the health loop cannot reach the HTTP listener but `loco server` is still running: 1. Log `supervisord daemon unreachable`. diff --git a/content/en/specs/bigfred/architecture/15-supervisord/04-integration.md b/content/en/specs/bigfred/architecture/15-supervisord/04-integration.md index dc99202..9eee332 100644 --- a/content/en/specs/bigfred/architecture/15-supervisord/04-integration.md +++ b/content/en/specs/bigfred/architecture/15-supervisord/04-integration.md @@ -211,4 +211,4 @@ To be copied into `14-acceptance-criteria/` when the milestone is scheduled: `scripts-executor` remains (`ps` check). 7. Template unit tests cover at least: empty groups, single group / single program, multiple groups, `autostart=false`, `autorestart=false`, - `shellQuote` escaping for `/bin/bash -c`. + `shellQuote` escaping for shell `-c` wrappers. diff --git a/content/en/specs/bigfred/architecture/15-supervisord/README.md b/content/en/specs/bigfred/architecture/15-supervisord/README.md index 95e9213..f45fdb0 100644 --- a/content/en/specs/bigfred/architecture/15-supervisord/README.md +++ b/content/en/specs/bigfred/architecture/15-supervisord/README.md @@ -37,6 +37,6 @@ Wiring in `cli/root.go`, `scripts-executor` migration, `system.status` events. | Config & runtime paths | Hub paths under `/data/etc/supervisord/`, `/data/run/`, `/data/log/` | | Config authoring | embedded `text/template` → atomic write to `supervisord.conf` | | Apply config changes | regenerate file, then **`supervisorctl reread` + `update`** (built-in hot reload); full daemon restart only when global sections change | -| Process declaration | `(command, autostart, autorestart)` inside a named **process group**; `command` is wrapped as `/bin/bash -c '…'` | +| Process declaration | `(command, autostart, autorestart)` inside a named **process group**; `command` is wrapped as ` -c '…'` (`DefaultShell`: `/bin/bash` → `/bin/sh` → `/system/bin/sh`) | | Single instance | one `loco server` per machine — no multi-instance ownership checks | | External dependency | `supervisord` + `supervisorctl` binaries on `PATH` (Python `supervisor` package) |