Repository navigation
Keep a hand-made unit and restore it when a first release fails (#151) - #154
Conversation
The deploy role keeps a same-name unit without the Cloudfall header at <name>.service.pre-cloudfall, records whether it was enabled and active, and on a failed first release copies it back, restores its enabled state and starts it when it was running. Check mode reports the unit it would keep. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The S-002-12 harness runs "Compute release paths" with a component that declares no service, so templating the unit paths there failed the play. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@romamo Decided without waiting: a first deploy keeps a hand-made unit at Why: it fixes #151 additively; components whose unit Cloudfall already manages deploy exactly as before, and the refusal keeps the copy equal to the unit it replaced, so a restore never puts back an older unit. The enabled state comes back as enabled or disabled, so a unit in a rarer state such as Reply with a comment starting with |
Summary
A first deploy over a hand-made systemd unit of the same name (e.g.
asrest.service, adopted on a brownfield move) no longer loses it when the release fails its health gate.# Managed by Cloudfall, it recordssystemctl is-enabled/is-active(exit codes read, never failing) and copies it withremote_srcto/etc/systemd/system/<name>.service.pre-cloudfall, root:root 0644,force: falserescueblock, a failed first release over a kept unit is stopped as before, then the kept unit is copied back, systemd is reloaded, its enabled state is restored, and it is started when it was active. The fail message says the pre-Cloudfall unit was restored. Without a kept unit, the first-release path is unchanged, and so is the rollback-to-previous-release pathdebugtask reports the unit a deploy would keep; nothing is copiedengine/README.mddescribes the new behaviour; changelog fragmentchangelog.d/151-keep-hand-made-unit.mdTests
uv run ruff check .,uv run mypy,uv run pytest engine/tests/test_deploy_role.py engine/tests/test_release_command.pypassengine/tests/test_deploy_role.pyreplay the role's decisions with Ansible's own templating, as the existing tests there do. They cover: hand-made vs managed vs missing unit detection, which adoption tasks run normally and in check mode, the copy settings, the stale-copy refusal, which rescue steps run (restore and start, restore and leave stopped, no resurrection over a managed unit, rollback unchanged, nothing in check mode), the enabled-state command, and the fail messagesansible-lintwithANSIBLE_CONFIGwas not run locally (permission denied in the session); CI runs itDecisions for you
.pre-cloudfallcopy already on disk, the deploy now fails before installing anything. Withforce: falsethe old copy would otherwise be restored over the newer unitcurrentremoved by hand): an old.pre-cloudfallcopy is not restored. Restore only happens when this run found a hand-made unitsystemctl reenableif it wasenabled, otherwisesystemctl disable. This removes themulti-user.target.wantslink the deploy added. Side effect: rarer states (static, indirect, enabled-runtime) end up disabledcurrentsymlink and the release directory stay, as todayansible-lintwith the config, the CI syntax-check, and a real systemd run (reenable/disableon a static unit,daemon-reloadwith no unit name)Fixes #151
🤖 Generated with Claude Code