summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2024-02-16 17:59:06 -0500
committerAndrew Cady <d@jerkface.net>2024-02-16 17:59:06 -0500
commit9bae4bec1c84abaac80e9ba4bba4fe5b28cacb20 (patch)
treefa881b3bdec82fbd7f7c0afa17a44bac846f57ba /src
parent254c699347896f1faa49e1254d3fa31ae22cafd8 (diff)
renames
Diffstat (limited to 'src')
-rwxr-xr-xsrc/mariadb-copy-cert.mk22
-rwxr-xr-xsrc/mariadb-persist-server-id139
-rwxr-xr-xsrc/mariadb-push-replica.sh541
3 files changed, 0 insertions, 702 deletions
diff --git a/src/mariadb-copy-cert.mk b/src/mariadb-copy-cert.mk
deleted file mode 100755
index d810f30..0000000
--- a/src/mariadb-copy-cert.mk
+++ /dev/null
@@ -1,22 +0,0 @@
1#!/usr/bin/env -S make -f
2domain != hostname --fqdn
3source_dir = /etc/apache2/md/domains/$(domain)
4target_dir = /etc/mysql
5user = mysql
6group = mysql
7source_basenames = privkey.pem pubcert.pem
8target_basenames = server-key.pem server-cert.pem cacert.pem
9source_files = $(addprefix $(source_dir)/,$(source_basenames))
10target_files = $(addprefix $(target_dir)/,$(target_basenames))
11
12INSTALL = install -o $(user) -g $(group)
13
14all: $(target_files)
15$(target_files): $(source_files) | $(target_dir)
16
17$(target_dir):
18 mkdir -p $@
19$(target_dir)/server-key.pem:
20 $(INSTALL) -m 0440 $(source_dir)/privkey.pem -T $@
21$(target_dir)/server-cert.pem $(target_dir)/cacert.pem:
22 $(INSTALL) -m 0444 $(source_dir)/pubcert.pem -T $@
diff --git a/src/mariadb-persist-server-id b/src/mariadb-persist-server-id
deleted file mode 100755
index 33c0245..0000000
--- a/src/mariadb-persist-server-id
+++ /dev/null
@@ -1,139 +0,0 @@
1#!/bin/bash
2# This script edits the file:
3# /etc/mysql/mariadb.conf.d/50-server.cnf
4# The config file will set
5# the server-id to
6# the server-id of
7# the running MariaDB server.
8# The config file is assumed to look like
9# the default Debian configuration file
10# approximately.
11# MariaDB will break if the user
12# has set the server-id in another file.
13set -o pipefail
14set -e
15PATH=$(dirname "$0"):$PATH
16source rpc.bash
17
18use_real_config()
19{
20 MARIADB_CONFIG_FILE=/etc/mysql/mariadb.conf.d/50-server.cnf
21}
22
23use_fake_config()
24{
25 use_real_config
26 OUR_RUNTIME_DIR=/run/hosting-tools
27 mkdir -p "$OUR_RUNTIME_DIR"
28 REAL_MARIADB_CONFIG_FILE=$MARIADB_CONFIG_FILE
29 FAKE_MARIADB_CONFIG_FILE=$OUR_RUNTIME_DIR/50-server.cnf
30 cp -i -a -T -- "$REAL_MARIADB_CONFIG_FILE" "$FAKE_MARIADB_CONFIG_FILE"
31 MARIADB_CONFIG_FILE=$FAKE_MARIADB_CONFIG_FILE
32}
33
34remove_fake_config()
35{
36 rm -f /run/hosting-tools/50-server.cnf
37}
38
39get_mariadb_server_id_from_config()
40{
41 set -- 's/^ *server-id *= *([^ ]+) *$/\1/p'
42 sed -n -E -e "$1" < "${MARIADB_CONFIG_FILE}"
43}
44
45valid_server_id()
46{
47 case "$newid" in
48 '' | *[^0-9]* ) false ;;
49 * ) [ "$newid" -ge 1 ] ;;
50 esac
51}
52
53set_mariadb_server_id_config()
54{
55 OUR_SUFFIX='.~hosting-tools~'
56 MARIADB_CONFIG_FILE_BACKUP=$MARIADB_CONFIG_FILE$OUR_SUFFIX
57 newid=$1
58 if ! valid_server_id "$newid"
59 then
60 echo "Error: Invalid server-id: $newid" >&2
61 return 9
62 fi
63 if grep -q '^ *server-id *=' "$MARIADB_CONFIG_FILE"
64 then
65 set -- s/'^( *server-id *= *)[^ ]+ *$'/'\1'"$newid"/
66 else
67 set -- s/'^#( *server-id *= *)1 *$'/'\1'"$newid"/
68 fi
69 set -- sed -E -i"${OUR_SUFFIX}" -e "$1"
70 "$@" "$MARIADB_CONFIG_FILE"
71}
72
73run_server()
74{
75 local BASH_RPC_REMOTE_DEST="$1"
76 shift
77 remote_run_function "$@"
78}
79
80main()
81{
82 set -e
83 set -o pipefail
84 runtime_server_id=$(mariadb -s <<< 'select @@server_id')
85 if false
86 then
87 use_fake_config
88 else
89 use_real_config
90 fi
91 config_server_id=$(get_mariadb_server_id_from_config)
92 if [ "$runtime_server_id" = "$config_server_id" ]
93 then
94 printf 'Warning: %s\n' \
95 "server-id is already correct. Doing nothing." >&2
96 remove_fake_config
97 return
98 fi
99 set_mariadb_server_id_config "$runtime_server_id"
100 set +e
101 validate_new_server_id "$runtime_server_id"
102 r=$?
103 interactive_show_config_change
104 if [ "$r" = 0 ]
105 then
106 remove_fake_config
107 fi
108 return $r
109}
110
111interactive_show_config_change()
112{
113 (
114 set +e
115 diff -u --color \
116 "$MARIADB_CONFIG_FILE_BACKUP" \
117 "$MARIADB_CONFIG_FILE"
118 [ $? = 1 ]
119 )
120}
121
122validate_new_server_id()
123{
124 expected=$1
125 received=$(get_mariadb_server_id_from_config)
126 if [ "$expected" = "$received" ]
127 then
128 printf 'Success: %s: server-id = %s\n' \
129 "wrote MariaDB config" \
130 "$received" >&2
131 else
132 printf 'Error: %s: server-id = %s\n' \
133 "failed to write MariaDB config" \
134 "$received" >&2
135 false
136 fi
137}
138
139run_server "${1:-root@localhost}" main
diff --git a/src/mariadb-push-replica.sh b/src/mariadb-push-replica.sh
deleted file mode 100755
index cde164c..0000000
--- a/src/mariadb-push-replica.sh
+++ /dev/null
@@ -1,541 +0,0 @@
1#!/bin/bash
2set -e
3PATH=$(dirname "$0"):$PATH
4source rpc.bash
5
6datadir=/etc/hosting-tools
7default_replica_host_file=$datadir/default-replica-host
8replication_password_file=$datadir/replication-password
9
10if [ -r "$default_replica_host_file" ]
11then
12 read default_replica_host < "$default_replica_host_file"
13fi
14
15gen_password()
16{
17 generated_password_length=32
18 generated_password=$(tr -cd a-zA-Z0-9 < /dev/urandom |
19 head -c "$generated_password_length")
20 [ "${#generated_password}" -eq "$generated_password_length" ]
21 printf '%s\n' "$generated_password"
22}
23
24if ! [ -e "$replication_password_file" ]
25then
26 gen_password > "$replication_password_file"
27fi
28
29if [ -r "$replication_password_file" ]
30then
31 read replication_password < "$replication_password_file"
32 [ "${#replication_password}" -ge 30 ]
33fi
34
35primary_host=$(hostname --fqdn)
36if [ $# = 0 ]
37then
38 replica_host=$default_replica_host
39else
40 replica_host=${1:-$default_replica_host}
41 shift
42fi
43replication_user=replication
44
45without_tty_input()
46{
47 if [ -t 0 ]
48 then
49 "$@" < /dev/null
50 else
51 "$@"
52 fi
53}
54
55run_()
56{
57 case "$1" in
58 primary_host | replica_host ) ;;
59 * ) return 58 ;;
60 esac
61 (set -x
62 : ${1%_host} : $2 $3 ${4:+ ...})
63 BASH_RPC_REMOTE_DEST=${!1} \
64 without_tty_input \
65 remote_run_function "${@:2}"
66}
67
68run_primary()
69{
70 run_ primary_host "$@"
71}
72
73run_replica()
74{
75 run_ replica_host "$@"
76}
77
78show_hostnames()
79{
80 printf \
81 "==> %s %s <==\n %s\n" \
82 "$(hostname -A)" \
83 "$(hostname -I)" \
84 "$(uptime)"
85}
86
87stop_mariadb_server_and_remove_database_files()
88{
89 livedb=/var/lib/mysql
90 set -e
91 set -o pipefail
92 [ -e "$livedb" ] || return 0
93 if [ "$(systemctl is-active mariadb)" = active ]
94 then
95 systemctl stop mariadb
96 fi
97 livedb_backup=$livedb~$(date -Ins)
98 mv -v -T -- "$livedb" "$livedb_backup"
99 mkdir "$livedb"
100 chown --reference="$livedb_backup" "$livedb"
101 chmod --reference="$livedb_backup" "$livedb"
102}
103
104silent_unless_error()
105{
106 set -- "$(mktemp)" "$@"
107 if
108 "${@:2}" >"$1" 2>&1
109 then
110 local r=0
111 else
112 local r=$?
113 cat "$1" >&2
114 fi
115 rm "$1"
116 return $r
117}
118
119mostly_silent_unless_error()
120{
121 echo "+ $*" >&2
122 set -- "$(mktemp)" "$@"
123 if
124 "${@:2}" >"$1" 2>&1
125 then
126 tail -n3 "$1" >&2
127 local r=0
128 else
129 local r=$?
130 cat "$1" >&2
131 fi
132 rm "$1"
133 return $r
134}
135
136mariadb_install_replication_credentials()
137{
138 set -e
139 mariadb -v --skip-reconnect -t <<.
140stop slave
141;
142change master
143to
144 master_host = '$1'
145, master_user = '$2'
146, master_password = '$3'
147, master_ssl = 1
148, master_ssl_verify_server_cert = 1
149;
150.
151}
152
153create_and_authorize_replication_user()
154{
155 mariadb --skip-reconnect -t <<.
156create or replace
157user
158 '$2'@'$1'
159identified
160by
161 '$3'
162;
163grant
164 replication replica
165on
166 *.*
167to
168 '$2'@'$1'
169;
170select
171 @@hostname
172 as
173 'primary host'
174, concat (user, '@', host)
175 as
176 login
177, repl_slave_priv
178 as
179 'replica privilege'
180from
181 mysql.user
182where
183 repl_slave_priv = 'Y'
184;
185.
186}
187
188showvars()
189{
190 mariadb --skip-reconnect -t <<.
191select
192 variable_name
193, session_value
194, global_value
195from
196 information_schema.system_variables
197where
198 variable_name like '%slave%state%'
199\G
200.
201}
202
203check_input()
204{
205 [ "$primary_host" ]
206 [ "$replica_host" ]
207 [ "$replication_user" ]
208 [ "$replication_password" ]
209 dns_check_servers
210}
211
212dns_check_servers()
213{
214 primary_ipv4=$(dig +short -ta "$primary_host")
215 replica_ipv4=$(dig +short -ta "$replica_host")
216 echo "primary: $primary_host $primary_ipv4"
217 echo "replica: $replica_host $replica_ipv4"
218}
219
220truncated_machineid_decimal_string_int32()
221{
222 systemd-id128 machine-id |
223 sha256sum |
224 ( read -n8 &&
225 printf '%u\n' 0x"$REPLY" )
226}
227
228run_both()
229{
230 set -e
231 r=0
232 run_primary "$@" || r=$?
233 run_replica "$@"
234 return $r
235}
236
237set_server_id()
238{
239 set -e
240 chosen_id=$(truncated_machineid_decimal_string_int32)
241 [ "$chosen_id" -gt 1 ]
242 mariadb -v --skip-reconnect -t <<.
243set global
244 server_id = $chosen_id
245;
246.
247}
248
249mariadb_enable_semi_sync()
250{
251 set -e
252 [ "$1" = off ] || set -- on
253 mariadb -v --skip-reconnect -t <<.
254stop
255 slave io_thread
256;
257set global
258 rpl_semi_sync_master_enabled = $1
259;
260set global
261 rpl_semi_sync_slave_enabled = $1
262;
263.
264 mariadb_show_vars_like 'rpl_%'
265}
266
267mariadb_show_vars_like()
268{
269 set -e
270 mariadb -v --skip-reconnect -t <<.
271select
272 @@hostname
273, @@server_id
274;
275use
276 information_schema
277;
278select
279 variable_name
280, variable_value
281from
282 global_variables
283where
284 variable_name like '$1'
285;
286.
287}
288
289mariadb_list_databases()
290{
291 show_all_databases >&2
292 mariadb --skip-reconnect -B -s <<.
293select
294 schema_name
295from
296 information_schema.schemata
297;
298.
299}
300
301printlines()
302{
303 printf '%s\n' "$@"
304}
305
306printarray()
307{
308 declare -n _PRINTARRAY_VARNAME="$1"
309 printf '%s\n' "${_PRINTARRAY_VARNAME[@]}"
310}
311
312# Call run_replica from here to avoid
313# piping the database back to caller
314# unnecessarily. Better would be
315# a direct connect from mariadb client
316# to remote mariadb server; but that
317# requires transmitting credentials.
318# Credential-transporter. Transporter-transporter.
319# Well, a transporter protein is more like a provenance tag,
320# and the transporter code is the receptor to the transporter
321# which is the provenance checker. But anyway we have that
322# with ssh, except we don't: we are assuming the primary
323# has the ssh root of the replica! Insanity! Now this only works
324# because the code runs on the primary; unless we forward the
325# ssh auth with the ssh agent; but that only makes the security
326# flaw temporary not solved; in fact, the replica should receive
327# the transmission on some limited authorization channel; which
328# _could_ be ssh; in fact, the dump could transparently be either
329# live or else cached on the server side; it could be the
330# rsync.net backup even; but ... it needs to include
331# the btrfs snap similarly ... .
332send_mariadb_dump()
333{
334 (
335 set -x
336 mariadb-dump "${@:2}"
337 ) |
338 BASH_RPC_REMOTE_DEST=$1 \
339 remote_run_function \
340 receive_mariadb_dump
341}
342
343receive_mariadb_dump()
344{
345 pv -f |
346 tee /var/cache/mariadb-dump.sql |
347 mariadb --skip-reconnect
348}
349
350save_array()
351{
352 declare -n _to_save="$1"
353 case "$2 $3" in
354 'from zfile' )
355 mapfile -d '' -t _to_save < "$4"
356 ;;
357 'from lines' )
358 mapfile -t _to_save < "$4"
359 ;;
360 * )
361 false
362 ;;
363 esac
364}
365
366mariadb_scan_databases()
367{
368 set -- "$(mktemp)"
369 declare -g -a primary_dbs
370 save_array primary_dbs from lines <(
371 run_primary mariadb_list_databases 2>"$1" |
372 sort -u
373 )
374
375 declare -g -a replica_dbs
376 save_array replica_dbs from lines <(
377 run_replica mariadb_list_databases 2>>"$1" |
378 sort -u
379 )
380
381 declare -g -a primary_dbs_not_on_replica
382 save_array primary_dbs_not_on_replica from zfile <(
383 subtract_arrays primary_dbs replica_dbs
384 )
385 if [ ${#primary_dbs_not_on_replica[@]} -gt 0 ]
386 then
387 cat "$1" >&2
388 fi
389 rm -- "$1"
390}
391
392showmissing()
393{
394 if [ ${#primary_dbs_not_on_replica[@]} -gt 0 ]
395 then
396 printf "Missing on ${replica_host}: %s\n" \
397 "${primary_dbs_not_on_replica[@]}" >&2
398 fi
399}
400
401choose_mariadbdump_target_databases()
402{
403 declare -n _target_db_array="$1"
404 shift
405 if [ $# = 0 ]
406 then
407 showmissing
408
409 if [ "$SEND_ALL_MARIADB_DATABASES" ]
410 then
411 _target_db_array=("${primary_dbs_not_on_replica[@]}")
412 else
413 _target_db_array=()
414 fi
415 else
416 save_array _target_db_array from lines \
417 <(intersection_lines \
418 <(printarray primary_dbs_not_on_replica) \
419 <(printlines "$@" | sort -u))
420 fi
421}
422
423intersection_lines()
424{
425 comm -12 -- "$1" "$2"
426}
427
428subtract_arrays()
429{
430 declare -n _a="$1" _b="$2"
431 comm -z -23 -- \
432 <(printf '%s\0' "${_a[@]}") \
433 <(printf '%s\0' "${_b[@]}")
434}
435
436main()
437{
438 set -e
439 check_input
440
441 : run_both set_server_id
442 : run_both mariadb_enable_semi_sync off
443 run_primary create_and_authorize_replication_user \
444 "$replica_host" \
445 "$replication_user" \
446 "$replication_password"
447
448 mariadb_scan_databases
449 choose_mariadbdump_target_databases databases "$@"
450 if [ ${#databases[@]} -gt 0 ]
451 then
452 run_replica \
453 mariadb_install_replication_credentials \
454 "$primary_host" \
455 "$replication_user" \
456 "$replication_password"
457 run_primary \
458 send_mariadb_dump \
459 "$replica_host" \
460 --master-data \
461 --apply-slave-statements \
462 --gtid \
463 --single-transaction \
464 --databases "${databases[@]}"
465 run_replica \
466 show_all_databases
467 fi
468 if gtid=$(run_primary mariadb_get_primary_gtid) &&
469 [ "$gtid" ]
470 then
471 run_replica \
472 mariadb_wait_on_gtid "$gtid"
473 fi
474}
475
476mariadb_get_primary_gtid()
477{
478 mariadb --skip-reconnect -B -s <<.
479select
480 @@gtid_binlog_pos;
481.
482}
483
484mariadb_wait_on_gtid()
485{
486 local gtid="$1"
487 mariadb --skip-reconnect -t <<.
488select
489 @@hostname
490, @@gtid_slave_pos as 'replica gtid'
491, '$gtid' as 'primary gtid'
492;
493stop
494 slave io_thread
495;
496start
497 slave io_thread
498;
499.
500 echo "trying primary_gtid_wait()... " >&2
501 mariadb -t --skip-reconnect <<.
502select
503 master_gtid_wait('$gtid')
504 as \`primary_gtid_wait('$gtid')\`
505;
506.
507}
508
509cleanup_after_test()
510{
511 run_primary delete_backup || true
512}
513
514show_all_databases()
515{
516mariadb --skip-reconnect -t "$@" <<.
517select
518 @@hostname
519, @@server_id
520, count(schema_name) as 'databases'
521, user() as 'login'
522, @@gtid_slave_pos as 'replica gtid'
523, @@gtid_binlog_pos as 'primary gtid'
524from
525 information_schema.schemata
526\G
527select
528 schema_name as 'database name'
529from
530 information_schema.schemata
531;
532.
533}
534
535if false
536then
537 cleanup_after_test
538fi
539SEND_ALL_MARIADB_DATABASES=y
540main "$@"
541exit $?