{ config, lib, pkgs, ... }: with lib; let cfg = config.services.lvm-snapshots; snapshotMount = name: "${cfg.mountPoint}/${if isNull cfg.snapshots."${name}".mountName then name else cfg.snapshots."${name}".mountName}"; snapshotConfig = { options = { LV = mkOption { type = types.str; }; VG = mkOption { type = types.str; }; mountName = mkOption { type = types.nullOr types.str; default = null; }; cowSize = mkOption { type = types.str; default = "-l20%%ORIGIN"; description = "Literate argument to lvcreate, escape for systemd"; }; readOnly = mkOption { type = types.bool; default = true; }; persist = mkOption { type = types.bool; default = false; }; }; }; in { options = { services.lvm-snapshots = { snapshots = mkOption { type = types.attrsOf (types.submodule snapshotConfig); default = {}; }; mountPoint = mkOption { type = types.path; default = "/mnt"; }; }; }; config = mkIf (cfg != {}) { system.activationScripts = mapAttrs' (name: scfg: nameValuePair ("lvm-mountpoint" + name) '' mkdir -p ${snapshotMount name} '') cfg.snapshots; systemd.services = mapAttrs' (name: scfg: nameValuePair ("lvm-snapshot@" + name) { enable = true; unitConfig = { StopWhenUnneeded = true; }; serviceConfig = with pkgs; { Type = "oneshot"; ExecStart = "${devicemapper}/bin/lvcreate -s ${scfg.cowSize} --name ${name} ${scfg.VG}/${scfg.LV}"; ExecStop = "${devicemapper}/bin/lvremove ${scfg.VG}/${name}"; RemainAfterExit = true; }; }) cfg.snapshots; systemd.mounts = mapAttrsToList (name: scfg: { enable = true; unitConfig = { AssertPathIsDirectory = snapshotMount name; StopWhenUnneeded = !scfg.persist; }; bindsTo = [ ("lvm-snapshot@" + name) ]; options = mkIf scfg.readOnly "ro"; where = snapshotMount name; what = "/dev/" + scfg.VG + "/" + name; }) cfg.snapshots; }; }