Skip to content

Commit fde9bfd

Browse files
Name systemd-run's own error when a release command unit fails
A unit that never starts (it already exists, an unknown user) left the failure message with empty command output and no reason. The message now ends with the tail of systemd-run's stderr. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent ef6623d commit fde9bfd

2 files changed

Lines changed: 28 additions & 1 deletion

File tree

‎engine/ansible/roles/cloudfall_deploy/tasks/release_command.yml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@
8080
on {{ cloudfall_server_id }}; no server switched to release
8181
{{ cloudfall_deploy_release }}. Output ends: {{
8282
cloudfall_deploy_release_run.stdout[-cloudfall_deploy_release_failure_characters:]
83+
}} systemd-run reported: {{
84+
cloudfall_deploy_release_run.stderr[-cloudfall_deploy_release_failure_characters:]
8385
}}
8486
when: >-
8587
cloudfall_deploy_release_timed_out

‎engine/tests/test_release_command.py‎

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
SWITCH = "Switch the current release symlink"
4242
RECEIPT = "Write the release receipt on the controller"
4343
TIMEOUT_MARKER = "cloudfall-test-timeout"
44+
REFUSED_MARKER = "cloudfall-test-refused"
4445

4546
FAKE_SYSTEMD_RUN = f"""#!/bin/sh
4647
# Stand-in for systemd-run --wait --pipe: chdir like --working-directory,
@@ -55,6 +56,10 @@
5556
done
5657
shift
5758
cd "$directory" || exit 200
59+
if [ -f "$directory/{REFUSED_MARKER}" ]; then
60+
echo "Failed to start transient service unit: Unit already exists." >&2
61+
exit 1
62+
fi
5863
"$@"
5964
status=$?
6065
if [ -f "$directory/{TIMEOUT_MARKER}" ]; then
@@ -129,12 +134,18 @@ def _local_inventory(tmp_path: Path) -> Path:
129134

130135

131136
def _run_release_command(
132-
tmp_path: Path, arguments: list[str], *, timed_out: bool = False
137+
tmp_path: Path,
138+
arguments: list[str],
139+
*,
140+
timed_out: bool = False,
141+
refused: bool = False,
133142
) -> tuple[int, Path]:
134143
"""Run the role's release command tasks; answer the exit code and result."""
135144
release_directory, working_directory, systemd_run = _release_tree(tmp_path)
136145
if timed_out:
137146
(working_directory / TIMEOUT_MARKER).write_text("", encoding="utf-8")
147+
if refused:
148+
(working_directory / REFUSED_MARKER).write_text("", encoding="utf-8")
138149
result_file = tmp_path / "result.json"
139150
variables = {
140151
"cloudfall_server_id": "b",
@@ -297,6 +308,20 @@ def test_s005_5_a_timed_out_release_command_fails_naming_the_timeout(
297308
assert "timed out after 300 seconds and was stopped" in output
298309

299310

311+
def test_s005_4_a_unit_that_never_starts_names_systemd_run_s_reason(
312+
tmp_path: Path, capsys: pytest.CaptureFixture[str]
313+
) -> None:
314+
"""A unit that never starts fails with systemd-run's own message."""
315+
exit_code, result_file = _run_release_command(tmp_path, ["0"], refused=True)
316+
317+
assert exit_code == 82
318+
output = _captured_output(capsys)
319+
assert "exited with code 1" in output
320+
assert "Failed to start transient service unit" in output
321+
assert not (tmp_path / "releases" / "20261027T000000Z-abcdef1" / "table").exists()
322+
assert not result_file.exists()
323+
324+
300325
def test_s005_5_the_timeout_is_the_unit_runtime_limit(tmp_path: Path) -> None:
301326
_run_release_command(tmp_path, ["0"])
302327

0 commit comments

Comments
 (0)