From 288cae3c83aa06448d4712b3baa7da2d13a58d88 Mon Sep 17 00:00:00 2001 From: Chris Toph Date: Wed, 30 Apr 2025 14:20:36 -0400 Subject: [PATCH] Adds backup notifications & SMTP config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Incorporates Apprise for sending backup start and completion notifications • Captures and formats backup statistics for richer log details • Updates backup exclusion lists to prevent unneeded data inclusion • Standardizes and extends SMTP configuration in secrets management --- flake.lock | 146 ++++++++++++++++++++++++-- hosts/nixos/cloud/config/borg.nix | 108 ++++++++++++++++--- hosts/nixos/cloud/config/snapraid.nix | 14 ++- modules/common/secret-spec.nix | 39 +++++++ secrets.nix | Bin 13214 -> 13463 bytes 5 files changed, 285 insertions(+), 22 deletions(-) diff --git a/flake.lock b/flake.lock index 67b0792..8e83f64 100644 --- a/flake.lock +++ b/flake.lock @@ -106,7 +106,7 @@ "crane": { "inputs": { "flake-compat": "flake-compat_2", - "flake-utils": "flake-utils_5", + "flake-utils": "flake-utils_6", "nixpkgs": [ "watershot", "std", @@ -308,6 +308,24 @@ } }, "flake-utils_2": { + "inputs": { + "systems": "systems_4" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_3": { "inputs": { "systems": [ "stylix", @@ -328,9 +346,9 @@ "type": "github" } }, - "flake-utils_3": { + "flake-utils_4": { "inputs": { - "systems": "systems_5" + "systems": "systems_6" }, "locked": { "lastModified": 1681202837, @@ -346,7 +364,7 @@ "type": "github" } }, - "flake-utils_4": { + "flake-utils_5": { "locked": { "lastModified": 1659877975, "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", @@ -361,7 +379,7 @@ "type": "github" } }, - "flake-utils_5": { + "flake-utils_6": { "locked": { "lastModified": 1667395993, "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", @@ -376,6 +394,24 @@ "type": "github" } }, + "flake-utils_7": { + "inputs": { + "systems": "systems_7" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "fromYaml": { "flake": false, "locked": { @@ -940,9 +976,11 @@ "nixpkgs-unstable": "nixpkgs-unstable", "nixvirt": "nixvirt", "rose-pine-hyprcursor": "rose-pine-hyprcursor", + "snapraid-aio": "snapraid-aio", "stylix": "stylix", "vscode-server": "vscode-server", "watershot": "watershot", + "yay": "yay", "zen-browser": "zen-browser" } }, @@ -1014,6 +1052,45 @@ "type": "github" } }, + "snapraid-aio": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ], + "snapraid-aio-src": "snapraid-aio-src" + }, + "locked": { + "lastModified": 1745877167, + "narHash": "sha256-I1LF6QlQnQmpsom676VNWzbA5xY1ksgwMyPh1b5JoG0=", + "ref": "refs/heads/main", + "rev": "fb1b3606270ce8ceaea8534a046eb1dda08c54dc", + "revCount": 1, + "type": "git", + "url": "https://git.ryot.foo/toph/snapraid-aio.nix.git" + }, + "original": { + "type": "git", + "url": "https://git.ryot.foo/toph/snapraid-aio.nix.git" + } + }, + "snapraid-aio-src": { + "flake": false, + "locked": { + "lastModified": 1744884143, + "narHash": "sha256-GNXn/V4HoFnQtyq7l+V+aXHArObr3zQd4vCgPEqPeRk=", + "owner": "auanasgheps", + "repo": "snapraid-aio-script", + "rev": "a46c7362af385eac945e86a2a0f6097dbe7ca3fb", + "type": "github" + }, + "original": { + "owner": "auanasgheps", + "repo": "snapraid-aio-script", + "rev": "a46c7362af385eac945e86a2a0f6097dbe7ca3fb", + "type": "github" + } + }, "std": { "inputs": { "arion": [ @@ -1024,7 +1101,7 @@ "blank": "blank", "devshell": "devshell", "dmerge": "dmerge", - "flake-utils": "flake-utils_4", + "flake-utils": "flake-utils_5", "incl": "incl", "makes": [ "watershot", @@ -1069,13 +1146,13 @@ "base16-vim": "base16-vim", "firefox-gnome-theme": "firefox-gnome-theme", "flake-compat": "flake-compat", - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils_3", "git-hooks": "git-hooks", "gnome-shell": "gnome-shell", "home-manager": "home-manager_2", "nixpkgs": "nixpkgs_3", "nur": "nur", - "systems": "systems_4", + "systems": "systems_5", "tinted-foot": "tinted-foot", "tinted-kitty": "tinted-kitty", "tinted-schemes": "tinted-schemes", @@ -1171,6 +1248,36 @@ "type": "github" } }, + "systems_6": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_7": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "tinted-foot": { "flake": false, "locked": { @@ -1295,7 +1402,7 @@ }, "vscode-server": { "inputs": { - "flake-utils": "flake-utils_3", + "flake-utils": "flake-utils_4", "nixpkgs": [ "nixpkgs-unstable" ] @@ -1358,6 +1465,27 @@ "type": "github" } }, + "yay": { + "inputs": { + "flake-utils": "flake-utils_7", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1745989032, + "narHash": "sha256-qKy5YVu8vhA60VxWpLiLV9QpN8LofL9qFCEAACrCxBw=", + "ref": "refs/heads/main", + "rev": "92d557d0d0393713cb57a970e880efafe6cc2b41", + "revCount": 9, + "type": "git", + "url": "https://git.ryot.foo/toph/yay.nix.git" + }, + "original": { + "type": "git", + "url": "https://git.ryot.foo/toph/yay.nix.git" + } + }, "zen-browser": { "inputs": { "nixpkgs": [ diff --git a/hosts/nixos/cloud/config/borg.nix b/hosts/nixos/cloud/config/borg.nix index 2e12aae..7a5278a 100644 --- a/hosts/nixos/cloud/config/borg.nix +++ b/hosts/nixos/cloud/config/borg.nix @@ -27,10 +27,28 @@ let fi ''; + # Function to send notifications + apprise-url = config.secretsSpec.users.admin.smtp.notifyUrl; + sendNotification = title: message: '' + # Send notification through Apprise + ${pkgs.apprise}/bin/apprise -t "${title}" -b "${message}" "${apprise-url}" || true + ''; + + # Get borg stats in a readable format + extractBorgStats = logFile: '' + # Extract and format relevant stats + echo -e "\nBackup Stats:" > ${logFile} + grep -A15 "Archive name:" ${logFile} >> ${logFile}.stats || true + STATS=$(cat ${logFile}.stats || echo "No stats available") + ''; + in { - # Make sure borg is installed - environment.systemPackages = [ pkgs.borgbackup ]; + # Make sure borg and apprise are installed + environment.systemPackages = with pkgs; [ + borgbackup + apprise + ]; # Docker Storage Backup Service systemd.services.backup-docker-storage = { @@ -39,29 +57,62 @@ in path = with pkgs; [ borgbackup coreutils + apprise + gnugrep ]; script = '' ${borgCommonSettings} + # Set up log file and temporary stats file + LOG_FILE="/tmp/borg-docker-backup-$(date +%Y%m%d-%H%M%S).log" + + # Send start notification + ${sendNotification "🚀 Docker Storage Backup Started" "Starting Docker Storage backup on $(hostname) at $(date)"} + # Initialize repository if needed ${initRepo dockerStorageRepo} - # Create backup + # Create backup and capture output/stats + echo "Starting backup at $(date)" > $LOG_FILE + ARCHIVE_NAME="docker-$(date +%Y-%m-%d_%H%M%S)" + + # Run backup command and capture exit status ${pkgs.borgbackup}/bin/borg create \ --stats \ --compression zstd,15 \ --exclude '*.tmp' \ --exclude '*/tmp/*' \ - ${dockerStorageRepo}::docker-{now:%Y-%m-%d_%H%M%S} \ - /mnt/drive1/DockerStorage - + ${dockerStorageRepo}::$ARCHIVE_NAME \ + /mnt/drive1/DockerStorage >> $LOG_FILE 2>&1 + + BACKUP_STATUS=$? + + # Extract stats from log file + ${extractBorgStats "$LOG_FILE"} + # Prune old backups + echo -e "\nPruning old backups..." >> $LOG_FILE ${pkgs.borgbackup}/bin/borg prune \ --keep-daily 7 \ --keep-weekly 4 \ --keep-monthly 3 \ - ${dockerStorageRepo} + ${dockerStorageRepo} >> $LOG_FILE 2>&1 + + PRUNE_STATUS=$? + + # Send completion notification + if [ $BACKUP_STATUS -eq 0 ] && [ $PRUNE_STATUS -eq 0 ]; then + ${sendNotification "✅ Docker Storage Backup Complete" "Docker Storage backup completed successfully on $(hostname) at $(date)\n\n$STATS"} + else + ${sendNotification "❌ Docker Storage Backup Failed" "Docker Storage backup failed on $(hostname) at $(date)\n\nBackup Status: $BACKUP_STATUS\nPrune Status: $PRUNE_STATUS\n\nSee $LOG_FILE for details"} + fi + + # Clean up temp stats file + rm -f $LOG_FILE.stats + + # Return exit status from backup operation + exit $BACKUP_STATUS ''; serviceConfig = { @@ -92,29 +143,62 @@ in path = with pkgs; [ borgbackup coreutils + apprise + gnugrep ]; script = '' ${borgCommonSettings} + # Set up log file and temporary stats file + LOG_FILE="/tmp/borg-forgejo-backup-$(date +%Y%m%d-%H%M%S).log" + + # Send start notification + ${sendNotification "🚀 Forgejo Backup Started" "Starting Forgejo backup on $(hostname) at $(date)"} + # Initialize repository if needed ${initRepo forgejoRepo} - # Create backup + # Create backup and capture output/stats + echo "Starting backup at $(date)" > $LOG_FILE + ARCHIVE_NAME="forgejo-$(date +%Y-%m-%d_%H%M%S)" + + # Run backup command and capture exit status ${pkgs.borgbackup}/bin/borg create \ --stats \ --compression zstd,15 \ --exclude '*.tmp' \ --exclude '*/tmp/*' \ - ${forgejoRepo}::forgejo-{now:%Y-%m-%d_%H%M%S} \ - /pool/forgejo - + ${forgejoRepo}::$ARCHIVE_NAME \ + /pool/forgejo >> $LOG_FILE 2>&1 + + BACKUP_STATUS=$? + + # Extract stats from log file + ${extractBorgStats "$LOG_FILE"} + # Prune old backups + echo -e "\nPruning old backups..." >> $LOG_FILE ${pkgs.borgbackup}/bin/borg prune \ --keep-daily 14 \ --keep-weekly 4 \ --keep-monthly 3 \ - ${forgejoRepo} + ${forgejoRepo} >> $LOG_FILE 2>&1 + + PRUNE_STATUS=$? + + # Send completion notification + if [ $BACKUP_STATUS -eq 0 ] && [ $PRUNE_STATUS -eq 0 ]; then + ${sendNotification "✅ Forgejo Backup Complete" "Forgejo backup completed successfully on $(hostname) at $(date)\n\n$STATS"} + else + ${sendNotification "❌ Forgejo Backup Failed" "Forgejo backup failed on $(hostname) at $(date)\n\nBackup Status: $BACKUP_STATUS\nPrune Status: $PRUNE_STATUS\n\nSee $LOG_FILE for details"} + fi + + # Clean up temp stats file + rm -f $LOG_FILE.stats + + # Return exit status from backup operation + exit $BACKUP_STATUS ''; serviceConfig = { diff --git a/hosts/nixos/cloud/config/snapraid.nix b/hosts/nixos/cloud/config/snapraid.nix index fa2b31e..a62cfcb 100644 --- a/hosts/nixos/cloud/config/snapraid.nix +++ b/hosts/nixos/cloud/config/snapraid.nix @@ -6,7 +6,7 @@ }: let - apprise-url = config.secretsSpec.api.apprise-url; + apprise-url = config.secretsSpec.users.admin.smtp.notifyUrl; snapraid-aio = inputs.snapraid-aio.nixosModules.default; snapraid-aio-config = pkgs.writeTextFile { @@ -96,6 +96,18 @@ let exclude *.unrecoverable exclude /tmp/ exclude /lost+found/ + exclude /var/tmp/ + exclude /var/cache/ + exclude /var/log/ + exclude .trash/ + exclude .Trash-1000/ + exclude .Trash/ + # These dirs change data all the time + # so I back them up in borg repos that are not excluded + exclude /mnt/drive1/DockerStorage/ + exclude /mnt/drive1/data/forgejo + exclude /mnt/drive2/data/forgejo + exclude /mnt/drive3/data/forgejo ''; }; in diff --git a/modules/common/secret-spec.nix b/modules/common/secret-spec.nix index 02dca79..2ed8dbe 100644 --- a/modules/common/secret-spec.nix +++ b/modules/common/secret-spec.nix @@ -89,6 +89,45 @@ in description = "SSH public keys for the user"; default = [ ]; }; + smtp = lib.mkOption { + type = lib.types.submodule { + options = { + host = lib.mkOption { + type = lib.types.str; + description = "SMTP server hostname"; + }; + user = lib.mkOption { + type = lib.types.str; + description = "SMTP username for authentication"; + }; + password = lib.mkOption { + type = lib.types.str; + description = "SMTP password for authentication"; + }; + port = lib.mkOption { + type = lib.types.port; + description = "SMTP server port"; + default = 587; + }; + from = lib.mkOption { + type = lib.types.str; + description = "Email address to send from"; + }; + notifyUrl = lib.mkOption { + type = lib.types.str; + description = "Apprise URL for sending notifications via this SMTP account"; + default = + config: + let + smtp = config; # parent smtp config + in + "mailtos://_?user=${smtp.user}&pass=${smtp.password}&smtp=${smtp.host}&from=${smtp.from}&to=${smtp.user}"; + }; + }; + }; + description = "SMTP configuration for the user"; + default = null; + }; }; } ); diff --git a/secrets.nix b/secrets.nix index 7d90baac33d66f7fe260f95a5566706fc32b2d47..1ea522d288d48db69bf687e5b397aa43bf20a1f8 100644 GIT binary patch literal 13463 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 F8Pq+?4KDxy literal 13214 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 QWhbi|=J|~2uST`zT>1OaWdHyG