at 25.11-pre 6.0 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.services.borgmatic; 9 settingsFormat = pkgs.formats.yaml { }; 10 11 postgresql = config.services.postgresql.package; 12 mysql = config.services.mysql.package; 13 requireSudo = 14 s: 15 s ? postgresql_databases 16 && lib.any (d: d ? username && !(d ? password) && !(d ? pg_dump_command)) s.postgresql_databases; 17 addRequiredBinaries = 18 s: 19 s 20 // { 21 postgresql_databases = map ( 22 d: 23 let 24 as_user = if d ? username && !(d ? password) then "${pkgs.sudo}/bin/sudo -u ${d.username} " else ""; 25 in 26 { 27 pg_dump_command = 28 if d.name == "all" then 29 "${as_user}${postgresql}/bin/pg_dumpall" 30 else 31 "${as_user}${postgresql}/bin/pg_dump"; 32 pg_restore_command = "${as_user}${postgresql}/bin/pg_restore"; 33 psql_command = "${as_user}${postgresql}/bin/psql"; 34 } 35 // d 36 ) (s.postgresql_databases or [ ]); 37 mariadb_databases = map ( 38 d: 39 { 40 mariadb_dump_command = "${mysql}/bin/mariadb-dump"; 41 mariadb_command = "${mysql}/bin/mariadb"; 42 } 43 // d 44 ) (s.mariadb_databases or [ ]); 45 mysql_databases = map ( 46 d: 47 { 48 mysql_dump_command = "${mysql}/bin/mysqldump"; 49 mysql_command = "${mysql}/bin/mysql"; 50 } 51 // d 52 ) (s.mysql_databases or [ ]); 53 }; 54 55 repository = 56 with lib.types; 57 submodule { 58 options = { 59 path = lib.mkOption { 60 type = str; 61 description = '' 62 Path to the repository 63 ''; 64 }; 65 label = lib.mkOption { 66 type = str; 67 description = '' 68 Label to the repository 69 ''; 70 }; 71 }; 72 }; 73 cfgType = 74 with lib.types; 75 submodule { 76 freeformType = settingsFormat.type; 77 options = { 78 source_directories = lib.mkOption { 79 type = listOf str; 80 default = [ ]; 81 description = '' 82 List of source directories and files to backup. Globs and tildes are 83 expanded. Do not backslash spaces in path names. 84 ''; 85 example = [ 86 "/home" 87 "/etc" 88 "/var/log/syslog*" 89 "/home/user/path with spaces" 90 ]; 91 }; 92 repositories = lib.mkOption { 93 type = listOf repository; 94 default = [ ]; 95 description = '' 96 A required list of local or remote repositories with paths and 97 optional labels (which can be used with the --repository flag to 98 select a repository). Tildes are expanded. Multiple repositories are 99 backed up to in sequence. Borg placeholders can be used. See the 100 output of "borg help placeholders" for details. See ssh_command for 101 SSH options like identity file or port. If systemd service is used, 102 then add local repository paths in the systemd service file to the 103 ReadWritePaths list. 104 ''; 105 example = [ 106 { 107 path = "ssh://user@backupserver/./sourcehostname.borg"; 108 label = "backupserver"; 109 } 110 { 111 path = "/mnt/backup"; 112 label = "local"; 113 } 114 ]; 115 }; 116 }; 117 }; 118 119 cfgfile = settingsFormat.generate "config.yaml" (addRequiredBinaries cfg.settings); 120 121 anycfgRequiresSudo = 122 requireSudo cfg.settings || lib.any requireSudo (lib.attrValues cfg.configurations); 123in 124{ 125 options.services.borgmatic = { 126 enable = lib.mkEnableOption "borgmatic"; 127 128 settings = lib.mkOption { 129 description = '' 130 See https://torsion.org/borgmatic/docs/reference/configuration/ 131 ''; 132 default = null; 133 type = lib.types.nullOr cfgType; 134 }; 135 136 configurations = lib.mkOption { 137 description = '' 138 Set of borgmatic configurations, see https://torsion.org/borgmatic/docs/reference/configuration/ 139 ''; 140 default = { }; 141 type = lib.types.attrsOf cfgType; 142 }; 143 144 enableConfigCheck = lib.mkEnableOption "checking all configurations during build time" // { 145 default = true; 146 }; 147 }; 148 149 config = 150 let 151 configFiles = 152 (lib.optionalAttrs (cfg.settings != null) { "borgmatic/config.yaml".source = cfgfile; }) 153 // lib.mapAttrs' ( 154 name: value: 155 lib.nameValuePair "borgmatic.d/${name}.yaml" { 156 source = settingsFormat.generate "${name}.yaml" (addRequiredBinaries value); 157 } 158 ) cfg.configurations; 159 borgmaticCheck = 160 name: f: 161 pkgs.runCommandCC "${name} validation" { } '' 162 ${pkgs.borgmatic}/bin/borgmatic -c ${f.source} config validate 163 touch $out 164 ''; 165 in 166 lib.mkIf cfg.enable { 167 168 warnings = 169 [ ] 170 ++ 171 lib.optional (cfg.settings != null && cfg.settings ? location) 172 "`services.borgmatic.settings.location` is deprecated, please move your options out of sections to the global scope" 173 ++ 174 lib.optional (lib.catAttrs "location" (lib.attrValues cfg.configurations) != [ ]) 175 "`services.borgmatic.configurations.<name>.location` is deprecated, please move your options out of sections to the global scope"; 176 177 environment.systemPackages = [ pkgs.borgmatic ]; 178 179 environment.etc = configFiles; 180 181 systemd.packages = [ pkgs.borgmatic ]; 182 systemd.services.borgmatic.path = [ pkgs.coreutils ]; 183 systemd.services.borgmatic.serviceConfig = lib.optionalAttrs anycfgRequiresSudo { 184 NoNewPrivileges = false; 185 CapabilityBoundingSet = "CAP_DAC_READ_SEARCH CAP_NET_RAW CAP_SETUID CAP_SETGID"; 186 }; 187 188 # Workaround: https://github.com/NixOS/nixpkgs/issues/81138 189 systemd.timers.borgmatic.wantedBy = [ "timers.target" ]; 190 191 system.checks = lib.mkIf cfg.enableConfigCheck (lib.mapAttrsToList borgmaticCheck configFiles); 192 }; 193}