Merge pull request #83904 from ju1m/sanoid

sanoid: fix sanoid.conf generation

authored by

Sandro and committed by
GitHub
30e2735f 035eabd2

+31 -59
+30 -58
nixos/modules/services/backup/sanoid.nix
··· 10 10 description = "dataset/template options"; 11 11 }; 12 12 13 - # Default values from https://github.com/jimsalterjrs/sanoid/blob/master/sanoid.defaults.conf 14 - 15 13 commonOptions = { 16 14 hourly = mkOption { 17 15 description = "Number of hourly snapshots."; 18 - type = types.ints.unsigned; 19 - default = 48; 16 + type = with types; nullOr ints.unsigned; 17 + default = null; 20 18 }; 21 19 22 20 daily = mkOption { 23 21 description = "Number of daily snapshots."; 24 - type = types.ints.unsigned; 25 - default = 90; 22 + type = with types; nullOr ints.unsigned; 23 + default = null; 26 24 }; 27 25 28 26 monthly = mkOption { 29 27 description = "Number of monthly snapshots."; 30 - type = types.ints.unsigned; 31 - default = 6; 28 + type = with types; nullOr ints.unsigned; 29 + default = null; 32 30 }; 33 31 34 32 yearly = mkOption { 35 33 description = "Number of yearly snapshots."; 36 - type = types.ints.unsigned; 37 - default = 0; 34 + type = with types; nullOr ints.unsigned; 35 + default = null; 38 36 }; 39 37 40 38 autoprune = mkOption { 41 39 description = "Whether to automatically prune old snapshots."; 42 - type = types.bool; 43 - default = true; 40 + type = with types; nullOr bool; 41 + default = null; 44 42 }; 45 43 46 44 autosnap = mkOption { 47 45 description = "Whether to automatically take snapshots."; 48 - type = types.bool; 49 - default = true; 50 - }; 51 - 52 - settings = mkOption { 53 - description = '' 54 - Free-form settings for this template/dataset. See 55 - <link xlink:href="https://github.com/jimsalterjrs/sanoid/blob/master/sanoid.defaults.conf"/> 56 - for allowed values. 57 - ''; 58 - type = datasetSettingsType; 59 - }; 60 - }; 61 - 62 - commonConfig = config: { 63 - settings = { 64 - hourly = mkDefault config.hourly; 65 - daily = mkDefault config.daily; 66 - monthly = mkDefault config.monthly; 67 - yearly = mkDefault config.yearly; 68 - autoprune = mkDefault config.autoprune; 69 - autosnap = mkDefault config.autosnap; 46 + type = with types; nullOr bool; 47 + default = null; 70 48 }; 71 49 }; 72 50 73 - datasetOptions = { 74 - useTemplate = mkOption { 51 + datasetOptions = rec { 52 + use_template = mkOption { 75 53 description = "Names of the templates to use for this dataset."; 76 - type = (types.listOf (types.enum (attrNames cfg.templates))) // { 77 - description = "list of template names"; 78 - }; 54 + type = types.listOf (types.enum (attrNames cfg.templates)); 79 55 default = []; 80 56 }; 57 + useTemplate = use_template; 81 58 82 59 recursive = mkOption { 83 60 description = "Whether to recursively snapshot dataset children."; ··· 85 62 default = false; 86 63 }; 87 64 88 - processChildrenOnly = mkOption { 65 + process_children_only = mkOption { 89 66 description = "Whether to only snapshot child datasets if recursing."; 90 67 type = types.bool; 91 68 default = false; 92 69 }; 93 - }; 94 - 95 - datasetConfig = config: { 96 - settings = { 97 - use_template = mkDefault config.useTemplate; 98 - recursive = mkDefault config.recursive; 99 - process_children_only = mkDefault config.processChildrenOnly; 100 - }; 70 + processChildrenOnly = process_children_only; 101 71 }; 102 72 103 73 # Extract pool names from configured datasets ··· 109 79 else generators.mkValueStringDefault {} v; 110 80 111 81 mkKeyValue = k: v: if v == null then "" 82 + else if k == "processChildrenOnly" then "" 83 + else if k == "useTemplate" then "" 112 84 else generators.mkKeyValueDefault { inherit mkValueString; } "=" k v; 113 85 in generators.toINI { inherit mkKeyValue; } cfg.settings; 114 - 115 - configDir = pkgs.writeTextDir "sanoid.conf" configFile; 116 86 117 87 in { 118 88 ··· 135 105 }; 136 106 137 107 datasets = mkOption { 138 - type = types.attrsOf (types.submodule ({ config, ... }: { 108 + type = types.attrsOf (types.submodule ({config, options, ...}: { 109 + freeformType = datasetSettingsType; 139 110 options = commonOptions // datasetOptions; 140 - config = mkMerge [ (commonConfig config) (datasetConfig config) ]; 111 + config.use_template = mkAliasDefinitions (options.useTemplate or {}); 112 + config.process_children_only = mkAliasDefinitions (options.processChildrenOnly or {}); 141 113 })); 142 114 default = {}; 143 115 description = "Datasets to snapshot."; 144 116 }; 145 117 146 118 templates = mkOption { 147 - type = types.attrsOf (types.submodule ({ config, ... }: { 119 + type = types.attrsOf (types.submodule { 120 + freeformType = datasetSettingsType; 148 121 options = commonOptions; 149 - config = commonConfig config; 150 - })); 122 + }); 151 123 default = {}; 152 124 description = "Templates for datasets."; 153 125 }; ··· 177 149 178 150 config = mkIf cfg.enable { 179 151 services.sanoid.settings = mkMerge [ 180 - (mapAttrs' (d: v: nameValuePair ("template_" + d) v.settings) cfg.templates) 181 - (mapAttrs (d: v: v.settings) cfg.datasets) 152 + (mapAttrs' (d: v: nameValuePair ("template_" + d) v) cfg.templates) 153 + (mapAttrs (d: v: v) cfg.datasets) 182 154 ]; 183 155 184 156 systemd.services.sanoid = { ··· 191 163 ExecStart = lib.escapeShellArgs ([ 192 164 "${pkgs.sanoid}/bin/sanoid" 193 165 "--cron" 194 - "--configdir" configDir 166 + "--configdir" (pkgs.writeTextDir "sanoid.conf" configFile) 195 167 ] ++ cfg.extraArgs); 196 168 ExecStopPost = map (pool: lib.escapeShellArgs [ 197 169 "+/run/booted-system/sw/bin/zfs" "unallow" "sanoid" pool
+1 -1
nixos/tests/sanoid.nix
··· 33 33 34 34 autosnap = true; 35 35 }; 36 - datasets."pool/sanoid".useTemplate = [ "test" ]; 36 + datasets."pool/sanoid".use_template = [ "test" ]; 37 37 extraArgs = [ "--verbose" ]; 38 38 }; 39 39