-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Summary
Replace the current systemctl CLI output parsing in systemd.py with proper D-Bus API calls for interacting with systemd.
Background
The current implementation parses text output from systemctl list-units, which is fragile:
- We recently shipped a bug where failed units were returned as "running" because we weren't parsing the state columns correctly
- CLI output format can change between systemd versions
- Text parsing is error-prone and hard to test reliably
systemd's official, stable API is D-Bus. The CLI tools are convenience wrappers, not the primary interface.
Technical Details
Current Implementation (src/ots_containers/systemd.py)
def discover_instances() -> list[int]:
result = subprocess.run(
["systemctl", "list-units", "onetime@*", "--plain", "--no-legend"],
capture_output=True,
text=True,
)
# Parses text: "onetime@7043.service loaded active running ..."Target Implementation
Use pystemd or dasbus to query systemd via D-Bus:
# Example with pystemd
from pystemd.systemd1 import Manager
def discover_instances() -> list[int]:
with Manager() as manager:
units = manager.list_units()
ports = []
for unit in units:
name, _, _, _, active_state, sub_state, *_ = unit
if name.startswith(b"onetime@") and name.endswith(b".service"):
if active_state == b"active" and sub_state == b"running":
port = int(name.split(b"@")[1].split(b".")[0])
ports.append(port)
return sorted(ports)D-Bus API Properties
From org.freedesktop.systemd1.Unit:
ActiveState: "active", "inactive", "failed", etc.SubState: "running", "dead", "failed", etc.LoadState: "loaded", "not-found", etc.
Library Options
| Library | Pros | Cons |
|---|---|---|
| pystemd | Facebook/Meta maintained, widely used | Requires libsystemd |
| dasbus | Pure Python, modern async | Less systemd-specific |
| dbus-python | Standard library feel | Older, callback-based |
Scope
Functions to convert in systemd.py:
-
discover_instances()- Query unit list and states -
daemon_reload()- CallReload()method -
start(unit)- CallStartUnit()method -
stop(unit)- CallStopUnit()method -
restart(unit)- CallRestartUnit()method -
status(unit)- Query unit properties -
unit_exists(unit)- CheckLoadStateproperty
Acceptance Criteria
- All systemd interactions use D-Bus instead of subprocess calls
- Unit tests mock D-Bus interface, not subprocess
- Works on systems with systemd 245+ (Debian 11+, Ubuntu 20.04+)
- Graceful fallback or clear error if D-Bus unavailable
- No change to public API of
systemd.pymodule
References
- systemd D-Bus API
- pystemd GitHub
- systemd-mcp architecture - Example of proper D-Bus integration
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels