diff options
Diffstat (limited to 'modules/private/databases/mariadb_replication.nix')
-rw-r--r-- | modules/private/databases/mariadb_replication.nix | 251 |
1 files changed, 0 insertions, 251 deletions
diff --git a/modules/private/databases/mariadb_replication.nix b/modules/private/databases/mariadb_replication.nix deleted file mode 100644 index 68e6f7f..0000000 --- a/modules/private/databases/mariadb_replication.nix +++ /dev/null | |||
@@ -1,251 +0,0 @@ | |||
1 | { pkgs, config, lib, ... }: | ||
2 | let | ||
3 | cfg = config.myServices.databasesReplication.mariadb; | ||
4 | in | ||
5 | { | ||
6 | options.myServices.databasesReplication.mariadb = { | ||
7 | enable = lib.mkEnableOption "Enable mariadb replication"; | ||
8 | base = lib.mkOption { | ||
9 | type = lib.types.path; | ||
10 | description = '' | ||
11 | Base path to put the replications | ||
12 | ''; | ||
13 | }; | ||
14 | hosts = lib.mkOption { | ||
15 | default = {}; | ||
16 | description = '' | ||
17 | Hosts to backup | ||
18 | ''; | ||
19 | type = lib.types.attrsOf (lib.types.submodule { | ||
20 | options = { | ||
21 | package = lib.mkOption { | ||
22 | type = lib.types.package; | ||
23 | default = pkgs.mariadb; | ||
24 | description = '' | ||
25 | Mariadb package for this host | ||
26 | ''; | ||
27 | }; | ||
28 | serverId = lib.mkOption { | ||
29 | type = lib.types.int; | ||
30 | description = '' | ||
31 | Server id to use for replication cluster (must be unique among the cluster!) | ||
32 | ''; | ||
33 | }; | ||
34 | host = lib.mkOption { | ||
35 | type = lib.types.str; | ||
36 | description = '' | ||
37 | Host to connect to | ||
38 | ''; | ||
39 | }; | ||
40 | port = lib.mkOption { | ||
41 | type = lib.types.str; | ||
42 | description = '' | ||
43 | Port to connect to | ||
44 | ''; | ||
45 | }; | ||
46 | user = lib.mkOption { | ||
47 | type = lib.types.str; | ||
48 | description = '' | ||
49 | User to connect as | ||
50 | ''; | ||
51 | }; | ||
52 | password = lib.mkOption { | ||
53 | type = lib.types.str; | ||
54 | description = '' | ||
55 | Password to use | ||
56 | ''; | ||
57 | }; | ||
58 | dumpUser = lib.mkOption { | ||
59 | type = lib.types.str; | ||
60 | description = '' | ||
61 | User who can do a dump | ||
62 | ''; | ||
63 | }; | ||
64 | dumpPassword = lib.mkOption { | ||
65 | type = lib.types.str; | ||
66 | description = '' | ||
67 | Password for the dump user | ||
68 | ''; | ||
69 | }; | ||
70 | }; | ||
71 | }); | ||
72 | }; | ||
73 | }; | ||
74 | |||
75 | config = lib.mkIf cfg.enable { | ||
76 | users.users.mysql = { | ||
77 | description = "MySQL server user"; | ||
78 | group = "mysql"; | ||
79 | uid = config.ids.uids.mysql; | ||
80 | extraGroups = [ "keys" ]; | ||
81 | }; | ||
82 | users.groups.mysql.gid = config.ids.gids.mysql; | ||
83 | |||
84 | secrets.keys = lib.listToAttrs (lib.flatten (lib.mapAttrsToList (name: hcfg: [ | ||
85 | (lib.nameValuePair "mysql_replication/${name}/slave_init_commands" { | ||
86 | user = "mysql"; | ||
87 | group = "mysql"; | ||
88 | permissions = "0400"; | ||
89 | text = '' | ||
90 | CHANGE MASTER TO master_host="${hcfg.host}", master_port=${hcfg.port}, master_user="${hcfg.user}", master_password="${hcfg.password}", master_ssl=1, master_use_gtid=slave_pos; | ||
91 | START SLAVE; | ||
92 | ''; | ||
93 | }) | ||
94 | (lib.nameValuePair "mysql_replication/${name}/mysqldump_remote" { | ||
95 | permissions = "0400"; | ||
96 | user = "root"; | ||
97 | group = "root"; | ||
98 | text = '' | ||
99 | [mysqldump] | ||
100 | user = ${hcfg.user} | ||
101 | password = ${hcfg.password} | ||
102 | ''; | ||
103 | }) | ||
104 | (lib.nameValuePair "mysql_replication/${name}/mysqldump" { | ||
105 | permissions = "0400"; | ||
106 | user = "root"; | ||
107 | group = "root"; | ||
108 | text = '' | ||
109 | [mysqldump] | ||
110 | user = ${hcfg.dumpUser} | ||
111 | password = ${hcfg.dumpPassword} | ||
112 | ''; | ||
113 | }) | ||
114 | (lib.nameValuePair "mysql_replication/${name}/client" { | ||
115 | permissions = "0400"; | ||
116 | user = "mysql"; | ||
117 | group = "mysql"; | ||
118 | text = '' | ||
119 | [client] | ||
120 | user = ${hcfg.dumpUser} | ||
121 | password = ${hcfg.dumpPassword} | ||
122 | ''; | ||
123 | }) | ||
124 | ]) cfg.hosts)); | ||
125 | |||
126 | services.cron = { | ||
127 | enable = true; | ||
128 | systemCronJobs = lib.flatten (lib.mapAttrsToList (name: hcfg: | ||
129 | let | ||
130 | dataDir = "${cfg.base}/${name}/mysql"; | ||
131 | backupDir = "${cfg.base}/${name}/mysql_backup"; | ||
132 | backup_script = pkgs.writeScript "backup_mysql_${name}" '' | ||
133 | #!${pkgs.stdenv.shell} | ||
134 | |||
135 | set -euo pipefail | ||
136 | |||
137 | filename=${backupDir}/$(${pkgs.coreutils}/bin/date -Iminutes).sql | ||
138 | ${hcfg.package}/bin/mysqldump \ | ||
139 | --defaults-file=${config.secrets.fullPaths."mysql_replication/${name}/mysqldump"} \ | ||
140 | -S /run/mysqld_${name}/mysqld.sock \ | ||
141 | --gtid \ | ||
142 | --master-data \ | ||
143 | --flush-privileges \ | ||
144 | --ignore-database=netdata \ | ||
145 | --all-databases > $filename | ||
146 | ${pkgs.gzip}/bin/gzip $filename | ||
147 | ''; | ||
148 | u = pkgs.callPackage ./utils.nix {}; | ||
149 | cleanup_script = pkgs.writeScript "cleanup_mysql_${name}" (u.exponentialDumps "sql.gz" backupDir); | ||
150 | in [ | ||
151 | "0 22,4,10,16 * * * root ${backup_script}" | ||
152 | "0 3 * * * root ${cleanup_script}" | ||
153 | ]) cfg.hosts); | ||
154 | }; | ||
155 | |||
156 | system.activationScripts = lib.attrsets.mapAttrs' (name: hcfg: | ||
157 | lib.attrsets.nameValuePair "mysql_replication_${name}" { | ||
158 | deps = [ "users" "groups" ]; | ||
159 | text = '' | ||
160 | install -m 0700 -o mysql -g mysql -d ${cfg.base}/${name}/mysql | ||
161 | install -m 0700 -o mysql -g mysql -d ${cfg.base}/${name}/mysql_backup | ||
162 | ''; | ||
163 | }) cfg.hosts; | ||
164 | |||
165 | environment.etc = lib.attrsets.mapAttrs' (name: hcfg: | ||
166 | lib.attrsets.nameValuePair "mysql/${name}_my.cnf" { | ||
167 | text = '' | ||
168 | [mysqld] | ||
169 | skip-networking | ||
170 | socket = /run/mysqld_${name}/mysqld.sock | ||
171 | datadir = ${cfg.base}/${name}/mysql/ | ||
172 | log-bin = mariadb-bin | ||
173 | server-id = ${builtins.toString hcfg.serverId} | ||
174 | ''; | ||
175 | } | ||
176 | ) cfg.hosts; | ||
177 | |||
178 | systemd.services = lib.attrsets.mapAttrs' (name: hcfg: | ||
179 | let | ||
180 | dataDir = "${cfg.base}/${name}/mysql"; | ||
181 | in | ||
182 | lib.attrsets.nameValuePair "mysql_backup_${name}" { | ||
183 | description = "Mysql replication for ${name}"; | ||
184 | wantedBy = [ "multi-user.target" ]; | ||
185 | after = [ "network.target" ]; | ||
186 | restartTriggers = [ config.environment.etc."mysql/${name}_my.cnf".source ]; | ||
187 | unitConfig.RequiresMountsFor = dataDir; | ||
188 | |||
189 | preStart = '' | ||
190 | if ! test -e ${dataDir}/mysql; then | ||
191 | if ! test -e ${dataDir}/initial.sql; then | ||
192 | ${hcfg.package}/bin/mysqldump \ | ||
193 | --defaults-file=${config.secrets.fullPaths."mysql_replication/${name}/mysqldump_remote"} \ | ||
194 | -h ${hcfg.host} \ | ||
195 | -P ${hcfg.port} \ | ||
196 | --ssl \ | ||
197 | --gtid \ | ||
198 | --flush-privileges \ | ||
199 | --master-data \ | ||
200 | --all-databases > ${dataDir}/initial.sql | ||
201 | fi | ||
202 | |||
203 | ${hcfg.package}/bin/mysql_install_db \ | ||
204 | --defaults-file=/etc/mysql/${name}_my.cnf \ | ||
205 | --user=mysql \ | ||
206 | --datadir=${dataDir} \ | ||
207 | --basedir=${hcfg.package} | ||
208 | fi | ||
209 | ''; | ||
210 | |||
211 | serviceConfig = { | ||
212 | User = "mysql"; | ||
213 | Group = "mysql"; | ||
214 | RuntimeDirectory = "mysqld_${name}"; | ||
215 | RuntimeDirectoryMode = "0755"; | ||
216 | SupplementaryGroups = "keys"; | ||
217 | PermissionsStartOnly = true; | ||
218 | Type = "notify"; | ||
219 | |||
220 | ExecStart = "${hcfg.package}/bin/mysqld --defaults-file=/etc/mysql/${name}_my.cnf --user=mysql --datadir=${dataDir} --basedir=${hcfg.package}"; | ||
221 | ExecStartPost = | ||
222 | let | ||
223 | sql_before = pkgs.writeText "mysql-initial-before" '' | ||
224 | DROP DATABASE test; | ||
225 | INSTALL SONAME 'auth_pam'; | ||
226 | ''; | ||
227 | setupScript = pkgs.writeScript "mysql-setup" '' | ||
228 | #!${pkgs.runtimeShell} -e | ||
229 | |||
230 | if test -e ${dataDir}/initial.sql; then | ||
231 | cat \ | ||
232 | ${sql_before} \ | ||
233 | ${dataDir}/initial.sql \ | ||
234 | ${config.secrets.fullPaths."mysql_replication/${name}/slave_init_commands"} \ | ||
235 | | ${hcfg.package}/bin/mysql \ | ||
236 | --defaults-file=/etc/mysql/${name}_my.cnf \ | ||
237 | -S /run/mysqld_${name}/mysqld.sock \ | ||
238 | --user=root | ||
239 | rm -f ${dataDir}/initial.sql | ||
240 | fi | ||
241 | ''; | ||
242 | in | ||
243 | "+${setupScript}"; | ||
244 | # initial dump can take a long time | ||
245 | TimeoutStartSec="infinity"; | ||
246 | TimeoutStopSec = 120; | ||
247 | }; | ||
248 | }) cfg.hosts; | ||
249 | }; | ||
250 | } | ||
251 | |||