From 4225cc759fe591d79365080061751fe034443d8b Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Thu, 22 May 2025 02:45:55 +0200 Subject: [PATCH] Introduce stateVersion concept With upcoming changes to the dovecot home and maildirectories we need to introduce a way to nudge users to inform themselves about manual migration steps they might need to carry out. --- default.nix | 14 ++++++++++++++ docs/howto-develop.rst | 33 +++++++++++++++++++++++++++++++++ docs/index.rst | 1 + docs/migrations.rst | 22 ++++++++++++++++++++++ docs/setup-guide.rst | 1 + mail-server/assertions.nix | 7 ++++++- tests/lib/config.nix | 7 ++++++- tests/minimal.nix | 5 ++++- tests/multiple.nix | 5 ++++- 9 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 docs/migrations.rst diff --git a/default.nix b/default.nix index aaa0987..94e83b8 100644 --- a/default.nix +++ b/default.nix @@ -25,6 +25,20 @@ in options.mailserver = { enable = mkEnableOption "nixos-mailserver"; + stateVersion = mkOption { + type = types.nullOr types.ints.positive; + default = null; + description = '' + Tracking stateful version changes as an incrementing number. + + When a new release comes out we may require manual migration steps to + be completed, before the new version can be put into production. + + If your `stateVersion` is too low one or multiple assertions may + trigger to give a hint on what migrations are missing. + ''; + }; + openFirewall = mkOption { type = types.bool; default = true; diff --git a/docs/howto-develop.rst b/docs/howto-develop.rst index 40527f9..aa1e558 100644 --- a/docs/howto-develop.rst +++ b/docs/howto-develop.rst @@ -64,3 +64,36 @@ To build the documentation, you need to enable `Nix Flakes $ nix build .#documentation $ xdg-open result/index.html + + +Manual migrations +----------------- + +We need to take great care around providing a migration story around breaking +changes. If manual intervention becomes necessary we provide the `stateVersion` +option, to notify the user that they need to complete a migration before +they deploy an update. + +If that is the case for your change, find the highest `stateVersion` that is +being asserted on in `mail-server/assertions.nix`. Then pick the next number +and add a new assertion, write a good summary what about the issue and what +remediation steps are necessary. Finally reference the URL to the specific +section on the migration page in the documentation. + +.. code-block:: nix + + { + assertions = [ + { + assertion = config.mailserver.stateVersion < 1; + message = "Migration step required: Move files from this location to that location, then bump the `stateVersion` to `1`. Check https://nixos-mailserver.readthedocs.io/en/latest/migrations.html for more details." + } + ]; + } + +The setup guide should always reference the latest `stateVersion`, since we +don't require any migration steps for new setups. + +The migration documentation should paint a more complete picture about the steps +that need to be carried out and why this has become necessary. Make sure to +referenc the correct anchor in the URL you put into the assertionn message. diff --git a/docs/index.rst b/docs/index.rst index 2fd1e1a..d31ed27 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,6 +18,7 @@ Welcome to NixOS Mailserver's documentation! faq release-notes options + migrations .. toctree:: :maxdepth: 1 diff --git a/docs/migrations.rst b/docs/migrations.rst new file mode 100644 index 0000000..0631b1a --- /dev/null +++ b/docs/migrations.rst @@ -0,0 +1,22 @@ +Migrations +========== + +With mailserver configuration best practices changing over time migrations are +a required step to complete before updating to a new version of NixOS +mailserver. + +The initial `mailserver.stateVersion` value should be copied from the setup +guide that you used to initially set up your mailserver. If in doubt you can +always initialize it at `1` and walk through all assertions, that might apply +to your setup. + +NixOS 25.11 +----------- + +This option was introduced in the NixOS 25.11 release cycle, in which case you +can safely initialize its value at `1`. + +:: code-block: nix + + mailserver.stateVersion = 1; + diff --git a/docs/setup-guide.rst b/docs/setup-guide.rst index 5f6f903..f92ef20 100644 --- a/docs/setup-guide.rst +++ b/docs/setup-guide.rst @@ -72,6 +72,7 @@ common ones. mailserver = { enable = true; + stateVersion = 1; fqdn = "mail.example.com"; domains = [ "example.com" ]; diff --git a/mail-server/assertions.nix b/mail-server/assertions.nix index 91921c6..b30ccaa 100644 --- a/mail-server/assertions.nix +++ b/mail-server/assertions.nix @@ -1,6 +1,11 @@ { config, lib, ... }: { - assertions = lib.optionals config.mailserver.ldap.enable [ + assertions = lib.optionals config.mailserver.enable [ + { + assertion = config.mailserver.stateVersion != null; + message = "The `mailserver.stateVersion` option is not set. Check https://nixos-mailserver.readthedocs.io/en/latest/migrations.html to determine the proper value to initialize it at."; + } + ] ++ lib.optionals config.mailserver.ldap.enable [ { assertion = config.mailserver.loginAccounts == {}; message = "When the LDAP support is enable (mailserver.ldap.enable = true), it is not possible to define mailserver.loginAccounts"; diff --git a/tests/lib/config.nix b/tests/lib/config.nix index 68a1b2e..2d4828d 100644 --- a/tests/lib/config.nix +++ b/tests/lib/config.nix @@ -1,3 +1,8 @@ { - security.dhparams.defaultBitSize = 2048; # minimum size required by dovecot + # Update this to the latest stateVersion when introducing a new migration step + # https://nixos-mailserver.readthedocs.io/en/latest/migrations.html + mailserver.stateVersion = 1; + + # minimum size required by dovecot + security.dhparams.defaultBitSize = 2048; } diff --git a/tests/minimal.nix b/tests/minimal.nix index 407f221..e78814e 100644 --- a/tests/minimal.nix +++ b/tests/minimal.nix @@ -18,7 +18,10 @@ name = "minimal"; nodes.machine = { - imports = [ ./../default.nix ]; + imports = [ + ../default.nix + ./lib/config.nix + ]; }; testScript = '' diff --git a/tests/multiple.nix b/tests/multiple.nix index 2427feb..3e71cd6 100644 --- a/tests/multiple.nix +++ b/tests/multiple.nix @@ -16,7 +16,10 @@ let password = pkgs.writeText "password" "password"; domainGenerator = domain: { pkgs, ... }: { - imports = [../default.nix]; + imports = [ + ../default.nix + ./lib/config.nix + ]; environment.systemPackages = with pkgs; [ netcat ]; virtualisation.memorySize = 1024; mailserver = {