diff --git a/global/fs/zfs/alert.nix b/global/fs/zfs/alert.nix new file mode 100644 index 00000000..d9c76ae7 --- /dev/null +++ b/global/fs/zfs/alert.nix @@ -0,0 +1,120 @@ +{ pkgs +, lib +, config +, ... }: with lib; let + cfg = config.global.fs.zfs.alert; + + backend = { + text = pkgs.writeShellScript "telegram-text" '' + set -e + source ${cfg.secret} + + ${pkgs.curl}/bin/curl -sG \ + --data-urlencode "chat_id=$CHATID" \ + --data-urlencode "text=$ALERT" \ + "https://api.telegram.org/bot$APIKEY/sendMessage" + ''; + image = pkgs.writeShellScript "telegram-image" '' + set -e + source ${cfg.secret} + + ${pkgs.curl}/bin/curl -sG \ + -F "chat_id=$CHATID" \ + -F "caption=$ALERT" \ + -F "photo=@-" \ + "https://api.telegram.org/bot$APIKEY/sendPhoto" + ''; + }; + + zedAlert = pkgs.writeShellScript "zed-alert" '' + set -e + export BODY="$(cat)" + + # add tag + ALERT="$1 #zfs" + + export ALERT + echo -e "$BODY" | \ + ${pkgs.imagemagick}/bin/convert \ + -size 1500x2000 xc:black \ + -font "${pkgs.freefont_ttf}/share/fonts/truetype/FreeMono.ttf" \ + -pointsize 16 \ + -fill white -annotate +15+80 "@-" \ + -trim -bordercolor "#000" \ + -border 32 +repage \ + png:- | \ + ${backend.image} + ''; + + mdadmAlert = pkgs.writeShellScript "mdadm-alert" '' + set -e + + EVENT="$1" + ARRAY="$2" + DEVICE="$3" + + # fallback alert + ALERT="$EVENT | $ARRAY | $DEVICE" + + case $EVENT in + DegradedArray) + ALERT="Array $ARRAY is in a degraded state" + ;; + DeviceDisappeared) + ALERT="Array $ARRAY disappeared" + ;; + Fail) + ALERT="Array $ARRAY encountered failure of component $DEVICE" + ;; + FailSpare) + ALERT="Array $ARRAY encountered failure of spare component $DEVICE during rebuild" + ;; + MoveSpare) + ALERT="Spare $DEVICE moved to array $ARRAY" + ;; + NewArray) + ALERT="Array $ARRAY appeared" + ;; + Rebuild??) + ALERT="Array $ARRAY rebuild is now $(echo $EVENT | ${pkgs.sedutil}/bin/sed 's/Rebuild//')% complete" + ;; + RebuildFinished) + ALERT="Rebuild of array $ARRAY has concluded" + ;; + RebuildStarted) + ALERT="Rebuild of array $ARRAY has started" + ;; + SpareActive) + ALERT="Spare $DEVICE activated in array $ARRAY" + ;; + SparesMissing) + ALERT="Array $ARRAY missing one or more spares" + ;; + TestMessage) + ALERT="Test message generated for array $ARRAY" + ;; + esac + + # add tag + ALERT="$ALERT #swraid" + + export ALERT + exec ${backend.text} + ''; +in mkIf (cfg.secret != null) { + services.zfs.zed = mkIf cfg.zed { + settings = { + ZED_EMAIL_ADDR = [ "root" ]; + ZED_EMAIL_PROG = toString zedAlert; + ZED_EMAIL_OPTS = "'@SUBJECT@'"; + + ZED_NOTIFY_INTERVAL_SECS = 3600; + ZED_NOTIFY_VERBOSE = false; + + ZED_USE_ENCLOSURE_LEDS = true; + ZED_SCRUB_AFTER_RESILVER = false; + }; + }; + + global.fs.zfs.split.mdProg = mkIf cfg.swraid (toString mdadmAlert); +} diff --git a/global/fs/zfs/default.nix b/global/fs/zfs/default.nix index 37ca13ee..10c88a85 100644 --- a/global/fs/zfs/default.nix +++ b/global/fs/zfs/default.nix @@ -5,6 +5,7 @@ cfg = config.global.fs; in { imports = [ + ./alert.nix ./split.nix ./replication.nix ]; @@ -13,6 +14,16 @@ in { # -O encryption=on -O keyformat=passphrase -O keylocation=prompt # -O compression=on -O mountpoint=none -O xattr=sa -O acltype=posixacl options.global.fs.zfs = { + alert = { + zed = mkEnableOption "zfs event alerts" // { default = true; }; + swraid = mkEnableOption "software raid alerts" // { default = true; }; + secret = mkOption { + type = with types; nullOr str; + default = null; + description = "path to alert secrets"; + }; + }; + persist = mkOption { type = with types; str; default = cfg.store;