From d6d2053b8006af17c69155bc8b9c34269202feea Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Sun, 6 Jul 2025 23:57:22 +0200 Subject: [PATCH] dovecot: use marker option as unit name migration indicator In nixpkgs we expose `services.dovecot.hasNewUnitName` option that can be safely inspected to understand that whether to use the `dovecot` systemd service name instead of `dovecot2`. --- mail-server/common.nix | 3 +++ mail-server/dovecot.nix | 27 +++++++++++-------- mail-server/nginx.nix | 12 +++++++-- mail-server/postfix.nix | 10 ++++++- mail-server/systemd.nix | 58 ++++++++++++++++++++++++----------------- mail-server/users.nix | 12 ++++++++- tests/external.nix | 12 ++++----- 7 files changed, 89 insertions(+), 45 deletions(-) diff --git a/mail-server/common.nix b/mail-server/common.nix index cb044b6..4247360 100644 --- a/mail-server/common.nix +++ b/mail-server/common.nix @@ -16,6 +16,7 @@ { config, + options, pkgs, lib, }: @@ -86,4 +87,6 @@ in chmod 600 ${destination} ''; + dovecotUnitName = if options.services.dovecot2 ? hasNewUnitName then "dovecot" else "dovecot2"; + } diff --git a/mail-server/dovecot.nix b/mail-server/dovecot.nix index 5535eaa..33e7f4c 100644 --- a/mail-server/dovecot.nix +++ b/mail-server/dovecot.nix @@ -16,22 +16,24 @@ { config, + options, pkgs, lib, ... }: -with (import ./common.nix { inherit config pkgs lib; }); +with (import ./common.nix { + inherit + config + options + pkgs + lib + ; +}); let cfg = config.mailserver; - dovecotPreStart = - '' - ${genPasswdScript} - '' - + (lib.optionalString cfg.ldap.enable setPwdInLdapConfFile); - passwdDir = "/run/dovecot2"; passwdFile = "${passwdDir}/passwd"; userdbFile = "${passwdDir}/userdb"; @@ -445,10 +447,13 @@ in ''; }; - systemd.services.dovecot.preStart = lib.mkIf (config.systemd.services ? "dovecot") dovecotPreStart; - systemd.services.dovecot2.preStart = lib.mkIf ( - config.systemd.services ? "dovecot2" - ) dovecotPreStart; + systemd.services.${dovecotUnitName} = { + preStart = + '' + ${genPasswdScript} + '' + + (lib.optionalString cfg.ldap.enable setPwdInLdapConfFile); + }; systemd.services.postfix.restartTriggers = [ genPasswdScript diff --git a/mail-server/nginx.nix b/mail-server/nginx.nix index 27de2fe..75ebc4c 100644 --- a/mail-server/nginx.nix +++ b/mail-server/nginx.nix @@ -16,12 +16,20 @@ { config, + options, pkgs, lib, ... }: -with (import ./common.nix { inherit config lib pkgs; }); +with (import ./common.nix { + inherit + config + options + lib + pkgs + ; +}); let cfg = config.mailserver; @@ -42,7 +50,7 @@ in security.acme.certs."${cfg.acmeCertificateName}".reloadServices = [ "postfix.service" - "dovecot2.service" + "${dovecotUnitName}.service" ]; }; } diff --git a/mail-server/postfix.nix b/mail-server/postfix.nix index edb3a11..79b2eca 100644 --- a/mail-server/postfix.nix +++ b/mail-server/postfix.nix @@ -16,12 +16,20 @@ { config, + options, pkgs, lib, ... }: -with (import ./common.nix { inherit config pkgs lib; }); +with (import ./common.nix { + inherit + config + options + lib + pkgs + ; +}); let inherit (lib.strings) concatStringsSep; diff --git a/mail-server/systemd.nix b/mail-server/systemd.nix index 5c9c670..5f6fd4a 100644 --- a/mail-server/systemd.nix +++ b/mail-server/systemd.nix @@ -16,11 +16,21 @@ { config, + options, pkgs, lib, ... }: +with (import ./common.nix { + inherit + config + options + lib + pkgs + ; +}); + let cfg = config.mailserver; certificatesDeps = @@ -31,25 +41,6 @@ let else [ "acme-finished-${cfg.fqdn}.target" ]; - dovecotUnitSettings = { - wants = certificatesDeps; - after = certificatesDeps; - preStart = - let - directories = lib.strings.escapeShellArgs ( - [ cfg.mailDirectory ] ++ lib.optional (cfg.indexDir != null) cfg.indexDir - ); - in - '' - # Create mail directory and set permissions. See - # . - # Prevent world-readable paths, even temporarily. - umask 007 - mkdir -p ${directories} - chgrp "${cfg.vmailGroupName}" ${directories} - chmod 02770 ${directories} - ''; - }; in { config = lib.mkIf cfg.enable { @@ -80,15 +71,34 @@ in }; # Create maildir folder before dovecot startup - systemd.services.dovecot = dovecotUnitSettings; - # TODO: remove after 25.11 release - systemd.services.dovecot2 = dovecotUnitSettings; + systemd.services.${dovecotUnitName} = { + wants = certificatesDeps; + after = certificatesDeps; + preStart = + let + directories = lib.strings.escapeShellArgs ( + [ cfg.mailDirectory ] ++ lib.optional (cfg.indexDir != null) cfg.indexDir + ); + in + '' + # Create mail directory and set permissions. See + # . + # Prevent world-readable paths, even temporarily. + umask 007 + mkdir -p ${directories} + chgrp "${cfg.vmailGroupName}" ${directories} + chmod 02770 ${directories} + ''; + }; # Postfix requires dovecot lmtp socket, dovecot auth socket and certificate to work systemd.services.postfix = { wants = certificatesDeps; - after = [ "dovecot2.service" ] ++ lib.optional cfg.dkimSigning "rspamd.service" ++ certificatesDeps; - requires = [ "dovecot2.service" ] ++ lib.optional cfg.dkimSigning "rspamd.service"; + after = + [ "${dovecotUnitName}.service" ] + ++ lib.optional cfg.dkimSigning "rspamd.service" + ++ certificatesDeps; + requires = [ "${dovecotUnitName}.service" ] ++ lib.optional cfg.dkimSigning "rspamd.service"; }; }; } diff --git a/mail-server/users.nix b/mail-server/users.nix index e9af05a..b08e3b5 100644 --- a/mail-server/users.nix +++ b/mail-server/users.nix @@ -16,11 +16,21 @@ { config, + options, pkgs, lib, ... }: +with (import ./common.nix { + inherit + config + options + lib + pkgs + ; +}); + with config.mailserver; let @@ -107,7 +117,7 @@ in systemd.services.activate-virtual-mail-users = { wantedBy = [ "multi-user.target" ]; - before = [ "dovecot2.service" ]; + before = [ "${dovecotUnitName}.service" ]; serviceConfig = { ExecStart = virtualMailUsersActivationScript; }; diff --git a/tests/external.nix b/tests/external.nix index c01f9ac..842e62c 100644 --- a/tests/external.nix +++ b/tests/external.nix @@ -490,9 +490,9 @@ server.wait_until_fails('[ "$(postqueue -p)" != "Mail queue is empty" ]') client.succeed("imap-mark-spam >&2") - server.wait_until_succeeds("journalctl -u dovecot2 | grep -i rspamd-learn-spam.sh >&2") + server.wait_until_succeeds("journalctl -u dovecot -u dovecot2 | grep -i rspamd-learn-spam.sh >&2") client.succeed("imap-mark-ham >&2") - server.wait_until_succeeds("journalctl -u dovecot2 | grep -i rspamd-learn-ham.sh >&2") + server.wait_until_succeeds("journalctl -u dovecot -u dovecot2 | grep -i rspamd-learn-ham.sh >&2") with subtest("full text search and indexation"): # send 2 email from user2 to user1 @@ -510,9 +510,9 @@ # should fail because this folder is not indexed client.fail("search Junk a >&2") # check that search really goes through the indexer - server.succeed("journalctl -u dovecot2 | grep 'fts-flatcurve(INBOX): Query ' >&2") + server.succeed("journalctl -u dovecot -u dovecot2 | grep 'fts-flatcurve(INBOX): Query ' >&2") # check that Junk is not indexed - server.fail("journalctl -u dovecot2 | grep 'fts-flatcurve(JUNK): Indexing ' >&2") + server.fail("journalctl -u dovecot -u dovecot2 | grep 'fts-flatcurve(JUNK): Indexing ' >&2") with subtest("dmarc reporting"): server.systemctl("start rspamd-dmarc-reporter.service") @@ -520,10 +520,10 @@ with subtest("no warnings or errors"): server.fail("journalctl -u postfix | grep -i error >&2") server.fail("journalctl -u postfix | grep -i warning >&2") - server.fail("journalctl -u dovecot2 | grep -v 'imap-login: Debug: SSL error: Connection closed' | grep -i error >&2") + server.fail("journalctl -u dovecot -u dovecot2 | grep -v 'imap-login: Debug: SSL error: Connection closed' | grep -i error >&2") # harmless ? https://dovecot.org/pipermail/dovecot/2020-August/119575.html server.fail( - "journalctl -u dovecot2 | \ + "journalctl -u dovecot -u dovecot2 | \ grep -v 'Expunged message reappeared, giving a new UID' | \ grep -v 'Time moved forwards' | \ grep -i warning >&2"