homelab framework module init (everything is a mess)
This commit is contained in:
parent
0347f4d325
commit
bcbcc8b17b
94 changed files with 7289 additions and 436 deletions
234
modules/nixos/system/backups/restic.nix
Normal file
234
modules/nixos/system/backups/restic.nix
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
# restic.nix - Restic backend implementation
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.system.backups;
|
||||
resticCfg = cfg.restic;
|
||||
|
||||
# Get only restic backups that are enabled
|
||||
resticBackups = filterAttrs (_: backup: backup.backend == "restic" && backup.enable) cfg.backups;
|
||||
|
||||
# Create restic service configurations
|
||||
createResticServices =
|
||||
mapAttrs (
|
||||
name: backup: let
|
||||
# Merge global defaults with backup-specific options
|
||||
serviceConfig =
|
||||
recursiveUpdate resticCfg.defaultBackendOptions backup.backendOptions
|
||||
// {
|
||||
inherit (backup) paths;
|
||||
|
||||
# Use backup-specific timer or fall back to global default
|
||||
timerConfig =
|
||||
if backup.timerConfig != null
|
||||
then backup.timerConfig
|
||||
else resticCfg.timerConfig;
|
||||
};
|
||||
in
|
||||
serviceConfig
|
||||
)
|
||||
resticBackups;
|
||||
in {
|
||||
options.system.backups.restic = {
|
||||
enable = mkEnableOption "restic backup backend";
|
||||
|
||||
timerConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = {
|
||||
OnCalendar = "*-*-* 05:00:00";
|
||||
Persistent = true;
|
||||
};
|
||||
description = "Default systemd timer configuration for restic backups";
|
||||
};
|
||||
|
||||
defaultBackendOptions = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = {
|
||||
repository = "/backup/restic";
|
||||
passwordFile = "/etc/nixos/secrets/restic-password";
|
||||
initialize = true;
|
||||
pruneOpts = [
|
||||
"--keep-daily 7"
|
||||
"--keep-weekly 5"
|
||||
"--keep-monthly 12"
|
||||
"--keep-yearly 75"
|
||||
];
|
||||
};
|
||||
description = "Default backend options applied to all restic backup jobs";
|
||||
};
|
||||
|
||||
# Advanced options
|
||||
runMaintenance = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether to run repository maintenance after backups";
|
||||
};
|
||||
|
||||
maintenanceTimer = mkOption {
|
||||
type = types.attrs;
|
||||
default = {
|
||||
OnCalendar = "*-*-* 06:00:00";
|
||||
Persistent = true;
|
||||
};
|
||||
description = "Timer configuration for maintenance tasks";
|
||||
};
|
||||
|
||||
pruneOpts = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
"--keep-daily 7"
|
||||
"--keep-weekly 4"
|
||||
"--keep-monthly 6"
|
||||
"--keep-yearly 3"
|
||||
];
|
||||
description = "Default pruning options for maintenance";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf resticCfg.enable {
|
||||
# Register restic backend
|
||||
system.backups.backends.restic = {
|
||||
backupConfig,
|
||||
backupName,
|
||||
...
|
||||
}: {
|
||||
# Define the proper options schema for restic backendOptions
|
||||
options = {
|
||||
repository = mkOption {
|
||||
type = types.str;
|
||||
description = "Restic repository path or URL";
|
||||
};
|
||||
|
||||
passwordFile = mkOption {
|
||||
type = types.str;
|
||||
description = "Path to file containing the repository password";
|
||||
};
|
||||
|
||||
initialize = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether to initialize the repository if it doesn't exist";
|
||||
};
|
||||
|
||||
exclude = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Patterns to exclude from backup";
|
||||
};
|
||||
|
||||
extraBackupArgs = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Additional arguments passed to restic backup command";
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "root";
|
||||
description = "User to run the backup as";
|
||||
};
|
||||
|
||||
pruneOpts = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = resticCfg.pruneOpts;
|
||||
description = "Pruning options for this backup";
|
||||
};
|
||||
};
|
||||
|
||||
# Default config merged with global defaults
|
||||
config = {
|
||||
extraBackupArgs =
|
||||
[
|
||||
"--tag ${backupName}"
|
||||
"--verbose"
|
||||
]
|
||||
++ (resticCfg.defaultBackendOptions.extraBackupArgs or []);
|
||||
};
|
||||
};
|
||||
|
||||
# Create actual restic backup services
|
||||
services.restic.backups = createResticServices;
|
||||
|
||||
# Add restic package
|
||||
environment.systemPackages = [pkgs.restic];
|
||||
|
||||
# Systemd service customizations for restic backups
|
||||
systemd.services =
|
||||
(mapAttrs' (
|
||||
name: backup:
|
||||
nameValuePair "restic-backups-${name}" {
|
||||
# Custom pre/post scripts
|
||||
preStart = mkBefore backup.preBackupScript;
|
||||
postStop = mkAfter backup.postBackupScript;
|
||||
|
||||
# Enhanced service configuration
|
||||
serviceConfig = {
|
||||
# Restart configuration
|
||||
Restart = "on-failure";
|
||||
RestartSec = "5m";
|
||||
RestartMaxDelaySec = "30m";
|
||||
RestartSteps = 3;
|
||||
|
||||
# Rate limiting
|
||||
StartLimitBurst = 4;
|
||||
StartLimitIntervalSec = "2h";
|
||||
};
|
||||
|
||||
# Failure handling could be extended here for notifications
|
||||
# onFailure = optional backup.notifications.failure.enable "restic-backup-${name}-failure-notify.service";
|
||||
}
|
||||
)
|
||||
resticBackups)
|
||||
// optionalAttrs resticCfg.runMaintenance {
|
||||
# Repository maintenance service
|
||||
restic-maintenance = {
|
||||
description = "Restic repository maintenance";
|
||||
after = map (name: "restic-backups-${name}.service") (attrNames resticBackups);
|
||||
|
||||
environment =
|
||||
resticCfg.defaultBackendOptions
|
||||
// {
|
||||
RESTIC_CACHE_DIR = "/var/cache/restic-maintenance";
|
||||
};
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = [
|
||||
"${pkgs.restic}/bin/restic forget --prune ${concatStringsSep " " resticCfg.pruneOpts}"
|
||||
"${pkgs.restic}/bin/restic check --read-data-subset=500M"
|
||||
];
|
||||
|
||||
User = "root";
|
||||
CacheDirectory = "restic-maintenance";
|
||||
CacheDirectoryMode = "0700";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Maintenance timer
|
||||
systemd.timers = mkIf resticCfg.runMaintenance {
|
||||
restic-maintenance = {
|
||||
description = "Timer for restic repository maintenance";
|
||||
wantedBy = ["timers.target"];
|
||||
timerConfig = resticCfg.maintenanceTimer;
|
||||
};
|
||||
};
|
||||
|
||||
# Helpful shell aliases
|
||||
programs.zsh.shellAliases =
|
||||
{
|
||||
restic-snapshots = "restic snapshots --compact --group-by tags";
|
||||
restic-repo-size = "restic stats --mode raw-data";
|
||||
}
|
||||
// (mapAttrs' (
|
||||
name: _:
|
||||
nameValuePair "backup-${name}" "systemctl start restic-backups-${name}"
|
||||
)
|
||||
resticBackups);
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue