Upgrade Mailman from 20.03 to 20.09?

I tried (without success) to migrate a NixOS server running mailman from 20.03 to 20.09.

My 20.03 config was as follows:

{ config, pkgs, ... }:

let
  OWNER_EMAIL = "mailman@example.com";
  MAILMAN_HOST = "mailman.example.com";
in

{
  # ...

  services.postfix = {
    enable = true;
    relayDomains = ["hash:/var/lib/mailman/data/postfix_domains"];
    sslCert = config.security.acme.certs.${MAILMAN_HOST}.directory + "/full.pem";
    sslKey = config.security.acme.certs.${MAILMAN_HOST}.directory + "/key.pem";
    config = {
      transport_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
      local_recipient_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
    };
  };

  services.mailman = {
    enable = true;
    siteOwner = OWNER_EMAIL;
    webUser = config.services.uwsgi.user;
    hyperkitty.enable = true;
    # Have mailman talk directly to hyperkitty, bypassing nginx:
    hyperkitty.baseUrl = "http://localhost:33141/hyperkitty/";
    webHosts = [MAILMAN_HOST];
  };

  # Make sure that uwsgi gets restarted if any django settings change.
  # I'm not sure why this isn't covered by the "before" and
  # "requiredBy" settings present in mailman-web.service. Maybe
  # because it's a oneshot and not a daemon?
  systemd.services.uwsgi.restartTriggers = [
    config.environment.etc."mailman3/settings.py".source
  ];

  # Tweak permissions so nginx can read and serve the static assets
  # (otherwise /var/lib/mailman-web is mode 0600)
  systemd.services.mailman-settings.script = ''
    chmod o+x /var/lib/mailman-web
  '';

  services.uwsgi = {
    enable = true;
    plugins = ["python3"];
    instance = {
      type = "normal";
      pythonPackages = (
        # TODO: I hope there is a nicer way of doing this:
        self: with self.override {
          overrides = self: super: { django = self.django_1_11; };
        }; [ mailman-web ]
      );
      # uwsgi protocol socket for nginx
      socket = "127.0.0.1:33140";
      # http socket for mailman core to reach the hyperkitty API directly
      http-socket = "127.0.0.1:33141";
      wsgi-file = "${config.services.mailman.webRoot}/mailman_web/wsgi.py";
      chdir = "/var/lib/mailman-web";
      master = true;
      processes = 4;
      vacuum = true;
    };
  };

  security.acme.email = OWNER_EMAIL;
  security.acme.acceptTerms = true;

  services.nginx = {
    enable = true;
    recommendedGzipSettings = true;
    recommendedProxySettings = true;
    recommendedTlsSettings = true;
    virtualHosts.${MAILMAN_HOST} = {
      enableACME = true;
      forceSSL = true;
      locations."/static/".alias = "/var/lib/mailman-web/static/";
      locations."/".extraConfig = ''
        uwsgi_pass 127.0.0.1:33140;
        include ${config.services.nginx.package}/conf/uwsgi_params;
      '';
    };
  };

  networking.firewall.allowedTCPPorts = [ 25 80 443 ];
}

Since mailman.serve.enable in 20.09 should take care of all the uwsgi stuff, I thought this should suffice:

let
  OWNER_EMAIL = "mailman@example.com";
  MAILMAN_HOST = "mailman.example.com";
in

{
  # ...

  services.postfix = {
    enable = true;
    relayDomains = ["hash:/var/lib/mailman/data/postfix_domains"];
    sslCert = config.security.acme.certs.${MAILMAN_HOST}.directory + "/full.pem";
    sslKey = config.security.acme.certs.${MAILMAN_HOST}.directory + "/key.pem";
    config = {
      transport_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
      local_recipient_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
    };
  };

  services.mailman = {
    enable = true;
    serve.enable = true;
    siteOwner = OWNER_EMAIL;
    hyperkitty.enable = true;
    webHosts = [MAILMAN_HOST];
  };

  security.acme.email = OWNER_EMAIL;
  security.acme.acceptTerms = true;

  users.users.nginx.extraGroups = [ "acme" ];
  users.users.postfix.extraGroups = [ "acme" ];

  services.nginx = {
    enable = true;
    recommendedGzipSettings = true;
    recommendedProxySettings = true;
    recommendedTlsSettings = true;
    virtualHosts.${MAILMAN_HOST} = {
      enableACME = true;
      forceSSL = true;
    };
  };

  networking.firewall.allowedTCPPorts = [ 25 80 443 ];
}

nixos-rebuild test fails with the following errors:

warning: the following units failed: hyperkitty.service, mailman-web-setup.service

● mailman-web-setup.service - Prepare mailman-web files and database
     Loaded: loaded (/nix/store/p63i698dfzhpvp2agv0h3l40hc91yijb-unit-mailman-web-setup.service/mailman-web-setup.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Thu 2020-10-29 00:47:39 CET; 8s ago
    Process: 8447 ExecStart=/nix/store/dsl613rz9b4w9swb4cqsxkhfq66whzqq-unit-script-mailman-web-setup-start/bin/mailman-web-setup-start (code=exited, status=1/FAILURE)
   Main PID: 8447 (code=exited, status=1/FAILURE)
         IP: 0B in, 0B out
        CPU: 116ms

Oct 29 00:47:39 mailman mailman-web-setup-start[8478]:   File "/nix/store/g5ai9as67mk8gjxm8q2jkywkz3ifawx6-python3-3.8.5-env/lib/python3.8/site-packages/mailman_web/manage.py", line 19, in main
Oct 29 00:47:39 mailman mailman-web-setup-start[8478]:     setup()
Oct 29 00:47:39 mailman mailman-web-setup-start[8478]:   File "/nix/store/g5ai9as67mk8gjxm8q2jkywkz3ifawx6-python3-3.8.5-env/lib/python3.8/site-packages/mailman_web/manage.py", line 11, in setup
Oct 29 00:47:39 mailman mailman-web-setup-start[8478]:     import settings
Oct 29 00:47:39 mailman mailman-web-setup-start[8478]:   File "/etc/mailman3/settings.py", line 14, in <module>
Oct 29 00:47:39 mailman mailman-web-setup-start[8478]:     with open('/var/lib/mailman-web/settings_local.json') as f:
Oct 29 00:47:39 mailman mailman-web-setup-start[8478]: PermissionError: [Errno 13] Permission denied: '/var/lib/mailman-web/settings_local.json'
Oct 29 00:47:39 mailman systemd[1]: mailman-web-setup.service: Main process exited, code=exited, status=1/FAILURE
Oct 29 00:47:39 mailman systemd[1]: mailman-web-setup.service: Failed with result 'exit-code'.
Oct 29 00:47:39 mailman systemd[1]: Failed to start Prepare mailman-web files and database.

● hyperkitty.service - GNU Hyperkitty QCluster Process
     Loaded: loaded (/nix/store/dyfd9ikvbgs4lkgkkrmx0qbpbq977vhv-unit-hyperkitty.service/hyperkitty.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Thu 2020-10-29 00:47:39 CET; 8s ago
    Process: 8442 ExecStart=/nix/store/g5ai9as67mk8gjxm8q2jkywkz3ifawx6-python3-3.8.5-env/bin/mailman-web qcluster (code=exited, status=1/FAILURE)
   Main PID: 8442 (code=exited, status=1/FAILURE)
         IP: 0B in, 0B out
        CPU: 114ms

Oct 29 00:47:39 mailman mailman-web[8442]:     sys.exit(main())
Oct 29 00:47:39 mailman mailman-web[8442]:   File "/nix/store/g5ai9as67mk8gjxm8q2jkywkz3ifawx6-python3-3.8.5-env/lib/python3.8/site-packages/mailman_web/manage.py", line 19, in main
Oct 29 00:47:39 mailman mailman-web[8442]:     setup()
Oct 29 00:47:39 mailman mailman-web[8442]:   File "/nix/store/g5ai9as67mk8gjxm8q2jkywkz3ifawx6-python3-3.8.5-env/lib/python3.8/site-packages/mailman_web/manage.py", line 11, in setup
Oct 29 00:47:39 mailman mailman-web[8442]:     import settings
Oct 29 00:47:39 mailman mailman-web[8442]:   File "/etc/mailman3/settings.py", line 14, in <module>
Oct 29 00:47:39 mailman mailman-web[8442]:     with open('/var/lib/mailman-web/settings_local.json') as f:
Oct 29 00:47:39 mailman mailman-web[8442]: PermissionError: [Errno 13] Permission denied: '/var/lib/mailman-web/settings_local.json'
Oct 29 00:47:39 mailman systemd[1]: hyperkitty.service: Main process exited, code=exited, status=1/FAILURE
Oct 29 00:47:39 mailman systemd[1]: hyperkitty.service: Failed with result 'exit-code'.
warning: error(s) occurred while switching to the new configuration

After setting chown -R mailman-web:mailman /var/lib/mailman-web, I’m getting only the following error:

arning: the following units failed: mailman-web-setup.service

● mailman-web-setup.service - Prepare mailman-web files and database
     Loaded: loaded (/nix/store/p63i698dfzhpvp2agv0h3l40hc91yijb-unit-mailman-web-setup.service/mailman-web-setup.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Thu 2020-10-29 00:50:49 CET; 58ms ago
    Process: 9272 ExecStart=/nix/store/dsl613rz9b4w9swb4cqsxkhfq66whzqq-unit-script-mailman-web-setup-start/bin/mailman-web-setup-start (code=exited, status=1/FAILURE)
   Main PID: 9272 (code=exited, status=1/FAILURE)
         IP: 0B in, 0B out
        CPU: 4.852s

Oct 29 00:50:49 mailman mailman-web-setup-start[9275]:     migration_recorded = True
Oct 29 00:50:49 mailman mailman-web-setup-start[9275]:   File "/nix/store/g5ai9as67mk8gjxm8q2jkywkz3ifawx6-python3-3.8.5-env/lib/python3.8/site-packages/django/db/backends/sqlite3/schema.py", line 34, in __exit__
Oct 29 00:50:49 mailman mailman-web-setup-start[9275]:     self.connection.check_constraints()
Oct 29 00:50:49 mailman mailman-web-setup-start[9275]:   File "/nix/store/g5ai9as67mk8gjxm8q2jkywkz3ifawx6-python3-3.8.5-env/lib/python3.8/site-packages/django/db/backends/sqlite3/base.py", line 313, in check_constraints
Oct 29 00:50:49 mailman mailman-web-setup-start[9275]:     raise utils.IntegrityError(
Oct 29 00:50:49 mailman mailman-web-setup-start[9275]: django.db.utils.IntegrityError: The row in table 'hyperkitty_attachment' with primary key '1' has an invalid foreign key: hyperkitty_attachment.email_id contains a value '7' that does not have a corresponding value in hyperkitty_email__old.id.
Oct 29 00:50:49 mailman systemd[1]: mailman-web-setup.service: Main process exited, code=exited, status=1/FAILURE
Oct 29 00:50:49 mailman systemd[1]: mailman-web-setup.service: Failed with result 'exit-code'.
Oct 29 00:50:49 mailman systemd[1]: Failed to start Prepare mailman-web files and database.
Oct 29 00:50:49 mailman systemd[1]: mailman-web-setup.service: Consumed 4.852s CPU time, no IP traffic.
warning: error(s) occurred while switching to the new configuration

I have created a bug in the Hyperkitty issue tracker now:

When doing a --rollback to 20.03, I’m getting the following error, so I’m kind of stuck between the versions:

warning: the following units failed: mailman.service

● mailman.service - GNU Mailman Master Process
   Loaded: loaded (/nix/store/633fxk8nc8xlxibpialx245355mhqgpr-unit-mailman.service/mailman.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Thu 2020-10-29 01:12:16 CET; 7s ago
  Process: 5308 ExecStart=/nix/store/dlv5wzv4881x7d3qny1z3yg85bxhpc2f-python3.7-mailman-3.3.0-wrapped/bin/mailman start (code=exited, status=1/FAILURE)
       IP: 0B in, 0B out
      CPU: 1.667s

Oct 29 01:12:16 mailman mailman[5308]:     for rev_id in resolved_id
Oct 29 01:12:16 mailman mailman[5308]:   File "/nix/store/5axi92kpd49759ih1hdify7g6i5zi11b-python3.7-alembic-1.3.2/lib/python3.7/site-packages/alembic/script/revision.py", line 324, in <genexpr>
Oct 29 01:12:16 mailman mailman[5308]:     for rev_id in resolved_id
Oct 29 01:12:16 mailman mailman[5308]:   File "/nix/store/5axi92kpd49759ih1hdify7g6i5zi11b-python3.7-alembic-1.3.2/lib/python3.7/site-packages/alembic/script/revision.py", line 397, in _revision_for_ident
Oct 29 01:12:16 mailman mailman[5308]:     resolved_id,
Oct 29 01:12:16 mailman mailman[5308]: alembic.util.exc.CommandError: Can't locate revision identified by 'd151c0b8d6f7'
Oct 29 01:12:16 mailman systemd[1]: mailman.service: Control process exited, code=exited, status=1/FAILURE
Oct 29 01:12:16 mailman systemd[1]: mailman.service: Failed with result 'exit-code'.
Oct 29 01:12:16 mailman systemd[1]: Failed to start GNU Mailman Master Process.
Oct 29 01:12:16 mailman systemd[1]: mailman.service: Consumed 1.667s CPU time, no IP traffic.
warning: error(s) occurred while switching to the new configuration

Finally, I gave up and reverted to the cloud snapshot before the upgrade.

Unfortunately, the Release notes don’t mention these backward incompatibilities regarding mailman.

@lheckemann Would you have any tips on how to do this upgrade? Am I missing any crucial option or step?

P.S.: Would it be possible to set the permissions of the /var/lib/mailman-web folders automatically as part of the services.mailman.serve.enable option?

Sorry about the slow response! The permissions thing is odd, the mailman-settings service should ensure the correct permissions for it: https://github.com/NixOS/nixpkgs/blob/f08bfb863718531ca935b6bff38cd945e7c2f257/nixos/modules/services/mail/mailman.nix#L322