fix(engine): pin docker compose project name to avoid empty-basename failure

systemd daemons run with WorkingDirectory=/ by default; docker compose
derives the project name from basename(cwd), which is empty at '/', and
aborts with 'project name must not be empty'. Pass -p decnet explicitly
so the project name is independent of cwd, and set WorkingDirectory=/opt/decnet
on the three DECNET units so compose artifacts (decnet-compose.yml,
build contexts) also land in the install dir.
This commit is contained in:
2026-04-19 06:17:30 -04:00
parent 79db999030
commit b883f24ba2
5 changed files with 14 additions and 3 deletions

View File

@@ -54,7 +54,11 @@ def _sync_logging_helper(config: DecnetConfig) -> None:
def _compose(*args: str, compose_file: Path = COMPOSE_FILE, env: dict | None = None) -> None:
import os
cmd = ["docker", "compose", "-f", str(compose_file), *args]
# -p decnet pins the compose project name. Without it, docker compose
# derives the project from basename($PWD); when a daemon (systemd) runs
# with WorkingDirectory=/ that basename is empty and compose aborts with
# "project name must not be empty".
cmd = ["docker", "compose", "-p", "decnet", "-f", str(compose_file), *args]
merged = {**os.environ, **(env or {})}
subprocess.run(cmd, check=True, env=merged) # nosec B603
@@ -79,7 +83,11 @@ def _compose_with_retry(
"""Run a docker compose command, retrying on transient failures."""
import os
last_exc: subprocess.CalledProcessError | None = None
cmd = ["docker", "compose", "-f", str(compose_file), *args]
# -p decnet pins the compose project name. Without it, docker compose
# derives the project from basename($PWD); when a daemon (systemd) runs
# with WorkingDirectory=/ that basename is empty and compose aborts with
# "project name must not be empty".
cmd = ["docker", "compose", "-p", "decnet", "-f", str(compose_file), *args]
merged = {**os.environ, **(env or {})}
for attempt in range(1, retries + 1):
result = subprocess.run(cmd, capture_output=True, text=True, env=merged) # nosec B603

View File

@@ -6,6 +6,7 @@ Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/decnet
Environment=DECNET_SYSTEM_LOGS=/var/log/decnet/decnet.agent.log
ExecStart=/usr/local/bin/decnet agent --no-forwarder
Restart=on-failure

View File

@@ -7,6 +7,7 @@ Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/decnet
Environment=DECNET_SYSTEM_LOGS=/var/log/decnet/decnet.log
ExecStart=/usr/local/bin/decnet deploy
StandardOutput=append:/var/log/decnet/decnet.log

View File

@@ -7,6 +7,7 @@ PartOf=decnet-agent.service
[Service]
Type=simple
WorkingDirectory=/opt/decnet
Environment=DECNET_SYSTEM_LOGS=/var/log/decnet/decnet.forwarder.log
ExecStart=/usr/local/bin/decnet forwarder --master-host {{ master_host }} --master-port 6514 --agent-dir /etc/decnet/agent --log-file /var/log/decnet/decnet.log
Restart=on-failure

View File

@@ -43,7 +43,7 @@ class TestCompose:
_compose("up", "-d", compose_file=Path("test.yml"))
mock_run.assert_called_once()
cmd = mock_run.call_args[0][0]
assert cmd[:4] == ["docker", "compose", "-f", "test.yml"]
assert cmd[:6] == ["docker", "compose", "-p", "decnet", "-f", "test.yml"]
assert "up" in cmd
assert "-d" in cmd