diff --git a/default.nix b/default.nix index aaa0987..71effa0 100644 --- a/default.nix +++ b/default.nix @@ -25,6 +25,22 @@ 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 you instructions on what migrations steps are required + to continue. Increase the `stateVersion` as instructed by the assertion + message. + ''; + }; + openFirewall = mkOption { type = types.bool; default = true; diff --git a/docs/howto-develop.rst b/docs/howto-develop.rst index 40527f9..4261418 100644 --- a/docs/howto-develop.rst +++ b/docs/howto-develop.rst @@ -64,3 +64,44 @@ 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 can 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 describing 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 = '' + Problem: The home directory for the foobar service is snafu. + Remediation: + - Stop the `foobar.service` + - Rename `/var/lib/foobaz` to `/var/lib/foobar` + - Increase the `mailserver.stateVersion` to 1. + + Check https://nixos-mailserver.readthedocs.io/en/latest/migrations.html#specific-anchor-here for further 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 +reference the correct anchor in the URL you put into the assertion 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..bd52196 --- /dev/null +++ b/docs/migrations.rst @@ -0,0 +1,22 @@ +Migrations +========== + +With mail server configuration best practices changing over time we might need +to make changes that require you to complete manual migration steps before you +can deploy 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 mail server. 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..09ae517 100644 --- a/tests/lib/config.nix +++ b/tests/lib/config.nix @@ -1,3 +1,7 @@ { - security.dhparams.defaultBitSize = 2048; # minimum size required by dovecot + # Testing eval failures that result from stateVersion assertion is out of scope + mailserver.stateVersion = 999; + + # 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 = {