/
mysql-systemd
376 lines (322 loc) · 10.7 KB
/
mysql-systemd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
#!/bin/bash -ue
#
# Scripts to run by PXC systemd service
#
parse_cnf()
{
local var=$1
local def=$2
shift
local groups=$*
reval=$(my_print_defaults $groups | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2- | tail -n 1)
if [[ -z ${reval:-} ]];then
val=$(tr ' ' '\n' <<< "$env_args" | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2- | tail -n 1)
if [[ -n ${val:-} ]];then
reval=$val
else
reval=$def
fi
fi
echo $reval
}
install_db () {
# Note: something different than datadir=/var/lib/mysql requires SELinux policy changes (in enforcing mode)
log=$(parse_cnf log-error server mysqld mysqld_safe)
# Check that pid-file directory exists and has valid permissions
pidfiledir=$(dirname $pid_path)
if [ ! -z $pidfiledir ]; then
[ -d "$pidfiledir" ] || install -d -m 0755 -omysql -gmysql "$pidfiledir" || exit 1
fi
# Restore log, dir, perms and SELinux contexts
[ -d "$datadir" ] || install -d -m 0755 -omysql -gmysql "$datadir" || exit 1
if [ -x /usr/sbin/restorecon ]; then
/usr/sbin/restorecon "$datadir"
if [ ! -z $pidfiledir ]; then
/usr/sbin/restorecon "$pidfiledir"
fi
fi
# If log file is not specified it's put into datadir by default
if [ ! -z $log ]; then
if [ ! -e "$log" -a ! -h "$log" -a x$(dirname "$log") = "x/var/log" ]; then
case $(basename "$log") in
mysql*.log) install /dev/null -m0640 -omysql -gmysql "$log" ;;
*) ;;
esac
fi
if [ -x /usr/sbin/restorecon ]; then
[ -e "$log" ] && /usr/sbin/restorecon $log
fi
fi
# If special mysql dir is in place, skip db install
[ -d "$datadir/mysql" ] && exit 0
if [ -f "$datadir/sst_in_progress" ]; then
rm -rf $datadir/*
fi
# Create initial db
/usr/sbin/mysqld --initialize --datadir="$datadir" --user=mysql
exit 0
}
log_success_msg() {
echo " SUCCESS! $@"
}
log_failure_msg() {
echo " ERROR! $@"
}
log_info_msg() {
echo " INFO: $@"
}
log_warning_msg() {
echo " WARNING: $@"
}
wait_for_pid () {
local verb=$1
local pid_file_path="$2"
local mpid=0
if [[ $verb = 'removed' ]];then
if [[ ! -s $pid_file_path ]];then
log_success_msg
return 0
fi
mpid=$(cat $pid_file_path)
fi
local sst_progress_file=$datadir/sst_in_progress
i=0
while [[ $i -lt $service_startup_timeout ]]; do
set +e
case "$verb" in
'created')
if [[ -s "$pid_file_path" ]]; then
mpid=$(cat $pid_file_path)
if kill -0 $mpid;then
i=''
break
fi
fi
;;
'removed')
if [[ ! -s "$pid_file_path" ]] && ! kill -0 $mpid;then
i=''
break
fi
;;
*)
echo "wait_for_pid () usage: wait_for_pid created|removed pid pid_file_path"
exit 1
;;
esac
set -e
if [[ $verb = 'created' ]];then
if ([[ -e $sst_progress_file ]] || grep -q -- '--wsrep-new-cluster' <<< "$env_args" ) \
&& [[ $startup_sleep -ne 10 ]];then
echo "State transfer in progress, setting sleep higher"
startup_sleep=10
fi
fi
i=$(( i+1 ))
sleep $startup_sleep
if [[ $verb = 'created' ]];then
if ! kill -0 $manager;then
log_failure_msg "mysqld_safe with PID $manager has already exited: FAILURE"
exit 1
fi
fi
done
if [[ -z "$i" ]]; then
log_success_msg
return 0
elif [[ -e $sst_progress_file ]]; then
log_info_msg
return 2
else
log_failure_msg
return 1
fi
}
pinger () {
# Wait for ping to answer to signal startup completed,
# might take a while in case of e.g. crash recovery
# MySQL systemd service will timeout script if no answer
datadir=$(parse_cnf datadir server mysqld)
if [[ -z ${datadir:-} ]]; then
datadir="/var/lib/mysql"
fi
socket=$(parse_cnf socket server mysqld)
case $socket in
/*) adminsocket="$socket" ;;
"") adminsocket="$datadir/mysql.sock" ;;
*) adminsocket="$datadir/$socket" ;;
esac
while /bin/true ; do
sleep 1
mysqladmin --no-defaults --socket="$adminsocket" --user=UNKNOWN_MYSQL_USER ping >/dev/null 2>&1 && break
done
exit 0
}
action=$1
manager=${2:-0}
service_startup_timeout=900
startup_sleep=1
basedir=/usr
bindir="$basedir/bin"
sbindir="$basedir/sbin"
libexecdir="$basedir/libexec"
env_args="${EXTRA_ARGS:-}"
PATH="/sbin:/usr/sbin:/bin:/usr/bin:$bindir:$sbindir"
export PATH
pid_path=$(parse_cnf pid-file "" server mysqld mysqld_safe)
datadir=$(parse_cnf datadir "" server mysqld mysqld_safe)
service_startup_timeout=$(parse_cnf service-startup-timeout $service_startup_timeout mysqld_safe)
if [[ -z ${datadir:-} ]];then
datadir="/var/lib/mysql"
if [[ ! -d $datadir ]];then
echo "FATAL: datadir not found in cnf or is /var/lib/mysql"
exit 2
fi
fi
grastate_loc="${datadir}/grastate.dat"
if [[ -z "${pid_path:-}" ]];then
hostname=$(hostname)
pid_path=$datadir/${hostname%.*}.pid
else
case "$pid_path" in
/* ) ;;
* ) pid_path="$datadir/$pid_path" ;;
esac
fi
if [[ $action == 'reload' || $action == 'stop' || $action == 'stop-post' ]];then
if [[ ! -s $pid_path ]];then
log_warning_msg "mysql pid file $pid_path empty or not readable"
[[ $action == 'stop' ]] && log_failure_msg "mysql already dead"
if [[ $action == 'stop-post' ]];then
log_warning_msg "mysql may be already dead"
exit
fi
exit 2
fi
mysql_pid=$(cat $pid_path)
if [[ $action == 'stop-post' && -n ${mysql_pid:-} ]] && ! kill -0 $mysql_pid;then
log_warning_msg "mysql already dead"
log_failure_msg "Stale PID file: $pid_path"
exit 3
fi
fi
if [[ $action == 'start-post' ]];then
if ! kill -0 $manager;then
log_failure_msg "mysqld_safe with PID $manager has already exited"
exit 1
fi
fi
check_running()
{
if [[ -s $pid_path ]];then
mysql_pid=$(cat $pid_path)
if [[ -n ${mysql_pid:-} ]] && kill -0 $mysql_pid 2>/dev/null;then
mysql_existed_pid=$(ps wwaux | grep mysql | grep "wsrep-new-cluster" | awk '{print $2}')
if [[ ${mysql_pid} == ${mysql_existed_pid} ]]; then
log_warning_msg "PXC is in bootstrap mode. To switch to normal operation, first stop the mysql@bootstrap.service then start the mysql service"
else
log_warning_msg "Another instance of mysqld running on $mysql_pid, exiting.."
fi
exit 1
fi
fi
}
# Run mysqld with --wsrep-recover and parse recovered position from log.
# Position will be stored in wsrep_start_position_opt global.
wsrep_start_position_opt=""
wsrep_recover_position() {
local mysqld_cmd="/usr/sbin/mysqld"
local ret=0
local uuid=""
local seqno=0
local wsrep_logfile=$(mktemp $datadir/wsrep_recovery.XXXXXX)
local err_log=$(parse_cnf log-error server mysqld)
if [ -f $grastate_loc ]; then
uuid=$(grep 'uuid:' $grastate_loc | cut -d: -f2 | tr -d ' ')
seqno=$(grep 'seqno:' $grastate_loc | cut -d: -f2 | tr -d ' ')
# If sequence number is not equal to -1, wsrep-recover co-ordinates aren't used.
# So, directly pass whatever is obtained from grastate.dat
if [ ! -z $seqno ] && [ $seqno -ne -1 ]; then
log_info_msg "Skipping wsrep-recover for $uuid:$seqno pair" >> $wsrep_logfile
log_info_msg "Assigning $uuid:$seqno to wsrep_start_position" >> $wsrep_logfile
wsrep_start_position_opt="--wsrep_start_position=$uuid:$seqno"
if [ -f $err_log ]; then
cat $wsrep_logfile >> $err_log
fi
rm $wsrep_logfile
echo ${wsrep_start_position_opt}
return $ret
fi
fi
local euid=$(id -u)
local wsrep_pidfile="$datadir/"`hostname`"-recover.pid"
local wsrep_verbose_logfile=$(mktemp $datadir/wsrep_recovery_verbose.XXXXXX)
local wr_options="--log_error='$wsrep_verbose_logfile' --pid-file='$wsrep_pidfile'"
[ "$euid" = "0" ] && chown 'mysql' $wsrep_logfile $wsrep_verbose_logfile
chmod 600 $wsrep_logfile $wsrep_verbose_logfile
log_info_msg "WSREP: Running position recovery with $wr_options" >> $wsrep_logfile
eval "$mysqld_cmd --user=mysql --log-error-verbosity=3 --wsrep_recover $wr_options"
local rp="$(grep '\[WSREP\] Recovered position:' $wsrep_verbose_logfile)"
if [ -z "$rp" ]; then
local skipped="$(grep WSREP $wsrep_verbose_logfile | grep 'skipping position recovery')"
if [ -z "$skipped" ]; then
log_failure_msg "WSREP: Failed to recover position: " >> $wsrep_logfile
cat $wsrep_verbose_logfile >> $wsrep_logfile
ret=2
else
log_info_msg "WSREP: Position recovery skipped" >> $wsrep_logfile
fi
else
local start_pos="$(echo $rp | sed 's/.*WSREP\]\ Recovered\ position://' \
| sed 's/^[ \t]*//')"
log_info_msg "WSREP: Recovered position $start_pos" >> $wsrep_logfile
wsrep_start_position_opt="--wsrep_start_position=$start_pos"
fi
if [ -f $err_log ]; then
echo "Log of wsrep recovery (--wsrep-recover):" >> $err_log
cat $wsrep_logfile >> $err_log
fi
rm $wsrep_logfile $wsrep_verbose_logfile
echo ${wsrep_start_position_opt}
return $ret
}
ret=0
case $action in
"galera-recovery") wsrep_recover_position ;;
"start-pre") check_running; install_db ;;
"start-post")
wait_for_pid created "$pid_path"; ret=$?
if [[ $ret -eq 1 ]];then
log_failure_msg "MySQL (Percona XtraDB Cluster) server startup failed!"
elif [[ $ret -eq 2 ]];then
log_info_msg "MySQL (Percona XtraDB Cluster) server startup failed! State transfer still in progress"
fi
exit $ret
;;
"stop-post")
wait_for_pid removed "$pid_path"; ret=$?
if [[ $ret -ne 0 ]];then
log_failure_msg "MySQL (Percona XtraDB Cluster) server stop failed!"
fi
exit $ret
;;
'reload')
kill -HUP $mysql_pid || ret=$?
if [[ $ret -ne 0 ]]; then
log_failure_msg "Failed to reload the server with PID: $mysql_pid with $ret status"
exit $ret
else
log_success_msg "Reloaded the server"
fi
;;
'stop')
kill -TERM $mysql_pid || ret=$?
if [[ $ret -ne 0 ]]; then
log_failure_msg "Failed to stop the server with PID: $mysql_pid with $ret status"
exit $ret
else
log_success_msg "Stopping Percona XtraDB Cluster......"
fi
;;
esac
exit 0