nixpkgs/nixos/modules/services/backup/mysql-backup.nix
Rodney Lorrimar 56eba66f77 mysqlBackup service: let it work with default settings
* Grants enough privileges to the configured user so that it can run
  mysqldump.

* Adds a nixos test.

* Use systemd timers instead of a cronjob (by @fadenb).

* Creates a new user for backups by default, instead of using mysql
  user.

* Ensures that backup user has write permissions on backup location.

* Write backup to a temporary file before renaming so that a failed
  backup won't overwrite the previous backup, and so that the backup
  location will never contain a partial backup.

Breaking changes:

 * Renamed period to calendar to reflect the change in how to
   configure the backup time.

 * A failed backup will no longer result in cron sending an e-mail --
   users' monitoring systems must be updated.

Resolves #24728
2017-09-27 18:44:49 +02:00

131 lines
3 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
inherit (pkgs) mysql gzip;
cfg = config.services.mysqlBackup;
defaultUser = "mysqlbackup";
backupScript = ''
set -o pipefail
failed=""
${concatMapStringsSep "\n" backupDatabaseScript cfg.databases}
if [ -n "$failed" ]; then
echo "Backup of database(s) failed:$failed"
exit 1
fi
'';
backupDatabaseScript = db: ''
dest="${cfg.location}/${db}.gz"
if ${mysql}/bin/mysqldump ${if cfg.singleTransaction then "--single-transaction" else ""} ${db} | ${gzip}/bin/gzip -c > $dest.tmp; then
mv $dest.tmp $dest
echo "Backed up to $dest"
else
echo "Failed to back up to $dest"
rm -f $dest.tmp
failed="$failed ${db}"
fi
'';
in
{
options = {
services.mysqlBackup = {
enable = mkOption {
default = false;
description = ''
Whether to enable MySQL backups.
'';
};
calendar = mkOption {
type = types.str;
default = "01:15:00";
description = ''
Configured when to run the backup service systemd unit (DayOfWeek Year-Month-Day Hour:Minute:Second).
'';
};
user = mkOption {
default = defaultUser;
description = ''
User to be used to perform backup.
'';
};
databases = mkOption {
default = [];
description = ''
List of database names to dump.
'';
};
location = mkOption {
default = "/var/backup/mysql";
description = ''
Location to put the gzipped MySQL database dumps.
'';
};
singleTransaction = mkOption {
default = false;
description = ''
Whether to create database dump in a single transaction
'';
};
};
};
config = mkIf cfg.enable {
users.extraUsers = optionalAttrs (cfg.user == defaultUser) (singleton
{ name = defaultUser;
isSystemUser = true;
createHome = false;
home = cfg.location;
group = "nogroup";
});
services.mysql.ensureUsers = [{
name = cfg.user;
ensurePermissions = with lib;
let
privs = "SELECT, SHOW VIEW, TRIGGER, LOCK TABLES";
grant = db: nameValuePair "${db}.*" privs;
in
listToAttrs (map grant cfg.databases);
}];
systemd = {
timers."mysql-backup" = {
description = "Mysql backup timer";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = cfg.calendar;
AccuracySec = "5m";
Unit = "mysql-backup.service";
};
};
services."mysql-backup" = {
description = "Mysql backup service";
enable = true;
serviceConfig = {
User = cfg.user;
PermissionsStartOnly = true;
};
preStart = ''
mkdir -m 0700 -p ${cfg.location}
chown -R ${cfg.user} ${cfg.location}
'';
script = backupScript;
};
};
};
}