summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-03 15:31:48 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-03 15:31:48 +0200
commit4d7581b23b560a2a6803cae2df91f90368c01b21 (patch)
tree63d0551bf66f9f9b4e5a4ee3b9695baf0a89f41c
parent0b3ffdb8d7f07aee817ece24fd44a24ac60e6714 (diff)
downloadmeshbay-4d7581b23b560a2a6803cae2df91f90368c01b21.tar.gz
fix(node): reload the user manager before reload/restart-daemon
Reported live: after installing the .deb, systemd printed "Warning: The unit file, source configuration file or drop-ins of meshbay-node.service changed on disk. Run 'systemctl --user daemon-reload' to reload units." Both postinst scripts (deb and rpm) already run a daemon-reload, but only for the system manager — they run as root, and the unit that changed is the *user* unit (packaging/systemd/meshbay-node-user.service), owned by each signed-in person's own user manager, a different process root cannot reach. Iterating over logged-in users from postinst was considered and rejected: fragile (depends on machined and each user's session bus), and root has no business doing a user's job. `_systemctl_user` — the one place `reload` and `restart-daemon` already shell out to systemd — now reloads the user manager first, under the correct privilege, right before the verb that would otherwise act on a stale unit. Best-effort and unchecked, like the postinst's own daemon-reload: a reload the manager did not need must never block what the operator asked for, and systemd still reports a genuine failure from the verb itself. Does not touch the postinst scripts. On a package upgrade the warning can still appear once, before the next reload/restart-daemon (or a login, which starts a fresh user manager that reads the current file); this closes it from the CLI's own lifecycle commands rather than reaching into every session from root. test_lifecycle_commands_delegate_to_systemctl_user now expects the daemon-reload call ahead of the verb — checked failing against the previous code. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AbwJDbNTkiRUh7HTWEoyss
-rw-r--r--packages/meshbay-node/src/meshbay_node/daemon.py14
-rw-r--r--packages/meshbay-node/tests/test_cli_dispatch.py10
2 files changed, 23 insertions, 1 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/daemon.py b/packages/meshbay-node/src/meshbay_node/daemon.py
index 8f9307c..3a024f0 100644
--- a/packages/meshbay-node/src/meshbay_node/daemon.py
+++ b/packages/meshbay-node/src/meshbay_node/daemon.py
@@ -1599,9 +1599,23 @@ def _systemctl_user(verb: str, unit: str, *, not_running_hint: str,
signalling it, respawning it — is a second, worse implementation of what
systemd is already doing, and pattern-matching a process list has already
hit a real developer's real running node by accident.
+
+ Reloads the user manager's view of unit files first. The package
+ installers (deb postinst, rpm %post) run as root and can only reload the
+ *system* manager — a different process from any signed-in user's *user*
+ manager, which is the one that actually owns this unit — so a package
+ upgrade leaves that manager still holding the old unit file and prints a
+ warning naming the exact fix. Doing it here runs it under the right
+ privilege, the user's own, right before the command that would otherwise
+ act on a stale definition. Best-effort and unchecked: a reload the
+ manager did not need must never block what the operator actually asked
+ for, and a genuine problem still surfaces from the verb below.
"""
import subprocess
+ subprocess.run(["systemctl", "--user", "daemon-reload"],
+ capture_output=True, text=True)
+
result = subprocess.run(["systemctl", "--user", verb, unit],
capture_output=True, text=True)
if result.returncode != 0:
diff --git a/packages/meshbay-node/tests/test_cli_dispatch.py b/packages/meshbay-node/tests/test_cli_dispatch.py
index b676546..c774dc0 100644
--- a/packages/meshbay-node/tests/test_cli_dispatch.py
+++ b/packages/meshbay-node/tests/test_cli_dispatch.py
@@ -150,12 +150,20 @@ def test_lifecycle_commands_delegate_to_systemctl_user(
`reload` and `restart-daemon` must ask systemd to do it, not hunt a PID
with pgrep and signal it directly — that pattern-matched a developer's own
running node by accident once, which is why it was replaced.
+
+ They must also reload the user manager's view of unit files first: a
+ package upgrade only reloads the *system* manager (it runs as root and
+ cannot reach a signed-in user's own), so the user manager can still be
+ holding a stale unit when one of these runs.
"""
monkeypatch.setattr(sys, "argv", ["meshbay-node", *argv])
daemon_mod.main()
systemctl_calls = dict(stub_daemon)["_systemctl_calls"]
- assert systemctl_calls == [["systemctl", "--user", verb, "meshbay-node"]]
+ assert systemctl_calls == [
+ ["systemctl", "--user", "daemon-reload"],
+ ["systemctl", "--user", verb, "meshbay-node"],
+ ]
assert not capsys.readouterr().err