{ config, lib, pkgs, ... }: with lib; # TODO replace with more secure service, e.g. matrix-sendmail (matrix-commander) # needs to support queueing # flake: https://github.com/emmanuelrosa/erosanix/blob/master/modules/matrix-sendmail.nix # call `matrix-commander --login` with credentials on service start let cfg = config.systemd.notify; sendmail = pkgs.writeScript "sendmail" '' #!${pkgs.runtimeShell} ${pkgs.system-sendmail}/bin/sendmail -t <<ERRMAIL To: ${cfg.email.mailTo} From: ${cfg.email.mailFrom} Subject: Service $1 failed Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 $(systemctl status --full "$1") ERRMAIL ''; in { options = { systemd.notify = { enable = mkOption { type = types.bool; default = false; description = "Whether to enable notifications for failed services."; }; method = mkOption { type = types.enum [ "libnotify" "email" ]; default = "libnotify"; description = "The method for sending notifications."; }; libnotify.user = mkOption { type = types.str; default = null; description = "User session to which the notification will be sent."; }; email.mailTo = mkOption { type = types.str; default = null; description = "Email address to which the service status will be mailed."; }; email.mailFrom = mkOption { type = types.str; default = null; description = "Email address from which the service status will be mailed."; }; }; systemd.services = mkOption { type = with types; attrsOf (submodule { config.onFailure = optional cfg.enable "notify@%n.service"; }); }; }; config = mkIf cfg.enable { assertions = [ { assertion = cfg.method != "libnotify" || cfg.libnotify.user != null; message = "You need to specify a user"; } { assertion = cfg.method != "email" || (cfg.email.mailTo != null && cfg.email.mailFrom != null); message = "You need to specify a sender and a receiver"; } ]; systemd.services."notify@" = { onFailure = lib.mkForce [ ]; } // optionalAttrs (cfg.method == "libnotify") { description = "Desktop notifications for %i service failure"; environment = { DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/user/${ toString config.users.users.${cfg.libnotify.user}.uid }/bus"; INSTANCE = "%i"; }; script = '' ${pkgs.libnotify}/bin/notify-send --urgency=critical \ "Service '$INSTANCE' failed" \ "$(journalctl -n 6 -o cat -u $INSTANCE)" ''; serviceConfig = { Type = "oneshot"; User = cfg.libnotify.user; }; } // optionalAttrs (cfg.method == "email") { description = "E-Mail notifications for %i service failure"; serviceConfig = { ExecStart = "${sendmail} %i"; Type = "oneshot"; }; }; }; }