Skip to content

Commit cf96f90

Browse files
Kabuki94claude
andcommitted
fix(boot): unblock all Quadlet services + dbus-daemon-wsl exec failure
Diagnostics from `quadlet --dryrun` revealed why every Quadlet "renders but nothing actually starts" -- and `systemctl status dbus-daemon-wsl` revealed why D-Bus dies even after the OOMScoreAdjust fix. Three real bugs, all addressed here. 1. Quadlet Label= word-splitting (THE Quadlet boot blocker) Quadlet's Label= parser word-splits values on whitespace and emits each word as a separate --label arg to `podman run`. With `Label=org.opencontainers.image.description=Self-hosted Forgejo on port 3000 (HTTP) and 2222 (git+ssh).` the generated ExecStart looks like: ... --label (Forgejo) --label (HTTP) --label (git+ssh). --label 2222 --label 3000 --label and --label forge --label on --label port codeberg.org/forgejo/forgejo:11 The image ref ends up positioned where podman expects another label, the entire command fails to parse, container never starts. This was the actual cause of "every Quadlet missing" in the dashboard (services rendered but ExecStart was malformed). Fixed in: mios-ai, mios-forge, mios-cockpit-link, mios-forgejo-runner, ollama, mios-guacamole. Title labels reduced to single tokens (mios-ai, mios-forge, mios-cockpit-link, mios-forgejo-runner, mios-ollama, mios-guacamole). Description labels REMOVED entirely -- the unit's [Unit] Description= still carries the long human-readable text (which doesn't have the parser bug). url + documentation + io.podman_desktop.openInBrowser labels retained (no spaces). 2. dbus-daemon binary missing -> 203/EXEC `systemctl status dbus-daemon-wsl.service`: Process: 154 ExecStart=/usr/bin/dbus-daemon ... (code=exited, status=203/EXEC) Fedora CoreOS ships dbus-broker by default and does NOT carry /usr/bin/dbus-daemon. The MiOS WSL2 fallback unit references that binary (dbus-broker fails on WSL2 kernels because the audit subsystem it requires is stripped from MS WSL kernels), so the unit fails immediately at exec(). Every D-Bus consumer (logind, polkit, cockpit, homectl, hostnamed) cascade-fails with "Failed to connect to system scope bus". Fix: added `dbus-daemon` to PACKAGES.md packages-base so the binary is present at /usr/bin/dbus-daemon. The unit can now exec it. 3. Dashboard mis-reported every Quadlet as "missing" service_status() used `systemctl list-unit-files <pattern>` to detect unit existence. That works for static units in /usr/lib/systemd/system but doesn't reliably show generator-produced units in /run/systemd/generator/. Every Quadlet (which IS generator-produced) showed up as "missing" even when its .service file existed. Fix: switched to `systemctl show ... LoadState,ActiveState`. LoadState tells us "does the unit exist at all"; ActiveState tells us whether it's running. Quadlet-generated units now report their real state. Adjacent improvement: dashboard previously double-rendered the loop hint and the ASCII fastfetch logo bled into the multi-line MiOS custom module output -- both fixed in the previous commit (a2845f4) by separating fastfetch from the services block. Cockpit web console at 10.88.0.5:9090 timeout in the latest log: that's downstream of (2) -- Cockpit needs D-Bus to render the management UI; bus is dead, web responder hangs. Fixing dbus-daemon should restore it. Note: 10.88.0.5 is the container subnet IP; from a Windows host, use https://localhost:9090/ instead (mirrored networking forwards into the WSL distro). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent a2845f4 commit cf96f90

8 files changed

Lines changed: 57 additions & 32 deletions

File tree

etc/containers/systemd/mios-ai.container

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,11 @@ Environment=CORS=true
3636
User=817
3737
Group=817
3838

39-
# OCI image labels for Podman Desktop. Architectural Law 5: this is the
40-
# single MIOS_AI_ENDPOINT every agent on the system targets; surfacing
41-
# it in Podman Desktop lets operators sanity-check that the OpenAI-API-
42-
# shaped surface is reachable without leaving the GUI.
43-
Label=org.opencontainers.image.title=MiOS AI inference (LocalAI)
44-
Label=org.opencontainers.image.description=OpenAI-API-compatible /v1 endpoint at port 8080 (chat/completions, responses, embeddings, models).
39+
# OCI image labels for Podman Desktop. Values MUST NOT contain spaces
40+
# -- Quadlet's Label= parser word-splits on whitespace and emits each
41+
# word as a separate --label arg, breaking the entire podman-run
42+
# command line.
43+
Label=org.opencontainers.image.title=mios-ai
4544
Label=org.opencontainers.image.url=http://localhost:8080/v1/models
4645
Label=org.opencontainers.image.documentation=https://platform.openai.com/docs/api-reference
4746
Label=io.podman_desktop.openInBrowser=http://localhost:8080/v1/models

etc/containers/systemd/mios-cockpit-link.container

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ ContainerName=mios-cockpit-link
4141
Exec=tcp-listen:19090,bind=0.0.0.0,fork,reuseaddr tcp:host.containers.internal:9090
4242
PublishPort=0.0.0.0:19090:19090
4343

44-
# OCI labels Podman Desktop renders. The url label is the canonical
45-
# Cockpit endpoint (https; cockpit-ws issues a self-signed cert by
46-
# default and clients accept it on first visit).
47-
Label=org.opencontainers.image.title=MiOS Cockpit web console
48-
Label=org.opencontainers.image.description=Web-based system administration UI (host service on :9090, surfaced via :19090 port-forward).
44+
# OCI labels Podman Desktop renders. Values MUST NOT contain spaces --
45+
# Quadlet's Label= parser word-splits on whitespace and breaks the
46+
# generated podman-run command. The url label is the canonical Cockpit
47+
# endpoint (https; cockpit-ws issues a self-signed cert by default and
48+
# clients accept it on first visit).
49+
Label=org.opencontainers.image.title=mios-cockpit-link
4950
Label=org.opencontainers.image.url=https://localhost:9090/
5051
Label=org.opencontainers.image.documentation=https://cockpit-project.org/documentation.html
5152
Label=io.podman_desktop.openInBrowser=https://localhost:9090/

etc/containers/systemd/mios-forge.container

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ Network=mios.network
3030
PublishPort=3000:3000
3131
PublishPort=2222:22
3232

33-
# OCI image labels surfaced in Podman Desktop's container detail panel.
34-
# org.opencontainers.image.url is rendered as a clickable "open" link
35-
# alongside the published-port list, so operators can open the forge
36-
# web UI directly from the Podman Desktop container view.
37-
Label=org.opencontainers.image.title=MiOS Git forge (Forgejo)
38-
Label=org.opencontainers.image.description=Self-hosted Forgejo on port 3000 (HTTP) and 2222 (git+ssh).
33+
# OCI image labels. Values MUST NOT contain whitespace -- Quadlet's
34+
# Label= parser word-splits on spaces and emits each word as a separate
35+
# --label arg to `podman run`, which then mis-positions the image ref
36+
# and the container fails to start. Use hyphens/dots/no-break-space
37+
# encoding if a multi-word description is genuinely needed.
38+
Label=org.opencontainers.image.title=mios-forge
3939
Label=org.opencontainers.image.url=http://localhost:3000/
4040
Label=org.opencontainers.image.documentation=https://forgejo.org/docs/latest/
4141
Label=io.podman_desktop.openInBrowser=http://localhost:3000/

etc/containers/systemd/mios-forgejo-runner.container

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,11 @@ Environment=FORGEJO_RUNNER_DEFAULT_LABELS=mios-self-hosted
9191
User=0
9292
Group=0
9393

94-
Label=org.opencontainers.image.title=MiOS Forgejo Runner
95-
Label=org.opencontainers.image.description=Self-hosted CI runner for the MiOS self-replication loop. Builds OCI images via podman build, signals bootc-switch.
94+
# Quadlet Label= parser word-splits on spaces -- values MUST NOT contain
95+
# whitespace or the generated podman-run command breaks. Title kept
96+
# single-word; long descriptions go in the unit's [Unit] Description=
97+
# (which doesn't have the same parser bug).
98+
Label=org.opencontainers.image.title=mios-forgejo-runner
9699
Label=org.opencontainers.image.documentation=https://forgejo.org/docs/latest/admin/actions/
97100
Label=io.podman_desktop.openInBrowser=http://localhost:3000/-/admin/actions/runners
98101

usr/libexec/mios/mios-dashboard.sh

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,28 @@ hr_line() {
8282
# service_status <unit>
8383
# Echoes "<state>|<dot>|<color>" so callers don't shell out twice.
8484
# state: active / failed / inactive / skipped / missing / unknown
85+
#
86+
# Uses `systemctl show ... LoadState,ActiveState` rather than
87+
# `list-unit-files` -- the latter misses Quadlet-generated units that
88+
# live in /run/systemd/generator/ until they're loaded into the
89+
# manager's set, causing the dashboard to mis-report every running
90+
# Quadlet as "missing".
8591
service_status() {
8692
local svc="$1"
8793
if ! command -v systemctl >/dev/null 2>&1; then
8894
printf 'no-systemd|%s|%s' "$DOT_DOWN" "$C_GRY"; return
8995
fi
90-
if ! systemctl list-unit-files "$svc" --no-legend 2>/dev/null | grep -q .; then
96+
# Read both LoadState (does the unit exist at all?) and ActiveState
97+
# (is it running?) in one call. LoadState=not-found means the unit
98+
# truly doesn't exist; anything else means it's loaded somewhere.
99+
local out load active
100+
out="$(systemctl show "$svc" --property=LoadState --property=ActiveState 2>/dev/null || true)"
101+
load="$(printf '%s' "$out" | sed -nE 's/^LoadState=(.*)$/\1/p')"
102+
active="$(printf '%s' "$out" | sed -nE 's/^ActiveState=(.*)$/\1/p')"
103+
if [[ -z "$load" ]] || [[ "$load" == "not-found" ]] || [[ "$load" == "masked" ]]; then
91104
printf 'missing|%s|%s' "$DOT_DOWN" "$C_GRY"; return
92105
fi
93-
local state
94-
state="$(systemctl is-active "$svc" 2>/dev/null || true)"
95-
case "$state" in
106+
case "$active" in
96107
active)
97108
printf 'active|%s|%s' "$DOT_UP" "$C_GRN" ;;
98109
activating|reloading)

usr/share/containers/systemd/mios-guacamole.container

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ Group=mios-guacamole
1919
# path is preserved so links from the README and MOTD still resolve.
2020
PublishPort=0.0.0.0:8090:8080
2121

22-
# OCI labels for Podman Desktop discovery -- "Browser desktop" entry
23-
# point. Path includes /guacamole because the upstream image serves on
24-
# that context root.
25-
Label=org.opencontainers.image.title=MiOS Apache Guacamole (Browser desktop)
26-
Label=org.opencontainers.image.description=Web client for RDP / VNC / SSH connections, served on port 8090 (mapped from container 8080 to avoid mios-ai conflict).
22+
# OCI labels for Podman Desktop discovery. Values MUST NOT contain
23+
# spaces -- Quadlet's Label= parser word-splits on whitespace and breaks
24+
# the generated podman-run command. Path includes /guacamole because
25+
# the upstream image serves on that context root.
26+
Label=org.opencontainers.image.title=mios-guacamole
2727
Label=org.opencontainers.image.url=http://localhost:8090/guacamole/
2828
Label=org.opencontainers.image.documentation=https://guacamole.apache.org/doc/
2929
Label=io.podman_desktop.openInBrowser=http://localhost:8090/guacamole/

usr/share/containers/systemd/ollama.container

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@ Volume=/usr/share/ollama:/usr/share/ollama:ro,Z
3333

3434
PublishPort=0.0.0.0:11434:11434
3535

36-
# OCI labels for Podman Desktop discovery. ollama is an alternate local
37-
# LLM backend alongside mios-ai (LocalAI on :8080); MIOS_AI_ENDPOINT
36+
# OCI labels for Podman Desktop discovery. Values MUST NOT contain
37+
# spaces -- Quadlet's Label= parser word-splits on whitespace and emits
38+
# each word as a separate --label arg, breaking the generated
39+
# podman-run command line. ollama is an alternate local LLM backend
40+
# alongside mios-ai (LocalAI on :8080); MIOS_AI_ENDPOINT
3841
# (Architectural Law 5) still points at LocalAI by default.
39-
Label=org.opencontainers.image.title=MiOS Ollama LLM server
40-
Label=org.opencontainers.image.description=Ollama API on port 11434 -- alternate local LLM runtime.
42+
Label=org.opencontainers.image.title=mios-ollama
4143
Label=org.opencontainers.image.url=http://localhost:11434/
4244
Label=io.podman_desktop.openInBrowser=http://localhost:11434/
4345

usr/share/mios/PACKAGES.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ audit
107107
fapolicyd
108108
crowdsec
109109
usbguard
110+
# dbus-daemon: Fedora CoreOS ships dbus-broker by default and does NOT
111+
# carry /usr/bin/dbus-daemon. The WSL2 D-Bus fallback unit
112+
# (usr/lib/systemd/system/dbus-daemon-wsl.service) ExecStart='s
113+
# /usr/bin/dbus-daemon because dbus-broker fails on WSL2 kernels (the
114+
# audit subsystem dbus-broker requires is stripped from MS WSL kernels).
115+
# Without this package, dbus-daemon-wsl exits 203/EXEC and the entire
116+
# system D-Bus stack stays down -- logind/polkit/cockpit/homectl all
117+
# cascade-fail with "Failed to connect to system scope bus".
118+
dbus-daemon
110119
```
111120

112121
## Moby -- Docker-compatible engine

0 commit comments

Comments
 (0)