nixos/services.znapzend: remove with lib;
This commit is contained in:
parent
8cf91e2c5b
commit
fcfa7fa441
@ -1,8 +1,4 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
with types;
|
||||
|
||||
let
|
||||
|
||||
planDescription = ''
|
||||
@ -29,46 +25,46 @@ let
|
||||
planExample = "1h=>10min,1d=>1h,1w=>1d,1m=>1w,1y=>1m";
|
||||
|
||||
# A type for a string of the form number{b|k|M|G}
|
||||
mbufferSizeType = str // {
|
||||
check = x: str.check x && builtins.isList (builtins.match "^[0-9]+[bkMG]$" x);
|
||||
mbufferSizeType = lib.types.str // {
|
||||
check = x: lib.types.str.check x && builtins.isList (builtins.match "^[0-9]+[bkMG]$" x);
|
||||
description = "string of the form number{b|k|M|G}";
|
||||
};
|
||||
|
||||
enabledFeatures = concatLists (mapAttrsToList (name: enabled: optional enabled name) cfg.features);
|
||||
enabledFeatures = lib.concatLists (lib.mapAttrsToList (name: enabled: lib.optional enabled name) cfg.features);
|
||||
|
||||
# Type for a string that must contain certain other strings (the list parameter).
|
||||
# Note that these would need regex escaping.
|
||||
stringContainingStrings = list: let
|
||||
matching = s: map (str: builtins.match ".*${str}.*" s) list;
|
||||
in str // {
|
||||
check = x: str.check x && all isList (matching x);
|
||||
description = "string containing all of the characters ${concatStringsSep ", " list}";
|
||||
in lib.types.str // {
|
||||
check = x: lib.types.str.check x && lib.all lib.isList (matching x);
|
||||
description = "string containing all of the characters ${lib.concatStringsSep ", " list}";
|
||||
};
|
||||
|
||||
timestampType = stringContainingStrings [ "%Y" "%m" "%d" "%H" "%M" "%S" ];
|
||||
|
||||
destType = srcConfig: submodule ({ name, ... }: {
|
||||
destType = srcConfig: lib.types.submodule ({ name, ... }: {
|
||||
options = {
|
||||
|
||||
label = mkOption {
|
||||
type = str;
|
||||
label = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Label for this destination. Defaults to the attribute name.";
|
||||
};
|
||||
|
||||
plan = mkOption {
|
||||
type = str;
|
||||
plan = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = planDescription;
|
||||
example = planExample;
|
||||
};
|
||||
|
||||
dataset = mkOption {
|
||||
type = str;
|
||||
dataset = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Dataset name to send snapshots to.";
|
||||
example = "tank/main";
|
||||
};
|
||||
|
||||
host = mkOption {
|
||||
type = nullOr str;
|
||||
host = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
Host to use for the destination dataset. Can be prefixed with
|
||||
`user@` to specify the ssh user.
|
||||
@ -77,8 +73,8 @@ let
|
||||
example = "john@example.com";
|
||||
};
|
||||
|
||||
presend = mkOption {
|
||||
type = nullOr str;
|
||||
presend = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
Command to run before sending the snapshot to the destination.
|
||||
Intended to run a remote script via {command}`ssh` on the
|
||||
@ -89,8 +85,8 @@ let
|
||||
example = "ssh root@bserv zpool import -Nf tank";
|
||||
};
|
||||
|
||||
postsend = mkOption {
|
||||
type = nullOr str;
|
||||
postsend = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
Command to run after sending the snapshot to the destination.
|
||||
Intended to run a remote script via {command}`ssh` on the
|
||||
@ -103,37 +99,37 @@ let
|
||||
};
|
||||
|
||||
config = {
|
||||
label = mkDefault name;
|
||||
plan = mkDefault srcConfig.plan;
|
||||
label = lib.mkDefault name;
|
||||
plan = lib.mkDefault srcConfig.plan;
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
|
||||
srcType = submodule ({ name, config, ... }: {
|
||||
srcType = lib.types.submodule ({ name, config, ... }: {
|
||||
options = {
|
||||
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
description = "Whether to enable this source.";
|
||||
default = true;
|
||||
};
|
||||
|
||||
recursive = mkOption {
|
||||
type = bool;
|
||||
recursive = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
description = "Whether to do recursive snapshots.";
|
||||
default = false;
|
||||
};
|
||||
|
||||
mbuffer = {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
description = "Whether to use {command}`mbuffer`.";
|
||||
default = false;
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = nullOr ints.u16;
|
||||
port = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.ints.u16;
|
||||
description = ''
|
||||
Port to use for {command}`mbuffer`.
|
||||
|
||||
@ -147,7 +143,7 @@ let
|
||||
default = null;
|
||||
};
|
||||
|
||||
size = mkOption {
|
||||
size = lib.mkOption {
|
||||
type = mbufferSizeType;
|
||||
description = ''
|
||||
The size for {command}`mbuffer`.
|
||||
@ -158,32 +154,32 @@ let
|
||||
};
|
||||
};
|
||||
|
||||
presnap = mkOption {
|
||||
type = nullOr str;
|
||||
presnap = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
Command to run before snapshots are taken on the source dataset,
|
||||
e.g. for database locking/flushing. See also
|
||||
{option}`postsnap`.
|
||||
'';
|
||||
default = null;
|
||||
example = literalExpression ''
|
||||
example = lib.literalExpression ''
|
||||
'''''${pkgs.mariadb}/bin/mysql -e "set autocommit=0;flush tables with read lock;\\! ''${pkgs.coreutils}/bin/sleep 600" & ''${pkgs.coreutils}/bin/echo $! > /tmp/mariadblock.pid ; sleep 10'''
|
||||
'';
|
||||
};
|
||||
|
||||
postsnap = mkOption {
|
||||
type = nullOr str;
|
||||
postsnap = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
Command to run after snapshots are taken on the source dataset,
|
||||
e.g. for database unlocking. See also {option}`presnap`.
|
||||
'';
|
||||
default = null;
|
||||
example = literalExpression ''
|
||||
example = lib.literalExpression ''
|
||||
"''${pkgs.coreutils}/bin/kill `''${pkgs.coreutils}/bin/cat /tmp/mariadblock.pid`;''${pkgs.coreutils}/bin/rm /tmp/mariadblock.pid"
|
||||
'';
|
||||
};
|
||||
|
||||
timestampFormat = mkOption {
|
||||
timestampFormat = lib.mkOption {
|
||||
type = timestampType;
|
||||
description = ''
|
||||
The timestamp format to use for constructing snapshot names.
|
||||
@ -197,8 +193,8 @@ let
|
||||
example = "znapzend-%m.%d.%Y-%H%M%SZ";
|
||||
};
|
||||
|
||||
sendDelay = mkOption {
|
||||
type = int;
|
||||
sendDelay = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
description = ''
|
||||
Specify delay (in seconds) before sending snaps to the destination.
|
||||
May be useful if you want to control sending time.
|
||||
@ -207,23 +203,23 @@ let
|
||||
example = 60;
|
||||
};
|
||||
|
||||
plan = mkOption {
|
||||
type = str;
|
||||
plan = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = planDescription;
|
||||
example = planExample;
|
||||
};
|
||||
|
||||
dataset = mkOption {
|
||||
type = str;
|
||||
dataset = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "The dataset to use for this source.";
|
||||
example = "tank/home";
|
||||
};
|
||||
|
||||
destinations = mkOption {
|
||||
type = attrsOf (destType config);
|
||||
destinations = lib.mkOption {
|
||||
type = lib.types.attrsOf (destType config);
|
||||
description = "Additional destinations.";
|
||||
default = {};
|
||||
example = literalExpression ''
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
local = {
|
||||
dataset = "btank/backup";
|
||||
@ -240,7 +236,7 @@ let
|
||||
};
|
||||
|
||||
config = {
|
||||
dataset = mkDefault name;
|
||||
dataset = lib.mkDefault name;
|
||||
};
|
||||
|
||||
});
|
||||
@ -251,18 +247,18 @@ let
|
||||
|
||||
onOff = b: if b then "on" else "off";
|
||||
nullOff = b: if b == null then "off" else toString b;
|
||||
stripSlashes = replaceStrings [ "/" ] [ "." ];
|
||||
stripSlashes = lib.replaceStrings [ "/" ] [ "." ];
|
||||
|
||||
attrsToFile = config: concatStringsSep "\n" (builtins.attrValues (
|
||||
mapAttrs (n: v: "${n}=${v}") config));
|
||||
attrsToFile = config: lib.concatStringsSep "\n" (builtins.attrValues (
|
||||
lib.mapAttrs (n: v: "${n}=${v}") config));
|
||||
|
||||
mkDestAttrs = dst: with dst;
|
||||
mapAttrs' (n: v: nameValuePair "dst_${label}${n}" v) ({
|
||||
"" = optionalString (host != null) "${host}:" + dataset;
|
||||
lib.mapAttrs' (n: v: lib.nameValuePair "dst_${label}${n}" v) ({
|
||||
"" = lib.optionalString (host != null) "${host}:" + dataset;
|
||||
_plan = plan;
|
||||
} // optionalAttrs (presend != null) {
|
||||
} // lib.optionalAttrs (presend != null) {
|
||||
_precmd = presend;
|
||||
} // optionalAttrs (postsend != null) {
|
||||
} // lib.optionalAttrs (postsend != null) {
|
||||
_pstcmd = postsend;
|
||||
});
|
||||
|
||||
@ -270,7 +266,7 @@ let
|
||||
enabled = onOff enable;
|
||||
# mbuffer is not referenced by its full path to accommodate non-NixOS systems or differing mbuffer versions between source and target
|
||||
mbuffer = with mbuffer; if enable then "mbuffer"
|
||||
+ optionalString (port != null) ":${toString port}" else "off";
|
||||
+ lib.optionalString (port != null) ":${toString port}" else "off";
|
||||
mbuffer_size = mbuffer.size;
|
||||
post_znap_cmd = nullOff postsnap;
|
||||
pre_znap_cmd = nullOff presnap;
|
||||
@ -279,11 +275,11 @@ let
|
||||
src_plan = plan;
|
||||
tsformat = timestampFormat;
|
||||
zend_delay = toString sendDelay;
|
||||
} // foldr (a: b: a // b) {} (
|
||||
} // lib.foldr (a: b: a // b) {} (
|
||||
map mkDestAttrs (builtins.attrValues destinations)
|
||||
);
|
||||
|
||||
files = mapAttrs' (n: srcCfg: let
|
||||
files = lib.mapAttrs' (n: srcCfg: let
|
||||
fileText = attrsToFile (mkSrcAttrs srcCfg);
|
||||
in {
|
||||
name = srcCfg.dataset;
|
||||
@ -294,20 +290,20 @@ in
|
||||
{
|
||||
options = {
|
||||
services.znapzend = {
|
||||
enable = mkEnableOption "ZnapZend ZFS backup daemon";
|
||||
enable = lib.mkEnableOption "ZnapZend ZFS backup daemon";
|
||||
|
||||
logLevel = mkOption {
|
||||
logLevel = lib.mkOption {
|
||||
default = "debug";
|
||||
example = "warning";
|
||||
type = enum ["debug" "info" "warning" "err" "alert"];
|
||||
type = lib.types.enum ["debug" "info" "warning" "err" "alert"];
|
||||
description = ''
|
||||
The log level when logging to file. Any of debug, info, warning, err,
|
||||
alert. Default in daemonized form is debug.
|
||||
'';
|
||||
};
|
||||
|
||||
logTo = mkOption {
|
||||
type = str;
|
||||
logTo = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "syslog::daemon";
|
||||
example = "/var/log/znapzend.log";
|
||||
description = ''
|
||||
@ -315,31 +311,31 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
mailErrorSummaryTo = mkOption {
|
||||
type = singleLineStr;
|
||||
mailErrorSummaryTo = lib.mkOption {
|
||||
type = lib.types.singleLineStr;
|
||||
default = "";
|
||||
description = ''
|
||||
Email address to send a summary to if "send task(s) failed".
|
||||
'';
|
||||
};
|
||||
|
||||
noDestroy = mkOption {
|
||||
type = bool;
|
||||
noDestroy = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Does all changes to the filesystem except destroy.";
|
||||
};
|
||||
|
||||
autoCreation = mkOption {
|
||||
type = bool;
|
||||
autoCreation = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Automatically create the destination dataset if it does not exist.";
|
||||
};
|
||||
|
||||
zetup = mkOption {
|
||||
type = attrsOf srcType;
|
||||
zetup = lib.mkOption {
|
||||
type = lib.types.attrsOf srcType;
|
||||
description = "Znapzend configuration.";
|
||||
default = {};
|
||||
example = literalExpression ''
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
"tank/home" = {
|
||||
# Make snapshots of tank/home every hour, keep those for 1 day,
|
||||
@ -356,8 +352,8 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
pure = mkOption {
|
||||
type = bool;
|
||||
pure = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
description = ''
|
||||
Do not persist any stateful znapzend setups. If this option is
|
||||
enabled, your previously set znapzend setups will be cleared and only
|
||||
@ -366,17 +362,17 @@ in
|
||||
default = false;
|
||||
};
|
||||
|
||||
features.oracleMode = mkEnableOption ''
|
||||
features.oracleMode = lib.mkEnableOption ''
|
||||
destroying snapshots one by one instead of using one long argument list.
|
||||
If source and destination are out of sync for a long time, you may have
|
||||
so many snapshots to destroy that the argument gets is too long and the
|
||||
command fails
|
||||
'';
|
||||
features.recvu = mkEnableOption ''
|
||||
features.recvu = lib.mkEnableOption ''
|
||||
recvu feature which uses `-u` on the receiving end to keep the destination
|
||||
filesystem unmounted
|
||||
'';
|
||||
features.compressed = mkEnableOption ''
|
||||
features.compressed = lib.mkEnableOption ''
|
||||
compressed feature which adds the options `-Lce` to
|
||||
the {command}`zfs send` command. When this is enabled, make
|
||||
sure that both the sending and receiving pool have the same relevant
|
||||
@ -387,7 +383,7 @@ in
|
||||
and {manpage}`zfs(8)`
|
||||
for more info
|
||||
'';
|
||||
features.sendRaw = mkEnableOption ''
|
||||
features.sendRaw = lib.mkEnableOption ''
|
||||
sendRaw feature which adds the options `-w` to the
|
||||
{command}`zfs send` command. For encrypted source datasets this
|
||||
instructs zfs not to decrypt before sending which results in a remote
|
||||
@ -396,7 +392,7 @@ in
|
||||
option must be used consistently, raw incrementals cannot be based on
|
||||
non-raw snapshots and vice versa
|
||||
'';
|
||||
features.skipIntermediates = mkEnableOption ''
|
||||
features.skipIntermediates = lib.mkEnableOption ''
|
||||
the skipIntermediates feature to send a single increment
|
||||
between latest common snapshot and the newly made one. It may skip
|
||||
several source snaps if the destination was offline for some time, and
|
||||
@ -404,14 +400,14 @@ in
|
||||
destinations, the new snapshot is sent as soon as it is created on the
|
||||
source, so there are no automatic increments to skip
|
||||
'';
|
||||
features.lowmemRecurse = mkEnableOption ''
|
||||
features.lowmemRecurse = lib.mkEnableOption ''
|
||||
use lowmemRecurse on systems where you have too many datasets, so a
|
||||
recursive listing of attributes to find backup plans exhausts the
|
||||
memory available to {command}`znapzend`: instead, go the slower
|
||||
way to first list all impacted dataset names, and then query their
|
||||
configs one by one
|
||||
'';
|
||||
features.zfsGetType = mkEnableOption ''
|
||||
features.zfsGetType = lib.mkEnableOption ''
|
||||
using zfsGetType if your {command}`zfs get` supports a
|
||||
`-t` argument for filtering by dataset type at all AND
|
||||
lists properties for snapshots by default when recursing, so that there
|
||||
@ -425,7 +421,7 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = [ pkgs.znapzend ];
|
||||
|
||||
systemd.services = {
|
||||
@ -436,12 +432,12 @@ in
|
||||
|
||||
path = with pkgs; [ zfs mbuffer openssh ];
|
||||
|
||||
preStart = optionalString cfg.pure ''
|
||||
preStart = lib.optionalString cfg.pure ''
|
||||
echo Resetting znapzend zetups
|
||||
${pkgs.znapzend}/bin/znapzendzetup list \
|
||||
| grep -oP '(?<=\*\*\* backup plan: ).*(?= \*\*\*)' \
|
||||
| xargs -I{} ${pkgs.znapzend}/bin/znapzendzetup delete "{}"
|
||||
'' + concatStringsSep "\n" (mapAttrsToList (dataset: config: ''
|
||||
'' + lib.concatStringsSep "\n" (lib.mapAttrsToList (dataset: config: ''
|
||||
echo Importing znapzend zetup ${config} for dataset ${dataset}
|
||||
${pkgs.znapzend}/bin/znapzendzetup import --write ${dataset} ${config} &
|
||||
'') files) + ''
|
||||
@ -458,15 +454,15 @@ in
|
||||
# Needs to have write access to ZFS
|
||||
User = "root";
|
||||
ExecStart = let
|
||||
args = concatStringsSep " " [
|
||||
args = lib.concatStringsSep " " [
|
||||
"--logto=${cfg.logTo}"
|
||||
"--loglevel=${cfg.logLevel}"
|
||||
(optionalString cfg.noDestroy "--nodestroy")
|
||||
(optionalString cfg.autoCreation "--autoCreation")
|
||||
(optionalString (cfg.mailErrorSummaryTo != "")
|
||||
(lib.optionalString cfg.noDestroy "--nodestroy")
|
||||
(lib.optionalString cfg.autoCreation "--autoCreation")
|
||||
(lib.optionalString (cfg.mailErrorSummaryTo != "")
|
||||
"--mailErrorSummaryTo=${cfg.mailErrorSummaryTo}")
|
||||
(optionalString (enabledFeatures != [])
|
||||
"--features=${concatStringsSep "," enabledFeatures}")
|
||||
(lib.optionalString (enabledFeatures != [])
|
||||
"--features=${lib.concatStringsSep "," enabledFeatures}")
|
||||
]; in "${pkgs.znapzend}/bin/znapzend ${args}";
|
||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||
Restart = "on-failure";
|
||||
@ -475,5 +471,5 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = with maintainers; [ SlothOfAnarchy ];
|
||||
meta.maintainers = with lib.maintainers; [ SlothOfAnarchy ];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user