Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/spamassassin: Avoid network dependency on boot #103902

Merged
merged 6 commits into from Apr 25, 2021

Conversation

pkern
Copy link
Contributor

@pkern pkern commented Nov 15, 2020

Motivation for this change

sa-update currently runs as part of the pre-start script of spamd. The network is not guaranteed to be online at that point and even if we were to depend on that, it makes the bootup brittle, as there is a reliance on SpamAssassin's update server as a startup dependency on boot.

Refactor the setup to move the pre-start script into its own oneshot unit (spamd-init.service). This allows to perform the setup task only once. Continuous updates are already done by sa-update.service triggered by sa-update.timer. Only run sa-update in case /var/lib/spamassassin is empty.

While we are on it, let sa-update.service depend on the network being online.

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS linux)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review wip"
    • None, because it's a change to a module.
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Ensured that relevant documentation is up to date
  • Fits CONTRIBUTING.md.

@pkern pkern changed the title nixos/spamassassin: Fix network requirement on boot nixos/spamassassin: Avoid network dependency on boot Nov 15, 2020
@pkern
Copy link
Contributor Author

pkern commented Nov 15, 2020

@alyssais Hey Alyssa, would you mind having a look at this? It looks like you touched spamassassin last. ;-)

nixos/modules/services/mail/spamassassin.nix Outdated Show resolved Hide resolved
@lukegb
Copy link
Contributor

lukegb commented Nov 23, 2020

@ofborg eval

@pkern
Copy link
Contributor Author

pkern commented Dec 25, 2020

Gentle ping. :)

@alyssais
Copy link
Member

Do we need the spamd-init service at all any more, then? All it does is create a state directory and do an update, so couldn’t it be replaced by a systemd StateDirectory and the update service?

@pkern
Copy link
Contributor Author

pkern commented Jan 3, 2021

@alyssais That's a good point. I think I made it work, PTAL. For spamd itself I did not see how you'd properly run it as non-root, though, so the systemd bits do escalation to root for starting and reloading but need to be set to user/group=spamd to ensure proper permissions on the state directory. I tested that initial startup and updates worked fine and did reload spamd without hanging.

While I was on it I also added sa-compile support post-update.

@pkern
Copy link
Contributor Author

pkern commented Jan 3, 2021

Although to be fair it might make sense to split out the sa-compile bit. It currently runs too often, i.e. not just when sa-update signals an update. But I guess I don't have a way to hook into that without using a script again or another service (which makes things more messy).

@pkern
Copy link
Contributor Author

pkern commented Jan 5, 2021

I re-added a script to only call sa-compile if updates have been installed. So now we are down to just a superfluous spamd reload in that case (because ExecStartPost cannot distinguish the two cases and we require elevation to do the systemctl invocation).

@alyssais
Copy link
Member

alyssais commented Jan 5, 2021 via email

@alyssais
Copy link
Member

alyssais commented Jan 5, 2021 via email

@alyssais
Copy link
Member

alyssais commented Jan 5, 2021 via email

@pkern
Copy link
Contributor Author

pkern commented Jan 5, 2021

Should we exit $rc at the end of that script?

sa-compile is only called when rc=0 and then the script returns the exit code of that. That's probably unfortunate in case sa-compile fails and systemd treats this as acceptable per SuccessExitStatus. Maybe it'd make sense to run sa-compile in its own unit somehow. This all seems messy, but "exit $rc" would not help. :/

Could we use a path unit to do this instead of an ExecStartPost? (systemd.path(5))

I naively don't see how given that we'd need some notion that the updating and compiling is done. The last action sa-compile (currently) performs is copying to /var/lib/spamassassin/<perlver>/<saver>/bases_body_0.pl, but that seems odd to depend on.

@alyssais
Copy link
Member

alyssais commented Jan 6, 2021 via email

@alyssais
Copy link
Member

alyssais commented Jan 6, 2021 via email

@pkern
Copy link
Contributor Author

pkern commented Jan 6, 2021

Hm, I guess in terms of states we want:

  • sa-update rc=1 -> exit 0 (no update found, nothing to do; no benefit of plumbing through the 1 to systemd verbatim)
  • sa-update rc=0 -> exit rc of sa-compile (which bash implicitly does for the last command in the script)
  • any other sa-update rc gets passed through literally as an error

And then we remove SuccessExitStatus and we should be good. Or so I hope. I'll try to cook something along these lines up tomorrow.

@pkern
Copy link
Contributor Author

pkern commented Jan 10, 2021

PTAL. Testing both with updates available and subsequently no updates available worked fine for me.

@pkern
Copy link
Contributor Author

pkern commented Jan 24, 2021

Resolved the merge conflict. Is there anything else left to do for me? :)

@aanderse
Copy link
Member

aanderse commented Feb 1, 2021

@pkern can you please remove the last 2 commits and do a rebase instead?

sa-update currently runs as part of the pre-start script of spamd. The
network is not guaranteed to be online at that point and even if we
were to depend on that, it makes the bootup brittle, as there is a
reliance on SpamAssassin's update server as a startup dependency on
boot.

Refactor the setup to move the pre-start script into its own unit.
This allows to perform the setup task only once. Continuous updates
are already done by sa-update.service triggered by sa-update.timer.
Only run sa-update in case /var/lib/spamassassin is empty.

While we are on it, let sa-update.service depend on the network being
online.
Let systemd create SpamAssassin's state directory and populate it using the
regular updater service. Depend on the updater service on boot but do not
propagate failure to the main service.

spamd's commands to start and reload the service are still executed as
root but user/group are set to properly chown the state directory to the
target user. spamd drops privileges itself for its runner children but
preserves root on the main daemon (to listen and re-exec).
sa-compile requires re2c, gcc and gnumake to compile the expressions to
performant C code. This compilation is done post-installation after
every ruleset update and stored as local state.
sa-compile speeds up processing the rules by compiling them from Perl to
C.  This needs to be run after every update and is saved in the local
state directory by Perl and SpamAssassin version.
For sa-update we care about two successful codes:

 * 1 -> no updates available: exit successfully
 * 0 -> updates have been installed: run sa-compile and pass
   through its return code
@pkern
Copy link
Contributor Author

pkern commented Feb 11, 2021

@aanderse Done.

@aanderse
Copy link
Member

@alyssais @lukegb are either of you reviewing this module? Is it ready for merge?

@lukegb
Copy link
Contributor

lukegb commented Feb 15, 2021

@aanderse I'm still happy with it; not sure if @alyssais has any outstanding commentary

@aanderse
Copy link
Member

Well... in that case... "ping" to any motivated parties wanting to merge 😄

@lukegb lukegb merged commit 2fa2e63 into NixOS:master Apr 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants