1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 inherit (pkgs) mysql gzip;
8
9 cfg = config.services.mysqlBackup;
10 defaultUser = "mysqlbackup";
11
12 backupScript = ''
13 set -o pipefail
14 failed=""
15 ${concatMapStringsSep "\n" backupDatabaseScript cfg.databases}
16 if [ -n "$failed" ]; then
17 echo "Backup of database(s) failed:$failed"
18 exit 1
19 fi
20 '';
21 backupDatabaseScript = db: ''
22 dest="${cfg.location}/${db}.gz"
23 if ${mysql}/bin/mysqldump ${if cfg.singleTransaction then "--single-transaction" else ""} ${db} | ${gzip}/bin/gzip -c > $dest.tmp; then
24 mv $dest.tmp $dest
25 echo "Backed up to $dest"
26 else
27 echo "Failed to back up to $dest"
28 rm -f $dest.tmp
29 failed="$failed ${db}"
30 fi
31 '';
32
33in
34
35{
36 options = {
37
38 services.mysqlBackup = {
39
40 enable = mkOption {
41 default = false;
42 description = ''
43 Whether to enable MySQL backups.
44 '';
45 };
46
47 calendar = mkOption {
48 type = types.str;
49 default = "01:15:00";
50 description = ''
51 Configured when to run the backup service systemd unit (DayOfWeek Year-Month-Day Hour:Minute:Second).
52 '';
53 };
54
55 user = mkOption {
56 default = defaultUser;
57 description = ''
58 User to be used to perform backup.
59 '';
60 };
61
62 databases = mkOption {
63 default = [];
64 description = ''
65 List of database names to dump.
66 '';
67 };
68
69 location = mkOption {
70 default = "/var/backup/mysql";
71 description = ''
72 Location to put the gzipped MySQL database dumps.
73 '';
74 };
75
76 singleTransaction = mkOption {
77 default = false;
78 description = ''
79 Whether to create database dump in a single transaction
80 '';
81 };
82 };
83
84 };
85
86 config = mkIf cfg.enable {
87 users.users = optionalAttrs (cfg.user == defaultUser) (singleton
88 { name = defaultUser;
89 isSystemUser = true;
90 createHome = false;
91 home = cfg.location;
92 group = "nogroup";
93 });
94
95 services.mysql.ensureUsers = [{
96 name = cfg.user;
97 ensurePermissions = with lib;
98 let
99 privs = "SELECT, SHOW VIEW, TRIGGER, LOCK TABLES";
100 grant = db: nameValuePair "${db}.*" privs;
101 in
102 listToAttrs (map grant cfg.databases);
103 }];
104
105 systemd = {
106 timers."mysql-backup" = {
107 description = "Mysql backup timer";
108 wantedBy = [ "timers.target" ];
109 timerConfig = {
110 OnCalendar = cfg.calendar;
111 AccuracySec = "5m";
112 Unit = "mysql-backup.service";
113 };
114 };
115 services."mysql-backup" = {
116 description = "Mysql backup service";
117 enable = true;
118 serviceConfig = {
119 User = cfg.user;
120 PermissionsStartOnly = true;
121 };
122 preStart = ''
123 mkdir -m 0700 -p ${cfg.location}
124 chown -R ${cfg.user} ${cfg.location}
125 '';
126 script = backupScript;
127 };
128 };
129 };
130
131}