From 1ae92e0639c952bc263ebfaa80949aefa6dff782 Mon Sep 17 00:00:00 2001 From: j4n Date: Thu, 16 Apr 2026 14:17:53 +0200 Subject: [PATCH] fix(cmdeploy/dovecot): detect stale dovecot binary and force restart in activate() When a previous deploy installed dovecot packages but the restart was blocked (policy-rc.d) or the deploy aborted before activate(), the next deploy sees the correct package version already installed and skips restart. Extend activate() to check /proc/MainPID/exe for "(deleted)" before the restart decision. --- cmdeploy/src/cmdeploy/dovecot/deployer.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cmdeploy/src/cmdeploy/dovecot/deployer.py b/cmdeploy/src/cmdeploy/dovecot/deployer.py index 56e259a4..0b9b7764 100644 --- a/cmdeploy/src/cmdeploy/dovecot/deployer.py +++ b/cmdeploy/src/cmdeploy/dovecot/deployer.py @@ -4,7 +4,7 @@ import urllib.request from chatmaild.config import Config from pyinfra import host from pyinfra.facts.deb import DebPackages -from pyinfra.facts.server import Arch, Sysctl +from pyinfra.facts.server import Arch, Command, Sysctl from pyinfra.operations import apt, files, server, systemd from cmdeploy.basedeploy import ( @@ -80,6 +80,17 @@ class DovecotDeployer(Deployer): def activate(self): activate_remote_units(self.units) + # Detect stale binary: package installed but service still runs old (deleted) binary. + if not self.disable_mail and not self.need_restart: + stale = host.get_fact( + Command, + 'pid=$(systemctl show -p MainPID --value dovecot.service 2>/dev/null);' + ' [ "${pid:-0}" != "0" ] && readlink "/proc/$pid/exe" 2>/dev/null | grep -q "(deleted)"' + " && echo STALE || true", + ) + if stale == "STALE": + self.need_restart = True + restart = False if self.disable_mail else self.need_restart systemd.service(