Skip to content

Commit

Permalink
services.mysqlBackup: add option to change compression tool
Browse files Browse the repository at this point in the history
  • Loading branch information
6543 committed Dec 12, 2024
1 parent f98a28c commit 23ed34c
Showing 1 changed file with 101 additions and 33 deletions.
134 changes: 101 additions & 33 deletions nixos/modules/services/backup/mysql-backup.nix
Original file line number Diff line number Diff line change
@@ -1,16 +1,52 @@
{
config,
lib,
pkgs,
...
}:
{ config, lib, pkgs, ... }:
let

inherit (pkgs) mariadb gzip;
inherit (pkgs) mariadb gzip p7zip zstd zip;

cfg = config.services.mysqlBackup;
defaultUser = "mysqlbackup";

compressionPkg = {
"gzip" = pkgs.gzip;
"zstd" = pkgs.zstd;
"7z" = pkgs.p7zip;
"zip" = pkgs.zip;
}.${cfg.compression};

fileExt = {
"gzip" = ".gz";
"zstd" = ".zst";
"7z" = ".7z";
"zip" = ".zip";
}.${cfg.compression};

validCompressionLevels = {
"zstd" = range: 1 <= range && range <= 19;
"7z" = range: 0 <= range && range <= 9;
"zip" = range: 0 <= range && range <= 9;
"gzip" = range: false; # gzip doesn't use compressionLevel
};

compressionCmd = let
zstdFlags = if cfg.compressionLevel != null then
"-${toString cfg.compressionLevel}"
else
"";
sevenZipFlags = if cfg.compressionLevel != null then
"-mx=${toString cfg.compressionLevel}"
else
"";
zipFlags = if cfg.compressionLevel != null then
"-${toString cfg.compressionLevel}"
else
"";
in {
"gzip" = "${gzip}/bin/gzip -c ${cfg.gzipOptions}";
"zstd" = "${zstd}/bin/zstd ${zstdFlags} -";
"7z" = "${p7zip}/bin/7z a -si -t7z ${sevenZipFlags}";
"zip" = ''
TMPFILE=$(mktemp).sql && cat > "$TMPFILE" && ${zip}/bin/zip ${zipFlags} - "$TMPFILE" && rm -f "$TMPFILE"'';
}.${cfg.compression};

backupScript = ''
set -o pipefail
failed=""
Expand All @@ -20,9 +56,12 @@ let
exit 1
fi
'';

backupDatabaseScript = db: ''
dest="${cfg.location}/${db}.gz"
if ${mariadb}/bin/mysqldump ${lib.optionalString cfg.singleTransaction "--single-transaction"} ${db} | ${gzip}/bin/gzip -c ${cfg.gzipOptions} > $dest.tmp; then
dest="${cfg.location}/${db}${fileExt}"
if ${mariadb}/bin/mysqldump ${
lib.optionalString cfg.singleTransaction "--single-transaction"
} ${db} | ${compressionCmd} > $dest.tmp; then
mv $dest.tmp $dest
echo "Backed up to $dest"
else
Expand All @@ -32,13 +71,9 @@ let
fi
'';

in

{
in {
options = {

services.mysqlBackup = {

enable = lib.mkEnableOption "MySQL backups";

calendar = lib.mkOption {
Expand All @@ -49,6 +84,27 @@ in
'';
};

compression = lib.mkOption {
type = lib.types.enum [ "gzip" "zstd" "7z" "zip" ];
default = "gzip";
description = ''
Compression algorithm to use for database dumps.
Available options: gzip, zstd, 7z, zip
'';
};

compressionLevel = lib.mkOption {
type = lib.types.nullOr lib.types.int;
default = null;
description = ''
Compression level to use for zstd or 7z.
For zstd: 1-19
For 7z: 0-9
For zip: 0-9
Ignored for gzip (use gzipOptions instead)
'';
};

user = lib.mkOption {
type = lib.types.str;
default = defaultUser;
Expand All @@ -69,7 +125,7 @@ in
type = lib.types.path;
default = "/var/backup/mysql";
description = ''
Location to put the gzipped MySQL database dumps.
Location to put the compressed MySQL database dumps.
'';
};

Expand All @@ -86,13 +142,29 @@ in
type = lib.types.str;
description = ''
Command line options to use when invoking `gzip`.
Only used when compression is set to "gzip".
'';
};
};

};

config = lib.mkIf cfg.enable {
# assert config to be correct
assertions = [{
assertion = cfg.compressionLevel == null
|| validCompressionLevels.${cfg.compression} cfg.compressionLevel;
message = let
rangeMsg = {
"zstd" = "zstd compression level must be between 1 and 19";
"7z" = "7z compression level must be between 0 and 9";
"zip" = "zip compression level must be between 0 and 9";
"gzip" =
"gzip does not support compression level option, use gzipOptions instead";
};
in rangeMsg.${cfg.compression};
}];

# ensure unix user to be used to perform backup exist.
users.users = lib.optionalAttrs (cfg.user == defaultUser) {
${defaultUser} = {
isSystemUser = true;
Expand All @@ -102,18 +174,17 @@ in
};
};

services.mysql.ensureUsers = [
{
name = cfg.user;
ensurePermissions =
with lib;
let
privs = "SELECT, SHOW VIEW, TRIGGER, LOCK TABLES";
grant = db: lib.nameValuePair "${db}.*" privs;
in
lib.listToAttrs (map grant cfg.databases);
}
];
# add the compression tool to the system environment.
environment.systemPackages = [ compressionPkg ];

# ensure database user to be used to perform backup exist.
services.mysql.ensureUsers = [{
name = cfg.user;
ensurePermissions = let
privs = "SELECT, SHOW VIEW, TRIGGER, LOCK TABLES";
grant = db: lib.nameValuePair "${db}.*" privs;
in lib.listToAttrs (map grant cfg.databases);
}];

systemd = {
timers.mysql-backup = {
Expand All @@ -134,10 +205,7 @@ in
};
script = backupScript;
};
tmpfiles.rules = [
"d ${cfg.location} 0700 ${cfg.user} - - -"
];
tmpfiles.rules = [ "d ${cfg.location} 0700 ${cfg.user} - - -" ];
};
};

}

0 comments on commit 23ed34c

Please sign in to comment.