Skip to content

fix(debian): upgrades keep a service the admin disabled - 7.3.7 - #11

Merged
ks98 merged 5 commits into
mainfrom
fix/dienst-zustand
Sep 28, 2026
Merged

ks98 merged 5 commits into
mainfrom
fix/dienst-zustand

Conversation

@ks98

@ks98 ks98 commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Upgrades respect a service the admin switched off (linuxmusterDEV work/plans/dienst-zustand-upgrade.md, approved by Kevin: "mache Debian-Regeln"). Version 7.3.7 (dist lmn73). The service-state logic is the same in linuxmuster-squid and linuxmuster-radius, word for word apart from the names.

Why

Up to 7.3.6 every configure ran systemctl enable and started linuxmuster-squid.service, then ran the instance update through it. An admin's systemctl disable --now was undone by the next upgrade. Debian's rule (dh_installsystemd, deb-systemd-helper) is to keep the local admin's decision.

What

  • postinst: deb-systemd-helper unmask, then enable when was-enabled, else update-state (also without a running systemd: an image or chroot gets the links, the service starts with the next boot). With systemd running: an enabled unit gets deb-systemd-invoke restart on upgrade (start on a new installation); a disabled or masked one only try-restart (still running: new code; stopped: stays stopped). The instance update (lmnsquid update-all, reconcile) runs only when the service runs after the configure; otherwise apt shows one line: linuxmuster-squid: the service is disabled and not running, instances not updated; run 'lmnsquid update-all' after starting it.
  • preinst (new), one-time transition: 7.3.6 and older never recorded deb-systemd-helper state, and without it was-enabled answers "enabled" even for a disabled unit. On upgrade without recorded state it records the current state (enabled -> enable; otherwise update-state, the latter only while systemd runs, since the old postinst never enabled the unit without systemd). A reinstall from config-files (install <old>) is a new installation (the old prerm had disabled the unit, not the admin).
  • prerm remove: deb-systemd-invoke stop only (no more disable). postrm purge: deb-systemd-helper purge. No mask on remove and no unmask on purge, as debhelper 13.14's dh_installsystemd snippets (Ubuntu 24.04; masking was dropped in 13.10, Debian #1021027, it only guarded sysv init scripts, which these packages do not have). Kept from those snippets: postinst deb-systemd-helper unmask (lifts only a mask deb-systemd-helper set itself) + enable/update-state, prerm stop on remove only, postrm purge. The decision survives remove + reinstall (the enable link and the recorded state stay until purge).
  • Units stay in /lib/systemd/system, dh_installsystemd stays off (usrmerge risk of moving a unit within a package).
  • debian/changelog 7.3.7, docs/operations.md "Keeping the service off" (how to keep the service off, what remove/purge/downgrade do), docs/install.md.
  • CI: upgrade-smoke (ci.yml and release.yml, same step, no new or renamed job, the required checks stay as they are) gets the permanent case "disabled before the upgrade stays disabled and stopped": purge, install the published release, systemctl disable --now, upgrade to the build twice; each time disabled + inactive, no start in the journal since the upgrade began, the hint line in the apt output; the deb-systemd-helper state exists afterwards. The fast tier shellchecks debian/preinst too.

Measured before writing it (ubuntu:24.04, init-system-helpers 1.66ubuntu1, systemd 255 as PID 1)

unit deb-systemd-invoke start restart try-restart
enabled, running no-op restarted restarted
enabled, stopped started started stays stopped
disabled, running no-op + "not starting it" restarted, stays disabled restarted
disabled, stopped stays stopped + message stays stopped + message stays stopped, silent
masked, stopped message message silent
masked, running message exit 1 "Unit is masked" silent, not restarted

With /usr/sbin/policy-rc.d (exit 101, as in the docker image) deb-systemd-invoke does nothing and says so. systemctl is-enabled and deb-systemd-helper work without a running systemd (read/write the links).

Tests

  • Container matrix (systemd as PID 1 without --privileged, Docker API stub), every row of the plan's table, from the published release and twice in a row (release -> 7.3.7 -> 7.3.7+t1 test build), plus remove/reinstall from config-files, remove/reinstall of 7.3.7 (enabled and disabled), purge/reinstall, masked (stopped and running), no running systemd (fresh, upgrade, boot of the result), policy-rc.d, no Docker, dpkg-reconfigure, downgrade to 7.3.6: all rows pass. Details, commands and logs: linuxmusterDEV work/campaign/dienst-zustand-2026-09-28.md.
  • The .deb of this PR's CI run (36438329873, job package) differs from the release v7.3.6 only in the maintainer scripts (+ preinst), changelog.gz, the own dist-info (METADATA, RECORD) and control/md5sums (sha256 of every file compared); the file tree (mode/owner/path) is identical.
  • Fast tier locally in the lmndev-runner image: lock gate, ruff, mypy, pytest, shellcheck, reuse all green.

A downgrade to 7.3.6 or older brings the old behaviour back (it enables and starts the service); the changelog says so.

Kevin Stenzel added 5 commits September 28, 2026 15:56
Up to 7.3.6 every configure ran `systemctl enable` and started the service,
so an admin's `systemctl disable --now` was undone by the next upgrade.
The maintainer scripts now follow Debian's rules the way the
dh_installsystemd snippets do, still by hand because the unit stays in
/lib/systemd/system:

* postinst: deb-systemd-helper unmask, then enable when was-enabled,
  update-state otherwise (links are made without a running systemd too).
  With systemd running: an enabled unit is restarted on upgrade (started
  on a new installation) with deb-systemd-invoke; a disabled or masked one
  only gets try-restart (a running one loads the new code, a stopped one
  stays stopped). The instance update runs only when the service runs
  after the configure, otherwise apt shows one line saying so.
* preinst (new): one-time transition. 7.3.6 and older never recorded
  deb-systemd-helper state, and without it was-enabled says "enabled"
  even for a disabled unit. On an upgrade without recorded state the
  current state is recorded (enabled -> enable, otherwise update-state;
  the latter only while systemd runs: without it the old postinst never
  enabled the unit). A reinstall from config-files is not an upgrade.
* prerm remove: deb-systemd-invoke stop only (no disable).
* postrm remove: deb-systemd-helper mask; purge: purge + unmask.

Measured in a systemd container (ubuntu:24.04, init-system-helpers
1.66ubuntu1): deb-systemd-invoke restart of a masked running unit fails
and of a disabled stopped one prints "not starting it", try-restart is
silent in both, so only enabled units get restart/start.

debian/changelog: 7.3.7 (lmn73).
A permanent case in upgrade-smoke (ci.yml and release.yml, same step in
both, no new job, so the required checks stay as they are): purge,
install the published release, `systemctl disable --now`, then upgrade to
the built package twice. After each upgrade the unit is disabled and
inactive, the journal shows no start since the upgrade began, and apt
printed the "instances not updated" line; afterwards deb-systemd-helper
holds the recorded state. The fast tier shellchecks debian/preinst too.
lintian warned command-with-path-in-maintainer-script for the
`[ -x /usr/bin/deb-systemd-helper ]` tests (dh_installsystemd's own
snippets are exempt as generated code). init-system-helpers is Essential
on Ubuntu 24.04, and `|| true` already covers a missing command.
…pets

debhelper 13.10 stopped masking system units on package removal (Debian
#1021027: the mask only kept a left-over sysv init script from starting,
and these packages ship none), and its purge snippet runs only
`deb-systemd-helper purge`. Ubuntu 24.04 has 13.14, so the postrm no
longer masks on remove and no longer unmasks on purge. What the 13.14
snippets still do stays: postinst `deb-systemd-helper unmask` (lifts only
a mask deb-systemd-helper set itself) followed by enable/update-state,
prerm `deb-systemd-invoke stop` on remove only, postrm
`deb-systemd-helper purge` on purge (the daemon-reload stays as before).
The decision still survives remove + reinstall: the prerm only stops the
service and the enable link and the recorded state stay until purge.
docs/operations.md no longer says the unit stays masked while removed.
…-all ran on upgrades

From the cold verification (linuxmusterDEV work/verification/
cold-dienst-zustand.md), text only:
* The changelog and docs/operations.md now state the one exception the
  preinst makes on purpose: when the one-time transition runs without a
  running systemd (an image build, a chroot), a service without an enable
  link is treated like a new installation and enabled, because the old
  postinst never enabled it offline. Online upgrades and every later
  upgrade keep an admin-disabled service off.
* The old postinst updated the instances on every upgrade (and on
  dpkg-reconfigure, which also passes the installed version), never on a
  new installation; the changelog no longer says "every install".
The entry keeps its version and date.
@ks98
ks98 merged commit e2e0e49 into main Sep 28, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant