nixos: Add borgthin module
This commit is contained in:
		@@ -81,6 +81,10 @@
 | 
			
		||||
            fsType = "ext4";
 | 
			
		||||
            neededForBoot = true;
 | 
			
		||||
          };
 | 
			
		||||
          "/mnt/backup" = {
 | 
			
		||||
            device = "/dev/main/tmp-backup";
 | 
			
		||||
            fsType = "ext4";
 | 
			
		||||
          };
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        services = {
 | 
			
		||||
@@ -240,6 +244,9 @@
 | 
			
		||||
          #deploy.generate.system.mode = "boot";
 | 
			
		||||
          secrets = {
 | 
			
		||||
            key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPIijqzAWF6OxKr4aeCa1TAc5xGn4rdIjVTt0wAPU6uY";
 | 
			
		||||
            files = {
 | 
			
		||||
              "colony/borg-pass.txt" = {};
 | 
			
		||||
            };
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          server.enable = true;
 | 
			
		||||
@@ -255,6 +262,34 @@
 | 
			
		||||
              }
 | 
			
		||||
            '';
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          borgthin = {
 | 
			
		||||
            enable = true;
 | 
			
		||||
            jobs = {
 | 
			
		||||
              main = {
 | 
			
		||||
                repo = "/mnt/backup/main";
 | 
			
		||||
                passFile = config.age.secrets."colony/borg-pass.txt".path;
 | 
			
		||||
                lvs = map (lv: "main/${lv}") [
 | 
			
		||||
                  "colony-persist"
 | 
			
		||||
                  "vm-shill-persist"
 | 
			
		||||
                  "minio"
 | 
			
		||||
                  "oci"
 | 
			
		||||
                  "vm-estuary-persist"
 | 
			
		||||
                  "vm-whale2-persist"
 | 
			
		||||
                ];
 | 
			
		||||
                compression = "zstd,5";
 | 
			
		||||
                extraCreateArgs = [ "--stats" ];
 | 
			
		||||
                prune.keep = {
 | 
			
		||||
                  last = 1;
 | 
			
		||||
                  within = "1d";
 | 
			
		||||
                  daily = 7;
 | 
			
		||||
                  weekly = 4;
 | 
			
		||||
                  monthly = 12;
 | 
			
		||||
                  yearly = -1;
 | 
			
		||||
                };
 | 
			
		||||
              };
 | 
			
		||||
            };
 | 
			
		||||
          };
 | 
			
		||||
        };
 | 
			
		||||
      };
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -16,5 +16,6 @@
 | 
			
		||||
    nginx-sso = ./nginx-sso.nix;
 | 
			
		||||
    gui = ./gui.nix;
 | 
			
		||||
    l2mesh = ./l2mesh.nix;
 | 
			
		||||
    borgthin = ./borgthin.nix;
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										150
									
								
								nixos/modules/borgthin.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								nixos/modules/borgthin.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,150 @@
 | 
			
		||||
{ lib, pkgs, config, ... }:
 | 
			
		||||
let
 | 
			
		||||
  inherit (builtins) substring match;
 | 
			
		||||
  inherit (lib)
 | 
			
		||||
    nameValuePair optional optionalString optionalAttrs mapAttrs' mapAttrsToList concatStringsSep
 | 
			
		||||
    concatMapStringsSep mkIf;
 | 
			
		||||
  inherit (lib.my) mkOpt' mkBoolOpt';
 | 
			
		||||
 | 
			
		||||
  jobType = with lib.types; submodule ({ name, ... }@args:
 | 
			
		||||
  let
 | 
			
		||||
    cfg = args.config;
 | 
			
		||||
  in
 | 
			
		||||
  {
 | 
			
		||||
    options = {
 | 
			
		||||
      repo = mkOpt' str null "borg repository URL";
 | 
			
		||||
      passFile = mkOpt' (nullOr str) null "Path to file containing passphrase";
 | 
			
		||||
 | 
			
		||||
      archivePrefix = mkOpt' str "${config.networking.hostName}-${name}-" "Prefix to start new archives with";
 | 
			
		||||
      dateFormat = mkOpt' str "+%Y-%m-%dT%H:%M:%S" "Format passed to the date command";
 | 
			
		||||
      compression = mkOpt' str "zstd,3" "Compression options";
 | 
			
		||||
      lvs = mkOpt' (listOf str) null "Thin LVs to backup (vg/lv format)";
 | 
			
		||||
      prune = {
 | 
			
		||||
        pattern = mkOpt' str "sh:${cfg.archivePrefix}*" "Borg pattern to select archives for pruning";
 | 
			
		||||
        keep = mkOpt' (attrsOf (either int str)) { } "Borg pruning params";
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      extraArgs = mkOpt' (listOf str) [ "--iec" ] "Extra args to pass to all borg commands";
 | 
			
		||||
      extraCreateArgs = mkOpt' (listOf str) [ ] "Extra args to pass to tcreate command";
 | 
			
		||||
      environment = mkOpt' (attrsOf str) { } "Extra environment variables to pass to borg";
 | 
			
		||||
 | 
			
		||||
      timer = {
 | 
			
		||||
        at = mkOpt' (either str (listOf str)) "5:00" "systemd calendar time(s) to run backup at";
 | 
			
		||||
        persistent = mkBoolOpt' false "Persistent systemd timer";
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  cfg' = config.my.borgthin;
 | 
			
		||||
 | 
			
		||||
  isLocalPath = x:
 | 
			
		||||
    substring 0 1 x == "/"      # absolute path
 | 
			
		||||
    || substring 0 1 x == "."   # relative path
 | 
			
		||||
    || match "[.*:.*]" == null; # not machine:path
 | 
			
		||||
 | 
			
		||||
  argStr = concatMapStringsSep " " (a: ''"${a}"'');
 | 
			
		||||
 | 
			
		||||
  mkEnv = name: cfg: (rec {
 | 
			
		||||
    BORG_BASE_DIR = "/var/lib/borgthin";
 | 
			
		||||
    BORG_CONFIG_DIR = "${BORG_BASE_DIR}/config";
 | 
			
		||||
    BORG_CACHE_DIR = "/var/cache/borgthin";
 | 
			
		||||
 | 
			
		||||
    BORG_REPO = cfg.repo;
 | 
			
		||||
  }) //
 | 
			
		||||
  (optionalAttrs (cfg.passFile != null) {
 | 
			
		||||
    BORG_PASSCOMMAND = "cat ${cfg.passFile}";
 | 
			
		||||
  }) //
 | 
			
		||||
  cfg.environment;
 | 
			
		||||
 | 
			
		||||
  # utility function around makeWrapper
 | 
			
		||||
  mkWrapperDrv = {
 | 
			
		||||
    original, name,
 | 
			
		||||
    set ? { }, addFlags ? [ ],
 | 
			
		||||
  }:
 | 
			
		||||
  pkgs.runCommand "${name}-wrapper" {
 | 
			
		||||
    nativeBuildInputs = [ pkgs.makeWrapper ];
 | 
			
		||||
  } ''
 | 
			
		||||
    makeWrapper "${original}" "$out/bin/${name}" \
 | 
			
		||||
      ${concatStringsSep " \\\n " (
 | 
			
		||||
        (mapAttrsToList (name: value: ''--set ${name} "${value}"'') set) ++
 | 
			
		||||
        (map (f: ''--add-flags "${f}"'') addFlags)
 | 
			
		||||
      )}
 | 
			
		||||
  '';
 | 
			
		||||
  mkBorgWrapper = name: cfg: mkWrapperDrv {
 | 
			
		||||
    original = "${cfg'.package}/bin/borgthin";
 | 
			
		||||
    name = "borgthin-job-${name}";
 | 
			
		||||
    set = mkEnv name cfg;
 | 
			
		||||
    addFlags = cfg.extraArgs;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  mkKeepArgs = keep:
 | 
			
		||||
    # If cfg.prune.keep e.g. has a yearly attribute,
 | 
			
		||||
    # its content is passed on as --keep-yearly
 | 
			
		||||
    concatStringsSep " "
 | 
			
		||||
      (mapAttrsToList (x: y: "--keep-${x}=${toString y}") keep);
 | 
			
		||||
 | 
			
		||||
  mkService = name: cfg: nameValuePair "borgthin-job-${name}" {
 | 
			
		||||
    description = "borgthin backup job ${name}";
 | 
			
		||||
    serviceConfig = {
 | 
			
		||||
      Type = "oneshot";
 | 
			
		||||
      StateDirectory = "borgthin";
 | 
			
		||||
      CacheDirectory = "borgthin";
 | 
			
		||||
 | 
			
		||||
      # Only run when no other process is using CPU or disk
 | 
			
		||||
      CPUSchedulingPolicy = "idle";
 | 
			
		||||
      IOSchedulingClass = "idle";
 | 
			
		||||
    };
 | 
			
		||||
    environment = mkEnv name cfg;
 | 
			
		||||
 | 
			
		||||
    path = [ cfg'.lvmPackage cfg'.thinToolsPackage cfg'.package ];
 | 
			
		||||
    script = ''
 | 
			
		||||
      extraArgs="${argStr cfg.extraArgs}"
 | 
			
		||||
      borgthin $extraArgs tcreate \
 | 
			
		||||
        --compression "${cfg.compression}" \
 | 
			
		||||
        ${argStr cfg.extraCreateArgs} \
 | 
			
		||||
        "${cfg.archivePrefix}$(date "${cfg.dateFormat}")" \
 | 
			
		||||
        ${concatStringsSep " " cfg.lvs}
 | 
			
		||||
    '' + optionalString (cfg.prune.keep != { }) ''
 | 
			
		||||
      borgthin $extraArgs prune \
 | 
			
		||||
        --match-archives "${cfg.prune.pattern}" \
 | 
			
		||||
        ${mkKeepArgs cfg.prune.keep}
 | 
			
		||||
      borgthin $extraArgs compact
 | 
			
		||||
    '';
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  mkTimer = name: cfg: nameValuePair "borgthin-job-${name}" {
 | 
			
		||||
    description = "borgthin backup job ${name} timer";
 | 
			
		||||
    after = optional (cfg.timer.persistent && !isLocalPath cfg.repo) "network-online.target";
 | 
			
		||||
    timerConfig = {
 | 
			
		||||
      Persistent = cfg.timer.persistent;
 | 
			
		||||
      OnCalendar = cfg.timer.at;
 | 
			
		||||
    };
 | 
			
		||||
    wantedBy = [ "timers.target" ];
 | 
			
		||||
  };
 | 
			
		||||
in
 | 
			
		||||
{
 | 
			
		||||
  options.my.borgthin = with lib.types; {
 | 
			
		||||
    enable = mkBoolOpt' false "Whether to enable borgthin jobs";
 | 
			
		||||
    lvmPackage = mkOpt' package pkgs.lvm2 "Packge containing LVM tools";
 | 
			
		||||
    thinToolsPackage = mkOpt' package pkgs.thin-provisioning-tools "Package containing thin-provisioning-tools";
 | 
			
		||||
    package = mkOpt' package pkgs.borgthin "borgthin package";
 | 
			
		||||
    jobs = mkOpt' (attrsOf jobType) { } "borgthin jobs";
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  config = mkIf cfg'.enable {
 | 
			
		||||
    environment.systemPackages =
 | 
			
		||||
      [ cfg'.package ] ++
 | 
			
		||||
      (mapAttrsToList mkBorgWrapper cfg'.jobs);
 | 
			
		||||
 | 
			
		||||
    systemd = {
 | 
			
		||||
      services = mapAttrs' mkService cfg'.jobs;
 | 
			
		||||
      timers = mapAttrs' mkTimer cfg'.jobs;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    my.tmproot.persistence.config.directories = [
 | 
			
		||||
      "/var/lib/borgthin"
 | 
			
		||||
      "/var/cache/borgthin"
 | 
			
		||||
    ];
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -73,6 +73,7 @@ in
 | 
			
		||||
        overlays = [
 | 
			
		||||
          inputs.deploy-rs.overlay
 | 
			
		||||
          inputs.sharry.overlays.default
 | 
			
		||||
          inputs.borgthin.overlays.default
 | 
			
		||||
        ];
 | 
			
		||||
        config = {
 | 
			
		||||
          allowUnfree = true;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user