mirror of
https://github.com/chatmail/relay.git
synced 2026-05-10 16:04:37 +00:00
fix(cmdeploy): Install dovecot .deb packages atomically
Since change 635ac7 we try to install Dovecot, even if it is already
running, which fails Dovecot upgrades fail when the installed version
differs from the target because dovecot-imapd/lmtpd dependencies
on dovecot-core: packages are installed one at a time via apt.deb(),
i.e. `dpkg -i`, and dpkg cannot satisfy them dependencies:
```
dpkg: dependency problems prevent configuration of dovecot-imapd:
dovecot-imapd depends on dovecot-core (= 1:2.3.21+dfsg1-3); however:
Version of dovecot-core on system is 1:2.3.21.1+dfsg1-1~bpo12+1.
```
Split _install_dovecot_package into _download_dovecot_package (download
only, return path) and a single server.shell call that passes all .deb
files to dpkg -i together. Uses the same 3-step pattern as pyinfra's
apt.deb: tolerant first dpkg -i, apt-get --fix-broken, then final
dpkg -i to fail if there are still errors.
This commit is contained in:
@@ -38,9 +38,21 @@ class DovecotDeployer(Deployer):
|
|||||||
def install(self):
|
def install(self):
|
||||||
arch = host.get_fact(Arch)
|
arch = host.get_fact(Arch)
|
||||||
with blocked_service_startup():
|
with blocked_service_startup():
|
||||||
_install_dovecot_package("core", arch)
|
debs = []
|
||||||
_install_dovecot_package("imapd", arch)
|
for pkg in ("core", "imapd", "lmtpd"):
|
||||||
_install_dovecot_package("lmtpd", arch)
|
deb = _download_dovecot_package(pkg, arch)
|
||||||
|
if deb:
|
||||||
|
debs.append(deb)
|
||||||
|
if debs:
|
||||||
|
deb_list = " ".join(debs)
|
||||||
|
server.shell(
|
||||||
|
name="Install dovecot packages",
|
||||||
|
commands=[
|
||||||
|
f"dpkg --force-confdef --force-confold -i {deb_list} 2> /dev/null || true",
|
||||||
|
"DEBIAN_FRONTEND=noninteractive apt-get -y --fix-broken install",
|
||||||
|
f"dpkg --force-confdef --force-confold -i {deb_list}",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def configure(self):
|
def configure(self):
|
||||||
configure_remote_units(self.config.mail_domain, self.units)
|
configure_remote_units(self.config.mail_domain, self.units)
|
||||||
@@ -73,7 +85,8 @@ def _pick_url(primary, fallback):
|
|||||||
return fallback
|
return fallback
|
||||||
|
|
||||||
|
|
||||||
def _install_dovecot_package(package: str, arch: str):
|
def _download_dovecot_package(package: str, arch: str):
|
||||||
|
"""Download a dovecot .deb if needed, return its path (or None)."""
|
||||||
arch = "amd64" if arch == "x86_64" else arch
|
arch = "amd64" if arch == "x86_64" else arch
|
||||||
arch = "arm64" if arch == "aarch64" else arch
|
arch = "arm64" if arch == "aarch64" else arch
|
||||||
|
|
||||||
@@ -81,11 +94,11 @@ def _install_dovecot_package(package: str, arch: str):
|
|||||||
sha256 = DOVECOT_SHA256.get((package, arch))
|
sha256 = DOVECOT_SHA256.get((package, arch))
|
||||||
if sha256 is None:
|
if sha256 is None:
|
||||||
apt.packages(packages=[pkg_name])
|
apt.packages(packages=[pkg_name])
|
||||||
return
|
return None
|
||||||
|
|
||||||
installed_versions = host.get_fact(DebPackages).get(pkg_name, [])
|
installed_versions = host.get_fact(DebPackages).get(pkg_name, [])
|
||||||
if DOVECOT_VERSION in installed_versions:
|
if DOVECOT_VERSION in installed_versions:
|
||||||
return
|
return None
|
||||||
|
|
||||||
url_version = DOVECOT_VERSION.replace("+", "%2B")
|
url_version = DOVECOT_VERSION.replace("+", "%2B")
|
||||||
deb_base = f"{pkg_name}_{url_version}_{arch}.deb"
|
deb_base = f"{pkg_name}_{url_version}_{arch}.deb"
|
||||||
@@ -102,7 +115,7 @@ def _install_dovecot_package(package: str, arch: str):
|
|||||||
cache_time=60 * 60 * 24 * 365 * 10, # never redownload the package
|
cache_time=60 * 60 * 24 * 365 * 10, # never redownload the package
|
||||||
)
|
)
|
||||||
|
|
||||||
apt.deb(name=f"Install {pkg_name}", src=deb_filename)
|
return deb_filename
|
||||||
|
|
||||||
|
|
||||||
def _configure_dovecot(config: Config, debug: bool = False) -> (bool, bool):
|
def _configure_dovecot(config: Config, debug: bool = False) -> (bool, bool):
|
||||||
|
|||||||
Reference in New Issue
Block a user