From 70862830f0a1415acd6c9fb7fc74ab59530f41dc Mon Sep 17 00:00:00 2001 From: Elis Hirwing Date: Sun, 25 Jul 2021 09:59:18 +0200 Subject: nixos/syncoid: Extract datasets rather than pools When sending or receiving datasets with the old implementation it wouldn't matter which dataset we were sending or receiving, we would always delegate permissions to the entire pool. --- nixos/modules/services/backup/syncoid.nix | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/services/backup/syncoid.nix b/nixos/modules/services/backup/syncoid.nix index 888ef20f642..80a704a7d26 100644 --- a/nixos/modules/services/backup/syncoid.nix +++ b/nixos/modules/services/backup/syncoid.nix @@ -5,9 +5,9 @@ with lib; let cfg = config.services.syncoid; - # Extract the pool name of a local dataset (any dataset not containing "@") - localPoolName = d: optionals (d != null) ( - let m = builtins.match "([^/@]+)[^@]*" d; in + # Extract local dasaset names (so no datasets containing "@") + localDatasetName = d: optionals (d != null) ( + let m = builtins.match "([^/@]+[^@]*)" d; in optionals (m != null) m); # Escape as required by: https://www.freedesktop.org/software/systemd/man/systemd.unit.html @@ -206,15 +206,15 @@ in { path = [ "/run/booted-system/sw/bin/" ]; serviceConfig = { ExecStartPre = - map (pool: lib.escapeShellArgs [ + map (dataset: lib.escapeShellArgs [ "+/run/booted-system/sw/bin/zfs" "allow" - cfg.user "bookmark,hold,send,snapshot,destroy" pool + cfg.user "bookmark,hold,send,snapshot,destroy" dataset # Permissions snapshot and destroy are in case --no-sync-snap is not used - ]) (localPoolName c.source) ++ - map (pool: lib.escapeShellArgs [ + ]) (localDatasetName c.source) ++ + map (dataset: lib.escapeShellArgs [ "+/run/booted-system/sw/bin/zfs" "allow" - cfg.user "create,mount,receive,rollback" pool - ]) (localPoolName c.target); + cfg.user "create,mount,receive,rollback" dataset + ]) (localDatasetName c.target); ExecStart = lib.escapeShellArgs ([ "${pkgs.sanoid}/bin/syncoid" ] ++ optionals c.useCommonArgs cfg.commonArgs ++ optional c.recursive "-r" -- cgit 1.4.1 From bb35e7c4044432111ab9fec5ef9c4260ae651582 Mon Sep 17 00:00:00 2001 From: Elis Hirwing Date: Sun, 25 Jul 2021 10:00:37 +0200 Subject: nixos/sanoid: Extract datasets rather than pools When making new snapshots we only need to delegate permissions to the specific dataset rather than the entire pool. --- nixos/modules/services/backup/sanoid.nix | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/services/backup/sanoid.nix b/nixos/modules/services/backup/sanoid.nix index abc4def1c61..9713581165b 100644 --- a/nixos/modules/services/backup/sanoid.nix +++ b/nixos/modules/services/backup/sanoid.nix @@ -70,8 +70,8 @@ let processChildrenOnly = process_children_only; }; - # Extract pool names from configured datasets - pools = unique (map (d: head (builtins.match "([^/]+).*" d)) (attrNames cfg.datasets)); + # Extract unique dataset names + datasets = unique (attrNames cfg.datasets); configFile = let mkValueString = v: @@ -156,18 +156,18 @@ in { systemd.services.sanoid = { description = "Sanoid snapshot service"; serviceConfig = { - ExecStartPre = map (pool: lib.escapeShellArgs [ + ExecStartPre = map (dataset: lib.escapeShellArgs [ "+/run/booted-system/sw/bin/zfs" "allow" - "sanoid" "snapshot,mount,destroy" pool - ]) pools; + "sanoid" "snapshot,mount,destroy" dataset + ]) datasets; ExecStart = lib.escapeShellArgs ([ "${pkgs.sanoid}/bin/sanoid" "--cron" "--configdir" (pkgs.writeTextDir "sanoid.conf" configFile) ] ++ cfg.extraArgs); - ExecStopPost = map (pool: lib.escapeShellArgs [ - "+/run/booted-system/sw/bin/zfs" "unallow" "sanoid" pool - ]) pools; + ExecStopPost = map (dataset: lib.escapeShellArgs [ + "+/run/booted-system/sw/bin/zfs" "unallow" "sanoid" dataset + ]) datasets; User = "sanoid"; Group = "sanoid"; DynamicUser = true; -- cgit 1.4.1 From ecd32b8104e6cca16fe1b2cfb89f39a8c7c01731 Mon Sep 17 00:00:00 2001 From: Elis Hirwing Date: Sun, 25 Jul 2021 18:22:05 +0200 Subject: nixos/syncoid: Build unallow commands as a post job to drop permissions --- nixos/modules/services/backup/syncoid.nix | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/services/backup/syncoid.nix b/nixos/modules/services/backup/syncoid.nix index 80a704a7d26..71007f6c38e 100644 --- a/nixos/modules/services/backup/syncoid.nix +++ b/nixos/modules/services/backup/syncoid.nix @@ -14,6 +14,14 @@ let escapeUnitName = name: lib.concatMapStrings (s: if lib.isList s then "-" else s) (builtins.split "[^a-zA-Z0-9_.\\-]+" name); + + # Function to build "zfs allow" and "zfs unallow" commands for the + # filesystems we've delegated permissions to. + buildAllowCommand = zfsAction: permissions: dataset: lib.escapeShellArgs [ + # Here we explicitly use the booted system to guarantee the stable API needed by ZFS + "-+/run/booted-system/sw/bin/zfs" zfsAction + cfg.user (concatStringsSep "," permissions) dataset + ]; in { # Interface @@ -206,15 +214,13 @@ in { path = [ "/run/booted-system/sw/bin/" ]; serviceConfig = { ExecStartPre = - map (dataset: lib.escapeShellArgs [ - "+/run/booted-system/sw/bin/zfs" "allow" - cfg.user "bookmark,hold,send,snapshot,destroy" dataset - # Permissions snapshot and destroy are in case --no-sync-snap is not used - ]) (localDatasetName c.source) ++ - map (dataset: lib.escapeShellArgs [ - "+/run/booted-system/sw/bin/zfs" "allow" - cfg.user "create,mount,receive,rollback" dataset - ]) (localDatasetName c.target); + # Permissions snapshot and destroy are in case --no-sync-snap is not used + (map (buildAllowCommand "allow" [ "bookmark" "hold" "send" "snapshot" "destroy" ]) (localDatasetName c.source)) ++ + (map (buildAllowCommand "allow" [ "create" "mount" "receive" "rollback" ]) (localDatasetName c.target)); + ExecStopPost = + # Permissions snapshot and destroy are in case --no-sync-snap is not used + (map (buildAllowCommand "unallow" [ "bookmark" "hold" "send" "snapshot" "destroy" ]) (localDatasetName c.source)) ++ + (map (buildAllowCommand "unallow" [ "create" "mount" "receive" "rollback" ]) (localDatasetName c.target)); ExecStart = lib.escapeShellArgs ([ "${pkgs.sanoid}/bin/syncoid" ] ++ optionals c.useCommonArgs cfg.commonArgs ++ optional c.recursive "-r" -- cgit 1.4.1 From b9f98165ab22b3981d7017ce88f268c4176f8072 Mon Sep 17 00:00:00 2001 From: Elis Hirwing Date: Sun, 25 Jul 2021 18:27:36 +0200 Subject: nixos/sanoid: Use a function to build allow/unallow commands --- nixos/modules/services/backup/sanoid.nix | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/services/backup/sanoid.nix b/nixos/modules/services/backup/sanoid.nix index 9713581165b..c7f276e3f04 100644 --- a/nixos/modules/services/backup/sanoid.nix +++ b/nixos/modules/services/backup/sanoid.nix @@ -73,6 +73,17 @@ let # Extract unique dataset names datasets = unique (attrNames cfg.datasets); + # Function to build "zfs allow" and "zfs unallow" commands for the + # filesystems we've delegated permissions to. + buildAllowCommand = zfsAction: permissions: dataset: lib.escapeShellArgs [ + # Here we explicitly use the booted system to guarantee the stable API needed by ZFS + "-+/run/booted-system/sw/bin/zfs" + zfsAction + "sanoid" + (concatStringsSep "," permissions) + dataset + ]; + configFile = let mkValueString = v: if builtins.isList v then concatStringsSep "," v @@ -156,18 +167,13 @@ in { systemd.services.sanoid = { description = "Sanoid snapshot service"; serviceConfig = { - ExecStartPre = map (dataset: lib.escapeShellArgs [ - "+/run/booted-system/sw/bin/zfs" "allow" - "sanoid" "snapshot,mount,destroy" dataset - ]) datasets; + ExecStartPre = (map (buildAllowCommand "allow" [ "snapshot" "mount" "destroy" ]) datasets); + ExecStopPost = (map (buildAllowCommand "unallow" [ "snapshot" "mount" "destroy" ]) datasets); ExecStart = lib.escapeShellArgs ([ "${pkgs.sanoid}/bin/sanoid" "--cron" "--configdir" (pkgs.writeTextDir "sanoid.conf" configFile) ] ++ cfg.extraArgs); - ExecStopPost = map (dataset: lib.escapeShellArgs [ - "+/run/booted-system/sw/bin/zfs" "unallow" "sanoid" dataset - ]) datasets; User = "sanoid"; Group = "sanoid"; DynamicUser = true; -- cgit 1.4.1 From fa58d89b24611461304f591c64a5539bf1c13a7c Mon Sep 17 00:00:00 2001 From: Elis Hirwing Date: Sun, 25 Jul 2021 18:31:19 +0200 Subject: nixos/syncoid: Reformat file with nixpkgs-fmt --- nixos/modules/services/backup/syncoid.nix | 373 ++++++++++++++++-------------- 1 file changed, 196 insertions(+), 177 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/services/backup/syncoid.nix b/nixos/modules/services/backup/syncoid.nix index 71007f6c38e..61a905a488a 100644 --- a/nixos/modules/services/backup/syncoid.nix +++ b/nixos/modules/services/backup/syncoid.nix @@ -8,206 +8,213 @@ let # Extract local dasaset names (so no datasets containing "@") localDatasetName = d: optionals (d != null) ( let m = builtins.match "([^/@]+[^@]*)" d; in - optionals (m != null) m); + optionals (m != null) m + ); # Escape as required by: https://www.freedesktop.org/software/systemd/man/systemd.unit.html escapeUnitName = name: lib.concatMapStrings (s: if lib.isList s then "-" else s) - (builtins.split "[^a-zA-Z0-9_.\\-]+" name); + (builtins.split "[^a-zA-Z0-9_.\\-]+" name); # Function to build "zfs allow" and "zfs unallow" commands for the # filesystems we've delegated permissions to. buildAllowCommand = zfsAction: permissions: dataset: lib.escapeShellArgs [ # Here we explicitly use the booted system to guarantee the stable API needed by ZFS - "-+/run/booted-system/sw/bin/zfs" zfsAction - cfg.user (concatStringsSep "," permissions) dataset + "-+/run/booted-system/sw/bin/zfs" + zfsAction + cfg.user + (concatStringsSep "," permissions) + dataset ]; -in { +in +{ - # Interface + # Interface - options.services.syncoid = { - enable = mkEnableOption "Syncoid ZFS synchronization service"; + options.services.syncoid = { + enable = mkEnableOption "Syncoid ZFS synchronization service"; - interval = mkOption { - type = types.str; - default = "hourly"; - example = "*-*-* *:15:00"; - description = '' - Run syncoid at this interval. The default is to run hourly. + interval = mkOption { + type = types.str; + default = "hourly"; + example = "*-*-* *:15:00"; + description = '' + Run syncoid at this interval. The default is to run hourly. - The format is described in - systemd.time - 7. - ''; - }; - - user = mkOption { - type = types.str; - default = "syncoid"; - example = "backup"; - description = '' - The user for the service. ZFS privilege delegation will be - automatically configured for any local pools used by syncoid if this - option is set to a user other than root. The user will be given the - "hold" and "send" privileges on any pool that has datasets being sent - and the "create", "mount", "receive", and "rollback" privileges on - any pool that has datasets being received. - ''; - }; + The format is described in + systemd.time + 7. + ''; + }; - group = mkOption { - type = types.str; - default = "syncoid"; - example = "backup"; - description = "The group for the service."; - }; + user = mkOption { + type = types.str; + default = "syncoid"; + example = "backup"; + description = '' + The user for the service. ZFS privilege delegation will be + automatically configured for any local pools used by syncoid if this + option is set to a user other than root. The user will be given the + "hold" and "send" privileges on any pool that has datasets being sent + and the "create", "mount", "receive", and "rollback" privileges on + any pool that has datasets being received. + ''; + }; - sshKey = mkOption { - type = types.nullOr types.path; - # Prevent key from being copied to store - apply = mapNullable toString; - default = null; - description = '' - SSH private key file to use to login to the remote system. Can be - overridden in individual commands. - ''; - }; + group = mkOption { + type = types.str; + default = "syncoid"; + example = "backup"; + description = "The group for the service."; + }; - commonArgs = mkOption { - type = types.listOf types.str; - default = []; - example = [ "--no-sync-snap" ]; - description = '' - Arguments to add to every syncoid command, unless disabled for that - command. See - - for available options. - ''; - }; + sshKey = mkOption { + type = types.nullOr types.path; + # Prevent key from being copied to store + apply = mapNullable toString; + default = null; + description = '' + SSH private key file to use to login to the remote system. Can be + overridden in individual commands. + ''; + }; - service = mkOption { - type = types.attrs; - default = {}; - description = '' - Systemd configuration common to all syncoid services. - ''; - }; + commonArgs = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "--no-sync-snap" ]; + description = '' + Arguments to add to every syncoid command, unless disabled for that + command. See + + for available options. + ''; + }; - commands = mkOption { - type = types.attrsOf (types.submodule ({ name, ... }: { - options = { - source = mkOption { - type = types.str; - example = "pool/dataset"; - description = '' - Source ZFS dataset. Can be either local or remote. Defaults to - the attribute name. - ''; - }; + service = mkOption { + type = types.attrs; + default = { }; + description = '' + Systemd configuration common to all syncoid services. + ''; + }; - target = mkOption { - type = types.str; - example = "user@server:pool/dataset"; - description = '' - Target ZFS dataset. Can be either local - (pool/dataset) or remote - (user@server:pool/dataset). - ''; - }; + commands = mkOption { + type = types.attrsOf (types.submodule ({ name, ... }: { + options = { + source = mkOption { + type = types.str; + example = "pool/dataset"; + description = '' + Source ZFS dataset. Can be either local or remote. Defaults to + the attribute name. + ''; + }; - recursive = mkEnableOption ''the transfer of child datasets''; + target = mkOption { + type = types.str; + example = "user@server:pool/dataset"; + description = '' + Target ZFS dataset. Can be either local + (pool/dataset) or remote + (user@server:pool/dataset). + ''; + }; - sshKey = mkOption { - type = types.nullOr types.path; - # Prevent key from being copied to store - apply = mapNullable toString; - description = '' - SSH private key file to use to login to the remote system. - Defaults to option. - ''; - }; + recursive = mkEnableOption ''the transfer of child datasets''; - sendOptions = mkOption { - type = types.separatedString " "; - default = ""; - example = "Lc e"; - description = '' - Advanced options to pass to zfs send. Options are specified - without their leading dashes and separated by spaces. - ''; - }; + sshKey = mkOption { + type = types.nullOr types.path; + # Prevent key from being copied to store + apply = mapNullable toString; + description = '' + SSH private key file to use to login to the remote system. + Defaults to option. + ''; + }; - recvOptions = mkOption { - type = types.separatedString " "; - default = ""; - example = "ux recordsize o compression=lz4"; - description = '' - Advanced options to pass to zfs recv. Options are specified - without their leading dashes and separated by spaces. - ''; - }; + sendOptions = mkOption { + type = types.separatedString " "; + default = ""; + example = "Lc e"; + description = '' + Advanced options to pass to zfs send. Options are specified + without their leading dashes and separated by spaces. + ''; + }; - useCommonArgs = mkOption { - type = types.bool; - default = true; - description = '' - Whether to add the configured common arguments to this command. - ''; - }; + recvOptions = mkOption { + type = types.separatedString " "; + default = ""; + example = "ux recordsize o compression=lz4"; + description = '' + Advanced options to pass to zfs recv. Options are specified + without their leading dashes and separated by spaces. + ''; + }; - service = mkOption { - type = types.attrs; - default = {}; - description = '' - Systemd configuration specific to this syncoid service. - ''; - }; + useCommonArgs = mkOption { + type = types.bool; + default = true; + description = '' + Whether to add the configured common arguments to this command. + ''; + }; - extraArgs = mkOption { - type = types.listOf types.str; - default = []; - example = [ "--sshport 2222" ]; - description = "Extra syncoid arguments for this command."; - }; + service = mkOption { + type = types.attrs; + default = { }; + description = '' + Systemd configuration specific to this syncoid service. + ''; }; - config = { - source = mkDefault name; - sshKey = mkDefault cfg.sshKey; + + extraArgs = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "--sshport 2222" ]; + description = "Extra syncoid arguments for this command."; }; - })); - default = {}; - example = literalExample '' - { - "pool/test".target = "root@target:pool/test"; - } - ''; - description = "Syncoid commands to run."; - }; + }; + config = { + source = mkDefault name; + sshKey = mkDefault cfg.sshKey; + }; + })); + default = { }; + example = literalExample '' + { + "pool/test".target = "root@target:pool/test"; + } + ''; + description = "Syncoid commands to run."; }; + }; - # Implementation + # Implementation - config = mkIf cfg.enable { - users = { - users = mkIf (cfg.user == "syncoid") { - syncoid = { - group = cfg.group; - isSystemUser = true; - # For syncoid to be able to create /var/lib/syncoid/.ssh/ - # and to use custom ssh_config or known_hosts. - home = "/var/lib/syncoid"; - createHome = false; - }; - }; - groups = mkIf (cfg.group == "syncoid") { - syncoid = {}; + config = mkIf cfg.enable { + users = { + users = mkIf (cfg.user == "syncoid") { + syncoid = { + group = cfg.group; + isSystemUser = true; + # For syncoid to be able to create /var/lib/syncoid/.ssh/ + # and to use custom ssh_config or known_hosts. + home = "/var/lib/syncoid"; + createHome = false; }; }; + groups = mkIf (cfg.group == "syncoid") { + syncoid = { }; + }; + }; - systemd.services = mapAttrs' (name: c: + systemd.services = mapAttrs' + (name: c: nameValuePair "syncoid-${escapeUnitName name}" (mkMerge [ - { description = "Syncoid ZFS synchronization from ${c.source} to ${c.target}"; + { + description = "Syncoid ZFS synchronization from ${c.source} to ${c.target}"; after = [ "zfs.target" ]; startAt = cfg.interval; # syncoid may need zpool to get feature@extensible_dataset @@ -226,11 +233,15 @@ in { ++ optional c.recursive "-r" ++ optionals (c.sshKey != null) [ "--sshkey" c.sshKey ] ++ c.extraArgs - ++ [ "--sendoptions" c.sendOptions - "--recvoptions" c.recvOptions - "--no-privilege-elevation" - c.source c.target - ]); + ++ [ + "--sendoptions" + c.sendOptions + "--recvoptions" + c.recvOptions + "--no-privilege-elevation" + c.source + c.target + ]); User = cfg.user; Group = cfg.group; StateDirectory = [ "syncoid" ]; @@ -246,7 +257,7 @@ in { # systemd-analyze security | grep syncoid-'*' AmbientCapabilities = ""; CapabilityBoundingSet = ""; - DeviceAllow = ["/dev/zfs"]; + DeviceAllow = [ "/dev/zfs" ]; LockPersonality = true; MemoryDenyWriteExecute = true; NoNewPrivileges = true; @@ -272,7 +283,7 @@ in { BindPaths = [ "/dev/zfs" ]; BindReadOnlyPaths = [ builtins.storeDir "/etc" "/run" "/bin/sh" ]; # Avoid useless mounting of RootDirectory= in the own RootDirectory= of ExecStart='s mount namespace. - InaccessiblePaths = ["-+/run/syncoid/${escapeUnitName name}"]; + InaccessiblePaths = [ "-+/run/syncoid/${escapeUnitName name}" ]; MountAPIVFS = true; # Create RootDirectory= in the host's mount namespace. RuntimeDirectory = [ "syncoid/${escapeUnitName name}" ]; @@ -283,8 +294,15 @@ in { # perf stat -x, 2>perf.log -e 'syscalls:sys_enter_*' syncoid … # awk >perf.syscalls -F "," '$1 > 0 {sub("syscalls:sys_enter_","",$3); print $3}' perf.log # systemd-analyze syscall-filter | grep -v -e '#' | sed -e ':loop; /^[^ ]/N; s/\n //; t loop' | grep $(printf ' -e \\<%s\\>' $(cat perf.syscalls)) | cut -f 1 -d ' ' - "~@aio" "~@chown" "~@keyring" "~@memlock" "~@privileged" - "~@resources" "~@setuid" "~@sync" "~@timer" + "~@aio" + "~@chown" + "~@keyring" + "~@memlock" + "~@privileged" + "~@resources" + "~@setuid" + "~@sync" + "~@timer" ]; SystemCallArchitectures = "native"; # This is for BindPaths= and BindReadOnlyPaths= @@ -294,8 +312,9 @@ in { } cfg.service c.service - ])) cfg.commands; - }; + ])) + cfg.commands; + }; - meta.maintainers = with maintainers; [ julm lopsided98 ]; - } + meta.maintainers = with maintainers; [ julm lopsided98 ]; +} -- cgit 1.4.1 From ea9d5876a05a413c199f404696320d8c5f2cb70d Mon Sep 17 00:00:00 2001 From: Elis Hirwing Date: Sun, 25 Jul 2021 18:31:42 +0200 Subject: nixos/sanoid: Reformat file with nixpkgs-fmt --- nixos/modules/services/backup/sanoid.nix | 199 ++++++++++++++++--------------- 1 file changed, 102 insertions(+), 97 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/services/backup/sanoid.nix b/nixos/modules/services/backup/sanoid.nix index c7f276e3f04..41d0e2e1df6 100644 --- a/nixos/modules/services/backup/sanoid.nix +++ b/nixos/modules/services/backup/sanoid.nix @@ -52,7 +52,7 @@ let use_template = mkOption { description = "Names of the templates to use for this dataset."; type = types.listOf (types.enum (attrNames cfg.templates)); - default = []; + default = [ ]; }; useTemplate = use_template; @@ -84,108 +84,113 @@ let dataset ]; - configFile = let - mkValueString = v: - if builtins.isList v then concatStringsSep "," v - else generators.mkValueStringDefault {} v; - - mkKeyValue = k: v: if v == null then "" - else if k == "processChildrenOnly" then "" - else if k == "useTemplate" then "" - else generators.mkKeyValueDefault { inherit mkValueString; } "=" k v; - in generators.toINI { inherit mkKeyValue; } cfg.settings; - -in { - - # Interface - - options.services.sanoid = { - enable = mkEnableOption "Sanoid ZFS snapshotting service"; - - interval = mkOption { - type = types.str; - default = "hourly"; - example = "daily"; - description = '' - Run sanoid at this interval. The default is to run hourly. - - The format is described in - systemd.time - 7. - ''; - }; + configFile = + let + mkValueString = v: + if builtins.isList v then concatStringsSep "," v + else generators.mkValueStringDefault { } v; + + mkKeyValue = k: v: + if v == null then "" + else if k == "processChildrenOnly" then "" + else if k == "useTemplate" then "" + else generators.mkKeyValueDefault { inherit mkValueString; } "=" k v; + in + generators.toINI { inherit mkKeyValue; } cfg.settings; + +in +{ + + # Interface + + options.services.sanoid = { + enable = mkEnableOption "Sanoid ZFS snapshotting service"; + + interval = mkOption { + type = types.str; + default = "hourly"; + example = "daily"; + description = '' + Run sanoid at this interval. The default is to run hourly. + + The format is described in + systemd.time + 7. + ''; + }; - datasets = mkOption { - type = types.attrsOf (types.submodule ({config, options, ...}: { - freeformType = datasetSettingsType; - options = commonOptions // datasetOptions; - config.use_template = mkAliasDefinitions (mkDefault options.useTemplate or {}); - config.process_children_only = mkAliasDefinitions (mkDefault options.processChildrenOnly or {}); - })); - default = {}; - description = "Datasets to snapshot."; - }; + datasets = mkOption { + type = types.attrsOf (types.submodule ({ config, options, ... }: { + freeformType = datasetSettingsType; + options = commonOptions // datasetOptions; + config.use_template = mkAliasDefinitions (mkDefault options.useTemplate or { }); + config.process_children_only = mkAliasDefinitions (mkDefault options.processChildrenOnly or { }); + })); + default = { }; + description = "Datasets to snapshot."; + }; - templates = mkOption { - type = types.attrsOf (types.submodule { - freeformType = datasetSettingsType; - options = commonOptions; - }); - default = {}; - description = "Templates for datasets."; - }; + templates = mkOption { + type = types.attrsOf (types.submodule { + freeformType = datasetSettingsType; + options = commonOptions; + }); + default = { }; + description = "Templates for datasets."; + }; - settings = mkOption { - type = types.attrsOf datasetSettingsType; - description = '' - Free-form settings written directly to the config file. See - - for allowed values. - ''; - }; + settings = mkOption { + type = types.attrsOf datasetSettingsType; + description = '' + Free-form settings written directly to the config file. See + + for allowed values. + ''; + }; - extraArgs = mkOption { - type = types.listOf types.str; - default = []; - example = [ "--verbose" "--readonly" "--debug" ]; - description = '' - Extra arguments to pass to sanoid. See - - for allowed options. - ''; - }; + extraArgs = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "--verbose" "--readonly" "--debug" ]; + description = '' + Extra arguments to pass to sanoid. See + + for allowed options. + ''; }; + }; - # Implementation - - config = mkIf cfg.enable { - services.sanoid.settings = mkMerge [ - (mapAttrs' (d: v: nameValuePair ("template_" + d) v) cfg.templates) - (mapAttrs (d: v: v) cfg.datasets) - ]; - - systemd.services.sanoid = { - description = "Sanoid snapshot service"; - serviceConfig = { - ExecStartPre = (map (buildAllowCommand "allow" [ "snapshot" "mount" "destroy" ]) datasets); - ExecStopPost = (map (buildAllowCommand "unallow" [ "snapshot" "mount" "destroy" ]) datasets); - ExecStart = lib.escapeShellArgs ([ - "${pkgs.sanoid}/bin/sanoid" - "--cron" - "--configdir" (pkgs.writeTextDir "sanoid.conf" configFile) - ] ++ cfg.extraArgs); - User = "sanoid"; - Group = "sanoid"; - DynamicUser = true; - RuntimeDirectory = "sanoid"; - CacheDirectory = "sanoid"; - }; - # Prevents missing snapshots during DST changes - environment.TZ = "UTC"; - after = [ "zfs.target" ]; - startAt = cfg.interval; + # Implementation + + config = mkIf cfg.enable { + services.sanoid.settings = mkMerge [ + (mapAttrs' (d: v: nameValuePair ("template_" + d) v) cfg.templates) + (mapAttrs (d: v: v) cfg.datasets) + ]; + + systemd.services.sanoid = { + description = "Sanoid snapshot service"; + serviceConfig = { + ExecStartPre = (map (buildAllowCommand "allow" [ "snapshot" "mount" "destroy" ]) datasets); + ExecStopPost = (map (buildAllowCommand "unallow" [ "snapshot" "mount" "destroy" ]) datasets); + ExecStart = lib.escapeShellArgs ([ + "${pkgs.sanoid}/bin/sanoid" + "--cron" + "--configdir" + (pkgs.writeTextDir "sanoid.conf" configFile) + ] ++ cfg.extraArgs); + User = "sanoid"; + Group = "sanoid"; + DynamicUser = true; + RuntimeDirectory = "sanoid"; + CacheDirectory = "sanoid"; }; + # Prevents missing snapshots during DST changes + environment.TZ = "UTC"; + after = [ "zfs.target" ]; + startAt = cfg.interval; }; + }; - meta.maintainers = with maintainers; [ lopsided98 ]; - } + meta.maintainers = with maintainers; [ lopsided98 ]; +} -- cgit 1.4.1 From a9d29a1d0ddaad92dd0db5fa913ff714f0e37ebe Mon Sep 17 00:00:00 2001 From: Elis Hirwing Date: Mon, 26 Jul 2021 09:17:10 +0200 Subject: nixos/syncoid: Drop ~[at]sync from the systemcallfilter to avoid coredumps --- nixos/modules/services/backup/syncoid.nix | 1 - 1 file changed, 1 deletion(-) (limited to 'nixos/modules') diff --git a/nixos/modules/services/backup/syncoid.nix b/nixos/modules/services/backup/syncoid.nix index 61a905a488a..73b01d4b53f 100644 --- a/nixos/modules/services/backup/syncoid.nix +++ b/nixos/modules/services/backup/syncoid.nix @@ -301,7 +301,6 @@ in "~@privileged" "~@resources" "~@setuid" - "~@sync" "~@timer" ]; SystemCallArchitectures = "native"; -- cgit 1.4.1