]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #!/bin/sh |
2 | # | |
3 | # rbd_mirror_helpers.sh - shared rbd-mirror daemon helper functions | |
4 | # | |
5 | # The scripts starts two ("local" and "remote") clusters using mstart.sh script, | |
6 | # creates a temporary directory, used for cluster configs, daemon logs, admin | |
7 | # socket, temporary files, and launches rbd-mirror daemon. | |
8 | # | |
9 | # There are several env variables useful when troubleshooting a test failure: | |
10 | # | |
11fdf7f2 TL |
11 | # RBD_MIRROR_NOCLEANUP - if not empty, don't run the cleanup (stop processes, |
12 | # destroy the clusters and remove the temp directory) | |
13 | # on exit, so it is possible to check the test state | |
14 | # after failure. | |
15 | # RBD_MIRROR_TEMDIR - use this path when creating the temporary directory | |
16 | # (should not exist) instead of running mktemp(1). | |
17 | # RBD_MIRROR_ARGS - use this to pass additional arguments to started | |
18 | # rbd-mirror daemons. | |
19 | # RBD_MIRROR_VARGS - use this to pass additional arguments to vstart.sh | |
20 | # when starting clusters. | |
21 | # RBD_MIRROR_INSTANCES - number of daemons to start per cluster | |
22 | # RBD_MIRROR_CONFIG_KEY - if not empty, use config-key for remote cluster | |
23 | # secrets | |
7c673cae FG |
24 | # The cleanup can be done as a separate step, running the script with |
25 | # `cleanup ${RBD_MIRROR_TEMDIR}' arguments. | |
26 | # | |
9f95a23c | 27 | # Note, as other workunits tests, rbd_mirror_journal.sh expects to find ceph binaries |
7c673cae FG |
28 | # in PATH. |
29 | # | |
30 | # Thus a typical troubleshooting session: | |
31 | # | |
32 | # From Ceph src dir (CEPH_SRC_PATH), start the test in NOCLEANUP mode and with | |
33 | # TEMPDIR pointing to a known location: | |
34 | # | |
35 | # cd $CEPH_SRC_PATH | |
36 | # PATH=$CEPH_SRC_PATH:$PATH | |
37 | # RBD_MIRROR_NOCLEANUP=1 RBD_MIRROR_TEMDIR=/tmp/tmp.rbd_mirror \ | |
9f95a23c | 38 | # ../qa/workunits/rbd/rbd_mirror_journal.sh |
7c673cae FG |
39 | # |
40 | # After the test failure cd to TEMPDIR and check the current state: | |
41 | # | |
42 | # cd /tmp/tmp.rbd_mirror | |
43 | # ls | |
44 | # less rbd-mirror.cluster1_daemon.$pid.log | |
45 | # ceph --cluster cluster1 -s | |
46 | # ceph --cluster cluster1 -s | |
47 | # rbd --cluster cluster2 -p mirror ls | |
48 | # rbd --cluster cluster2 -p mirror journal status --image test | |
49 | # ceph --admin-daemon rbd-mirror.cluster1_daemon.cluster1.$pid.asok help | |
50 | # ... | |
51 | # | |
52 | # Also you can execute commands (functions) from the script: | |
53 | # | |
54 | # cd $CEPH_SRC_PATH | |
55 | # export RBD_MIRROR_TEMDIR=/tmp/tmp.rbd_mirror | |
9f95a23c TL |
56 | # ../qa/workunits/rbd/rbd_mirror_journal.sh status |
57 | # ../qa/workunits/rbd/rbd_mirror_journal.sh stop_mirror cluster1 | |
58 | # ../qa/workunits/rbd/rbd_mirror_journal.sh start_mirror cluster2 | |
59 | # ../qa/workunits/rbd/rbd_mirror_journal.sh flush cluster2 | |
7c673cae FG |
60 | # ... |
61 | # | |
62 | # Eventually, run the cleanup: | |
63 | # | |
64 | # cd $CEPH_SRC_PATH | |
65 | # RBD_MIRROR_TEMDIR=/tmp/tmp.rbd_mirror \ | |
9f95a23c | 66 | # ../qa/workunits/rbd/rbd_mirror_journal.sh cleanup |
7c673cae FG |
67 | # |
68 | ||
11fdf7f2 TL |
69 | if type xmlstarlet > /dev/null 2>&1; then |
70 | XMLSTARLET=xmlstarlet | |
71 | elif type xml > /dev/null 2>&1; then | |
72 | XMLSTARLET=xml | |
73 | else | |
74 | echo "Missing xmlstarlet binary!" | |
75 | exit 1 | |
76 | fi | |
77 | ||
78 | RBD_MIRROR_INSTANCES=${RBD_MIRROR_INSTANCES:-2} | |
79 | ||
7c673cae FG |
80 | CLUSTER1=cluster1 |
81 | CLUSTER2=cluster2 | |
11fdf7f2 | 82 | PEER_CLUSTER_SUFFIX= |
7c673cae FG |
83 | POOL=mirror |
84 | PARENT_POOL=mirror_parent | |
9f95a23c TL |
85 | NS1=ns1 |
86 | NS2=ns2 | |
7c673cae | 87 | TEMPDIR= |
11fdf7f2 | 88 | CEPH_ID=${CEPH_ID:-mirror} |
9f95a23c | 89 | RBD_IMAGE_FEATURES=${RBD_IMAGE_FEATURES:-layering,exclusive-lock,journaling} |
11fdf7f2 | 90 | MIRROR_USER_ID_PREFIX=${MIRROR_USER_ID_PREFIX:-${CEPH_ID}.} |
9f95a23c TL |
91 | MIRROR_POOL_MODE=${MIRROR_POOL_MODE:-pool} |
92 | MIRROR_IMAGE_MODE=${MIRROR_IMAGE_MODE:-journal} | |
93 | ||
11fdf7f2 TL |
94 | export CEPH_ARGS="--id ${CEPH_ID}" |
95 | ||
96 | LAST_MIRROR_INSTANCE=$((${RBD_MIRROR_INSTANCES} - 1)) | |
7c673cae FG |
97 | |
98 | CEPH_ROOT=$(readlink -f $(dirname $0)/../../../src) | |
99 | CEPH_BIN=. | |
100 | CEPH_SRC=. | |
101 | if [ -e CMakeCache.txt ]; then | |
102 | CEPH_SRC=${CEPH_ROOT} | |
103 | CEPH_ROOT=${PWD} | |
104 | CEPH_BIN=./bin | |
105 | ||
106 | # needed for ceph CLI under cmake | |
107 | export LD_LIBRARY_PATH=${CEPH_ROOT}/lib:${LD_LIBRARY_PATH} | |
9f95a23c | 108 | export PYTHONPATH=${PYTHONPATH}:${CEPH_SRC}/pybind:${CEPH_ROOT}/lib/cython_modules/lib.3 |
7c673cae FG |
109 | fi |
110 | ||
111 | # These vars facilitate running this script in an environment with | |
112 | # ceph installed from packages, like teuthology. These are not defined | |
113 | # by default. | |
114 | # | |
115 | # RBD_MIRROR_USE_EXISTING_CLUSTER - if set, do not start and stop ceph clusters | |
116 | # RBD_MIRROR_USE_RBD_MIRROR - if set, use an existing instance of rbd-mirror | |
117 | # running as ceph client $CEPH_ID. If empty, | |
118 | # this script will start and stop rbd-mirror | |
119 | ||
120 | # | |
121 | # Functions | |
122 | # | |
123 | ||
124 | # Parse a value in format cluster[:instance] and set cluster and instance vars. | |
125 | set_cluster_instance() | |
126 | { | |
127 | local val=$1 | |
128 | local cluster_var_name=$2 | |
129 | local instance_var_name=$3 | |
130 | ||
131 | cluster=${val%:*} | |
132 | instance=${val##*:} | |
133 | ||
134 | if [ "${instance}" = "${val}" ]; then | |
9f95a23c TL |
135 | # instance was not specified, use default |
136 | instance=0 | |
7c673cae FG |
137 | fi |
138 | ||
139 | eval ${cluster_var_name}=${cluster} | |
140 | eval ${instance_var_name}=${instance} | |
141 | } | |
142 | ||
143 | daemon_asok_file() | |
144 | { | |
145 | local local_cluster=$1 | |
146 | local cluster=$2 | |
147 | local instance | |
148 | ||
149 | set_cluster_instance "${local_cluster}" local_cluster instance | |
150 | ||
11fdf7f2 | 151 | echo $(ceph-conf --cluster $local_cluster --name "client.${MIRROR_USER_ID_PREFIX}${instance}" 'admin socket') |
7c673cae FG |
152 | } |
153 | ||
154 | daemon_pid_file() | |
155 | { | |
156 | local cluster=$1 | |
157 | local instance | |
158 | ||
159 | set_cluster_instance "${cluster}" cluster instance | |
160 | ||
11fdf7f2 | 161 | echo $(ceph-conf --cluster $cluster --name "client.${MIRROR_USER_ID_PREFIX}${instance}" 'pid file') |
7c673cae FG |
162 | } |
163 | ||
164 | testlog() | |
165 | { | |
166 | echo $(date '+%F %T') $@ | tee -a "${TEMPDIR}/rbd-mirror.test.log" >&2 | |
167 | } | |
168 | ||
169 | expect_failure() | |
170 | { | |
171 | local expected="$1" ; shift | |
172 | local out=${TEMPDIR}/expect_failure.out | |
173 | ||
174 | if "$@" > ${out} 2>&1 ; then | |
175 | cat ${out} >&2 | |
176 | return 1 | |
177 | fi | |
178 | ||
179 | if [ -z "${expected}" ]; then | |
9f95a23c | 180 | return 0 |
7c673cae FG |
181 | fi |
182 | ||
183 | if ! grep -q "${expected}" ${out} ; then | |
184 | cat ${out} >&2 | |
185 | return 1 | |
186 | fi | |
187 | ||
188 | return 0 | |
189 | } | |
190 | ||
9f95a23c TL |
191 | mkfname() |
192 | { | |
193 | echo "$@" | sed -e 's|[/ ]|_|g' | |
194 | } | |
195 | ||
11fdf7f2 | 196 | create_users() |
7c673cae | 197 | { |
11fdf7f2 TL |
198 | local cluster=$1 |
199 | ||
200 | CEPH_ARGS='' ceph --cluster "${cluster}" \ | |
201 | auth get-or-create client.${CEPH_ID} \ | |
9f95a23c | 202 | mon 'profile rbd' osd 'profile rbd' mgr 'profile rbd' >> \ |
11fdf7f2 TL |
203 | ${CEPH_ROOT}/run/${cluster}/keyring |
204 | for instance in `seq 0 ${LAST_MIRROR_INSTANCE}`; do | |
205 | CEPH_ARGS='' ceph --cluster "${cluster}" \ | |
206 | auth get-or-create client.${MIRROR_USER_ID_PREFIX}${instance} \ | |
9f95a23c | 207 | mon 'profile rbd-mirror' osd 'profile rbd' mgr 'profile rbd' >> \ |
11fdf7f2 TL |
208 | ${CEPH_ROOT}/run/${cluster}/keyring |
209 | done | |
210 | } | |
211 | ||
11fdf7f2 TL |
212 | setup_cluster() |
213 | { | |
214 | local cluster=$1 | |
215 | ||
216 | CEPH_ARGS='' ${CEPH_SRC}/mstart.sh ${cluster} -n ${RBD_MIRROR_VARGS} | |
217 | ||
218 | cd ${CEPH_ROOT} | |
219 | rm -f ${TEMPDIR}/${cluster}.conf | |
220 | ln -s $(readlink -f run/${cluster}/ceph.conf) \ | |
221 | ${TEMPDIR}/${cluster}.conf | |
222 | ||
223 | cd ${TEMPDIR} | |
224 | create_users "${cluster}" | |
225 | ||
226 | for instance in `seq 0 ${LAST_MIRROR_INSTANCE}`; do | |
227 | cat<<EOF >> ${TEMPDIR}/${cluster}.conf | |
228 | [client.${MIRROR_USER_ID_PREFIX}${instance}] | |
229 | admin socket = ${TEMPDIR}/rbd-mirror.\$cluster-\$name.asok | |
230 | pid file = ${TEMPDIR}/rbd-mirror.\$cluster-\$name.pid | |
231 | log file = ${TEMPDIR}/rbd-mirror.${cluster}_daemon.${instance}.log | |
232 | EOF | |
233 | done | |
234 | } | |
235 | ||
1911f103 TL |
236 | peer_add() |
237 | { | |
238 | local cluster=$1 ; shift | |
239 | local pool=$1 ; shift | |
240 | local client_cluster=$1 ; shift | |
241 | ||
242 | local uuid_var_name | |
243 | if [ -n "$1" ]; then | |
244 | uuid_var_name=$1 ; shift | |
245 | fi | |
246 | ||
247 | local error_code | |
248 | local peer_uuid | |
249 | ||
250 | for s in 1 2 4 8 16 32; do | |
251 | set +e | |
252 | peer_uuid=$(rbd --cluster ${cluster} mirror pool peer add \ | |
253 | ${pool} ${client_cluster} $@) | |
254 | error_code=$? | |
255 | set -e | |
256 | ||
257 | if [ $error_code -eq 17 ]; then | |
258 | # raced with a remote heartbeat ping -- remove and retry | |
259 | sleep $s | |
260 | rbd --cluster ${cluster} --pool ${pool} mirror pool peer remove ${peer_uuid} | |
261 | else | |
262 | test $error_code -eq 0 | |
263 | if [ -n "$uuid_var_name" ]; then | |
264 | eval ${uuid_var_name}=${peer_uuid} | |
265 | fi | |
266 | return 0 | |
267 | fi | |
268 | done | |
269 | ||
270 | return 1 | |
271 | } | |
272 | ||
11fdf7f2 TL |
273 | setup_pools() |
274 | { | |
275 | local cluster=$1 | |
276 | local remote_cluster=$2 | |
277 | local mon_map_file | |
278 | local mon_addr | |
279 | local admin_key_file | |
280 | local uuid | |
281 | ||
282 | CEPH_ARGS='' ceph --cluster ${cluster} osd pool create ${POOL} 64 64 | |
283 | CEPH_ARGS='' ceph --cluster ${cluster} osd pool create ${PARENT_POOL} 64 64 | |
284 | ||
285 | CEPH_ARGS='' rbd --cluster ${cluster} pool init ${POOL} | |
286 | CEPH_ARGS='' rbd --cluster ${cluster} pool init ${PARENT_POOL} | |
7c673cae | 287 | |
9f95a23c TL |
288 | if [ -n "${RBD_MIRROR_CONFIG_KEY}" ]; then |
289 | PEER_CLUSTER_SUFFIX=-DNE | |
290 | fi | |
291 | ||
292 | CEPH_ARGS='' rbd --cluster ${cluster} mirror pool enable \ | |
293 | --site-name ${cluster}${PEER_CLUSTER_SUFFIX} ${POOL} ${MIRROR_POOL_MODE} | |
11fdf7f2 TL |
294 | rbd --cluster ${cluster} mirror pool enable ${PARENT_POOL} image |
295 | ||
9f95a23c TL |
296 | rbd --cluster ${cluster} namespace create ${POOL}/${NS1} |
297 | rbd --cluster ${cluster} namespace create ${POOL}/${NS2} | |
298 | ||
299 | rbd --cluster ${cluster} mirror pool enable ${POOL}/${NS1} ${MIRROR_POOL_MODE} | |
300 | rbd --cluster ${cluster} mirror pool enable ${POOL}/${NS2} image | |
301 | ||
eafe8130 TL |
302 | if [ -z ${RBD_MIRROR_MANUAL_PEERS} ]; then |
303 | if [ -z ${RBD_MIRROR_CONFIG_KEY} ]; then | |
1911f103 TL |
304 | peer_add ${cluster} ${POOL} ${remote_cluster} |
305 | peer_add ${cluster} ${PARENT_POOL} ${remote_cluster} | |
eafe8130 TL |
306 | else |
307 | mon_map_file=${TEMPDIR}/${remote_cluster}.monmap | |
9f95a23c | 308 | CEPH_ARGS='' ceph --cluster ${remote_cluster} mon getmap > ${mon_map_file} |
eafe8130 TL |
309 | mon_addr=$(monmaptool --print ${mon_map_file} | grep -E 'mon\.' | |
310 | head -n 1 | sed -E 's/^[0-9]+: ([^ ]+).+$/\1/' | sed -E 's/\/[0-9]+//g') | |
311 | ||
312 | admin_key_file=${TEMPDIR}/${remote_cluster}.client.${CEPH_ID}.key | |
313 | CEPH_ARGS='' ceph --cluster ${remote_cluster} auth get-key client.${CEPH_ID} > ${admin_key_file} | |
314 | ||
1911f103 TL |
315 | CEPH_ARGS='' peer_add ${cluster} ${POOL} \ |
316 | client.${CEPH_ID}@${remote_cluster}${PEER_CLUSTER_SUFFIX} '' \ | |
eafe8130 TL |
317 | --remote-mon-host "${mon_addr}" --remote-key-file ${admin_key_file} |
318 | ||
1911f103 | 319 | peer_add ${cluster} ${PARENT_POOL} client.${CEPH_ID}@${remote_cluster}${PEER_CLUSTER_SUFFIX} uuid |
9f95a23c TL |
320 | CEPH_ARGS='' rbd --cluster ${cluster} mirror pool peer set ${PARENT_POOL} ${uuid} mon-host ${mon_addr} |
321 | CEPH_ARGS='' rbd --cluster ${cluster} mirror pool peer set ${PARENT_POOL} ${uuid} key-file ${admin_key_file} | |
eafe8130 | 322 | fi |
11fdf7f2 TL |
323 | fi |
324 | } | |
325 | ||
326 | setup_tempdir() | |
327 | { | |
7c673cae | 328 | if [ -n "${RBD_MIRROR_TEMDIR}" ]; then |
9f95a23c TL |
329 | test -d "${RBD_MIRROR_TEMDIR}" || |
330 | mkdir "${RBD_MIRROR_TEMDIR}" | |
331 | TEMPDIR="${RBD_MIRROR_TEMDIR}" | |
332 | cd ${TEMPDIR} | |
7c673cae | 333 | else |
9f95a23c | 334 | TEMPDIR=`mktemp -d` |
7c673cae | 335 | fi |
11fdf7f2 TL |
336 | } |
337 | ||
338 | setup() | |
339 | { | |
340 | local c | |
341 | trap 'cleanup $?' INT TERM EXIT | |
7c673cae | 342 | |
11fdf7f2 | 343 | setup_tempdir |
7c673cae | 344 | if [ -z "${RBD_MIRROR_USE_EXISTING_CLUSTER}" ]; then |
9f95a23c TL |
345 | setup_cluster "${CLUSTER1}" |
346 | setup_cluster "${CLUSTER2}" | |
7c673cae FG |
347 | fi |
348 | ||
11fdf7f2 TL |
349 | setup_pools "${CLUSTER1}" "${CLUSTER2}" |
350 | setup_pools "${CLUSTER2}" "${CLUSTER1}" | |
9f95a23c TL |
351 | |
352 | if [ -n "${RBD_MIRROR_MIN_COMPAT_CLIENT}" ]; then | |
353 | CEPH_ARGS='' ceph --cluster ${CLUSTER1} osd \ | |
354 | set-require-min-compat-client ${RBD_MIRROR_MIN_COMPAT_CLIENT} | |
355 | CEPH_ARGS='' ceph --cluster ${CLUSTER2} osd \ | |
356 | set-require-min-compat-client ${RBD_MIRROR_MIN_COMPAT_CLIENT} | |
357 | fi | |
7c673cae FG |
358 | } |
359 | ||
360 | cleanup() | |
361 | { | |
11fdf7f2 | 362 | local error_code=$1 |
7c673cae FG |
363 | |
364 | set +e | |
365 | ||
11fdf7f2 TL |
366 | if [ "${error_code}" -ne 0 ]; then |
367 | status | |
368 | fi | |
369 | ||
370 | if [ -z "${RBD_MIRROR_NOCLEANUP}" ]; then | |
371 | local cluster instance | |
7c673cae | 372 | |
c07f9fc5 FG |
373 | CEPH_ARGS='' ceph --cluster ${CLUSTER1} osd pool rm ${POOL} ${POOL} --yes-i-really-really-mean-it |
374 | CEPH_ARGS='' ceph --cluster ${CLUSTER2} osd pool rm ${POOL} ${POOL} --yes-i-really-really-mean-it | |
375 | CEPH_ARGS='' ceph --cluster ${CLUSTER1} osd pool rm ${PARENT_POOL} ${PARENT_POOL} --yes-i-really-really-mean-it | |
376 | CEPH_ARGS='' ceph --cluster ${CLUSTER2} osd pool rm ${PARENT_POOL} ${PARENT_POOL} --yes-i-really-really-mean-it | |
11fdf7f2 TL |
377 | |
378 | for cluster in "${CLUSTER1}" "${CLUSTER2}"; do | |
9f95a23c | 379 | stop_mirrors "${cluster}" |
11fdf7f2 TL |
380 | done |
381 | ||
382 | if [ -z "${RBD_MIRROR_USE_EXISTING_CLUSTER}" ]; then | |
383 | cd ${CEPH_ROOT} | |
384 | CEPH_ARGS='' ${CEPH_SRC}/mstop.sh ${CLUSTER1} | |
385 | CEPH_ARGS='' ${CEPH_SRC}/mstop.sh ${CLUSTER2} | |
386 | fi | |
387 | test "${RBD_MIRROR_TEMDIR}" = "${TEMPDIR}" || rm -Rf ${TEMPDIR} | |
388 | fi | |
389 | ||
390 | if [ "${error_code}" -eq 0 ]; then | |
391 | echo "OK" | |
392 | else | |
393 | echo "FAIL" | |
7c673cae | 394 | fi |
11fdf7f2 TL |
395 | |
396 | exit ${error_code} | |
7c673cae FG |
397 | } |
398 | ||
399 | start_mirror() | |
400 | { | |
401 | local cluster=$1 | |
402 | local instance | |
403 | ||
404 | set_cluster_instance "${cluster}" cluster instance | |
405 | ||
406 | test -n "${RBD_MIRROR_USE_RBD_MIRROR}" && return | |
407 | ||
408 | rbd-mirror \ | |
9f95a23c | 409 | --cluster ${cluster} \ |
11fdf7f2 | 410 | --id ${MIRROR_USER_ID_PREFIX}${instance} \ |
9f95a23c TL |
411 | --rbd-mirror-delete-retry-interval=5 \ |
412 | --rbd-mirror-image-state-check-interval=5 \ | |
413 | --rbd-mirror-journal-poll-age=1 \ | |
414 | --rbd-mirror-pool-replayers-refresh-interval=5 \ | |
415 | --debug-rbd=30 --debug-journaler=30 \ | |
416 | --debug-rbd_mirror=30 \ | |
417 | --daemonize=true \ | |
418 | ${RBD_MIRROR_ARGS} | |
7c673cae FG |
419 | } |
420 | ||
11fdf7f2 TL |
421 | start_mirrors() |
422 | { | |
423 | local cluster=$1 | |
424 | ||
425 | for instance in `seq 0 ${LAST_MIRROR_INSTANCE}`; do | |
426 | start_mirror "${cluster}:${instance}" | |
427 | done | |
428 | } | |
429 | ||
7c673cae FG |
430 | stop_mirror() |
431 | { | |
432 | local cluster=$1 | |
433 | local sig=$2 | |
434 | ||
435 | test -n "${RBD_MIRROR_USE_RBD_MIRROR}" && return | |
436 | ||
437 | local pid | |
438 | pid=$(cat $(daemon_pid_file "${cluster}") 2>/dev/null) || : | |
439 | if [ -n "${pid}" ] | |
440 | then | |
9f95a23c TL |
441 | kill ${sig} ${pid} |
442 | for s in 1 2 4 8 16 32; do | |
443 | sleep $s | |
444 | ps auxww | awk -v pid=${pid} '$2 == pid {print; exit 1}' && break | |
445 | done | |
446 | ps auxww | awk -v pid=${pid} '$2 == pid {print; exit 1}' | |
7c673cae FG |
447 | fi |
448 | rm -f $(daemon_asok_file "${cluster}" "${CLUSTER1}") | |
449 | rm -f $(daemon_asok_file "${cluster}" "${CLUSTER2}") | |
450 | rm -f $(daemon_pid_file "${cluster}") | |
451 | } | |
452 | ||
11fdf7f2 TL |
453 | stop_mirrors() |
454 | { | |
455 | local cluster=$1 | |
456 | local sig=$2 | |
457 | ||
458 | for instance in `seq 0 ${LAST_MIRROR_INSTANCE}`; do | |
459 | stop_mirror "${cluster}:${instance}" "${sig}" | |
460 | done | |
461 | } | |
462 | ||
7c673cae FG |
463 | admin_daemon() |
464 | { | |
465 | local cluster=$1 ; shift | |
466 | local instance | |
467 | ||
468 | set_cluster_instance "${cluster}" cluster instance | |
469 | ||
470 | local asok_file=$(daemon_asok_file "${cluster}:${instance}" "${cluster}") | |
471 | test -S "${asok_file}" | |
472 | ||
473 | ceph --admin-daemon ${asok_file} $@ | |
474 | } | |
475 | ||
11fdf7f2 TL |
476 | admin_daemons() |
477 | { | |
478 | local cluster_instance=$1 ; shift | |
479 | local cluster="${cluster_instance%:*}" | |
480 | local instance="${cluster_instance##*:}" | |
481 | local loop_instance | |
482 | ||
483 | for s in 0 1 2 4 8 8 8 8 8 8 8 8 16 16; do | |
9f95a23c TL |
484 | sleep ${s} |
485 | if [ "${instance}" != "${cluster_instance}" ]; then | |
486 | admin_daemon "${cluster}:${instance}" $@ && return 0 | |
487 | else | |
488 | for loop_instance in `seq 0 ${LAST_MIRROR_INSTANCE}`; do | |
489 | admin_daemon "${cluster}:${loop_instance}" $@ && return 0 | |
490 | done | |
491 | fi | |
11fdf7f2 TL |
492 | done |
493 | return 1 | |
494 | } | |
495 | ||
496 | all_admin_daemons() | |
497 | { | |
498 | local cluster=$1 ; shift | |
499 | ||
500 | for instance in `seq 0 ${LAST_MIRROR_INSTANCE}`; do | |
9f95a23c | 501 | admin_daemon "${cluster}:${instance}" $@ |
11fdf7f2 TL |
502 | done |
503 | } | |
504 | ||
7c673cae FG |
505 | status() |
506 | { | |
9f95a23c | 507 | local cluster daemon image_pool image_ns image |
7c673cae FG |
508 | |
509 | for cluster in ${CLUSTER1} ${CLUSTER2} | |
510 | do | |
9f95a23c TL |
511 | echo "${cluster} status" |
512 | CEPH_ARGS='' ceph --cluster ${cluster} -s | |
513 | CEPH_ARGS='' ceph --cluster ${cluster} service dump | |
514 | CEPH_ARGS='' ceph --cluster ${cluster} service status | |
515 | echo | |
516 | ||
517 | for image_pool in ${POOL} ${PARENT_POOL} | |
518 | do | |
519 | for image_ns in "" "${NS1}" "${NS2}" | |
520 | do | |
521 | echo "${cluster} ${image_pool} ${image_ns} images" | |
522 | rbd --cluster ${cluster} -p ${image_pool} --namespace "${image_ns}" ls -l | |
523 | echo | |
524 | ||
525 | echo "${cluster} ${image_pool}${image_ns} mirror pool info" | |
526 | rbd --cluster ${cluster} -p ${image_pool} --namespace "${image_ns}" mirror pool info | |
527 | echo | |
528 | ||
529 | echo "${cluster} ${image_pool}${image_ns} mirror pool status" | |
530 | CEPH_ARGS='' rbd --cluster ${cluster} -p ${image_pool} --namespace "${image_ns}" mirror pool status --verbose | |
531 | echo | |
532 | ||
533 | for image in `rbd --cluster ${cluster} -p ${image_pool} --namespace "${image_ns}" ls 2>/dev/null` | |
534 | do | |
535 | echo "image ${image} info" | |
536 | rbd --cluster ${cluster} -p ${image_pool} --namespace "${image_ns}" info ${image} | |
537 | echo | |
538 | echo "image ${image} journal status" | |
539 | rbd --cluster ${cluster} -p ${image_pool} --namespace "${image_ns}" journal status --image ${image} | |
540 | echo | |
541 | done | |
542 | ||
543 | echo "${cluster} ${image_pool} ${image_ns} rbd_mirroring omap vals" | |
544 | rados --cluster ${cluster} -p ${image_pool} --namespace "${image_ns}" listomapvals rbd_mirroring | |
545 | echo | |
546 | done | |
547 | done | |
7c673cae FG |
548 | done |
549 | ||
550 | local ret | |
551 | ||
552 | for cluster in "${CLUSTER1}" "${CLUSTER2}" | |
553 | do | |
9f95a23c TL |
554 | for instance in `seq 0 ${LAST_MIRROR_INSTANCE}`; do |
555 | local pid_file=$(daemon_pid_file ${cluster}:${instance}) | |
556 | if [ ! -e ${pid_file} ] | |
557 | then | |
558 | echo "${cluster} rbd-mirror not running or unknown" \ | |
559 | "(${pid_file} not exist)" | |
560 | continue | |
561 | fi | |
562 | ||
563 | local pid | |
564 | pid=$(cat ${pid_file} 2>/dev/null) || : | |
565 | if [ -z "${pid}" ] | |
566 | then | |
567 | echo "${cluster} rbd-mirror not running or unknown" \ | |
568 | "(can't find pid using ${pid_file})" | |
569 | ret=1 | |
570 | continue | |
571 | fi | |
572 | ||
573 | echo "${daemon} rbd-mirror process in ps output:" | |
574 | if ps auxww | | |
575 | awk -v pid=${pid} 'NR == 1 {print} $2 == pid {print; exit 1}' | |
576 | then | |
577 | echo | |
578 | echo "${cluster} rbd-mirror not running" \ | |
579 | "(can't find pid $pid in ps output)" | |
580 | ret=1 | |
581 | continue | |
582 | fi | |
583 | echo | |
584 | ||
585 | local asok_file=$(daemon_asok_file ${cluster}:${instance} ${cluster}) | |
586 | if [ ! -S "${asok_file}" ] | |
587 | then | |
588 | echo "${cluster} rbd-mirror asok is unknown (${asok_file} not exits)" | |
589 | ret=1 | |
590 | continue | |
591 | fi | |
592 | ||
593 | echo "${cluster} rbd-mirror status" | |
594 | ceph --admin-daemon ${asok_file} rbd mirror status | |
595 | echo | |
596 | done | |
7c673cae FG |
597 | done |
598 | ||
599 | return ${ret} | |
600 | } | |
601 | ||
602 | flush() | |
603 | { | |
604 | local cluster=$1 | |
605 | local pool=$2 | |
606 | local image=$3 | |
607 | local cmd="rbd mirror flush" | |
608 | ||
609 | if [ -n "${image}" ] | |
610 | then | |
611 | cmd="${cmd} ${pool}/${image}" | |
612 | fi | |
613 | ||
11fdf7f2 | 614 | admin_daemons "${cluster}" ${cmd} |
7c673cae FG |
615 | } |
616 | ||
617 | test_image_replay_state() | |
618 | { | |
619 | local cluster=$1 | |
620 | local pool=$2 | |
621 | local image=$3 | |
622 | local test_state=$4 | |
11fdf7f2 | 623 | local status_result |
7c673cae FG |
624 | local current_state=stopped |
625 | ||
11fdf7f2 TL |
626 | status_result=$(admin_daemons "${cluster}" rbd mirror status ${pool}/${image} | grep -i 'state') || return 1 |
627 | echo "${status_result}" | grep -i 'Replaying' && current_state=started | |
7c673cae FG |
628 | test "${test_state}" = "${current_state}" |
629 | } | |
630 | ||
631 | wait_for_image_replay_state() | |
632 | { | |
633 | local cluster=$1 | |
634 | local pool=$2 | |
635 | local image=$3 | |
636 | local state=$4 | |
637 | local s | |
638 | ||
639 | # TODO: add a way to force rbd-mirror to update replayers | |
640 | for s in 1 2 4 8 8 8 8 8 8 8 8 16 16; do | |
9f95a23c TL |
641 | sleep ${s} |
642 | test_image_replay_state "${cluster}" "${pool}" "${image}" "${state}" && return 0 | |
7c673cae FG |
643 | done |
644 | return 1 | |
645 | } | |
646 | ||
647 | wait_for_image_replay_started() | |
648 | { | |
649 | local cluster=$1 | |
650 | local pool=$2 | |
651 | local image=$3 | |
652 | ||
653 | wait_for_image_replay_state "${cluster}" "${pool}" "${image}" started | |
654 | } | |
655 | ||
656 | wait_for_image_replay_stopped() | |
657 | { | |
658 | local cluster=$1 | |
659 | local pool=$2 | |
660 | local image=$3 | |
661 | ||
662 | wait_for_image_replay_state "${cluster}" "${pool}" "${image}" stopped | |
663 | } | |
664 | ||
9f95a23c | 665 | get_journal_position() |
7c673cae FG |
666 | { |
667 | local cluster=$1 | |
668 | local pool=$2 | |
669 | local image=$3 | |
670 | local id_regexp=$4 | |
671 | ||
672 | # Parse line like below, looking for the first position | |
673 | # [id=, commit_position=[positions=[[object_number=1, tag_tid=3, entry_tid=9], [object_number=0, tag_tid=3, entry_tid=8], [object_number=3, tag_tid=3, entry_tid=7], [object_number=2, tag_tid=3, entry_tid=6]]]] | |
674 | ||
9f95a23c TL |
675 | local status_log=${TEMPDIR}/$(mkfname ${CLUSTER2}-${pool}-${image}.status) |
676 | rbd --cluster ${cluster} journal status --image ${pool}/${image} | | |
677 | tee ${status_log} >&2 | |
7c673cae | 678 | sed -nEe 's/^.*\[id='"${id_regexp}"',.*positions=\[\[([^]]*)\],.*state=connected.*$/\1/p' \ |
9f95a23c | 679 | ${status_log} |
7c673cae FG |
680 | } |
681 | ||
9f95a23c | 682 | get_master_journal_position() |
7c673cae FG |
683 | { |
684 | local cluster=$1 | |
685 | local pool=$2 | |
686 | local image=$3 | |
687 | ||
9f95a23c | 688 | get_journal_position "${cluster}" "${pool}" "${image}" '' |
7c673cae FG |
689 | } |
690 | ||
9f95a23c | 691 | get_mirror_journal_position() |
7c673cae FG |
692 | { |
693 | local cluster=$1 | |
694 | local pool=$2 | |
695 | local image=$3 | |
696 | ||
9f95a23c | 697 | get_journal_position "${cluster}" "${pool}" "${image}" '..*' |
7c673cae FG |
698 | } |
699 | ||
9f95a23c | 700 | wait_for_journal_replay_complete() |
7c673cae FG |
701 | { |
702 | local local_cluster=$1 | |
703 | local cluster=$2 | |
704 | local pool=$3 | |
705 | local image=$4 | |
706 | local s master_pos mirror_pos last_mirror_pos | |
707 | local master_tag master_entry mirror_tag mirror_entry | |
708 | ||
709 | while true; do | |
710 | for s in 0.2 0.4 0.8 1.6 2 2 4 4 8 8 16 16 32 32; do | |
9f95a23c TL |
711 | sleep ${s} |
712 | flush "${local_cluster}" "${pool}" "${image}" | |
713 | master_pos=$(get_master_journal_position "${cluster}" "${pool}" "${image}") | |
714 | mirror_pos=$(get_mirror_journal_position "${cluster}" "${pool}" "${image}") | |
715 | test -n "${master_pos}" -a "${master_pos}" = "${mirror_pos}" && return 0 | |
7c673cae FG |
716 | test "${mirror_pos}" != "${last_mirror_pos}" && break |
717 | done | |
718 | ||
719 | test "${mirror_pos}" = "${last_mirror_pos}" && return 1 | |
720 | last_mirror_pos="${mirror_pos}" | |
721 | ||
722 | # handle the case where the mirror is ahead of the master | |
723 | master_tag=$(echo "${master_pos}" | grep -Eo "tag_tid=[0-9]*" | cut -d'=' -f 2) | |
724 | mirror_tag=$(echo "${mirror_pos}" | grep -Eo "tag_tid=[0-9]*" | cut -d'=' -f 2) | |
725 | master_entry=$(echo "${master_pos}" | grep -Eo "entry_tid=[0-9]*" | cut -d'=' -f 2) | |
726 | mirror_entry=$(echo "${mirror_pos}" | grep -Eo "entry_tid=[0-9]*" | cut -d'=' -f 2) | |
727 | test "${master_tag}" = "${mirror_tag}" -a ${master_entry} -le ${mirror_entry} && return 0 | |
728 | done | |
729 | return 1 | |
730 | } | |
731 | ||
9f95a23c TL |
732 | mirror_image_snapshot() |
733 | { | |
734 | local cluster=$1 | |
735 | local pool=$2 | |
736 | local image=$3 | |
737 | ||
738 | rbd --cluster "${cluster}" mirror image snapshot "${pool}/${image}" | |
739 | } | |
740 | ||
741 | get_newest_mirror_snapshot() | |
742 | { | |
743 | local cluster=$1 | |
744 | local pool=$2 | |
745 | local image=$3 | |
746 | local log=$4 | |
747 | ||
748 | rbd --cluster "${cluster}" snap list --all "${pool}/${image}" --format xml | \ | |
749 | xmlstarlet sel -t -c "//snapshots/snapshot[namespace/complete='true' and position()=last()]" > \ | |
750 | ${log} || true | |
751 | } | |
752 | ||
753 | wait_for_snapshot_sync_complete() | |
754 | { | |
755 | local local_cluster=$1 | |
756 | local cluster=$2 | |
757 | local pool=$3 | |
758 | local image=$4 | |
759 | ||
760 | local status_log=${TEMPDIR}/$(mkfname ${cluster}-${pool}-${image}.status) | |
761 | local local_status_log=${TEMPDIR}/$(mkfname ${local_cluster}-${pool}-${image}.status) | |
762 | ||
763 | mirror_image_snapshot "${cluster}" "${pool}" "${image}" | |
764 | get_newest_mirror_snapshot "${cluster}" "${pool}" "${image}" "${status_log}" | |
765 | local snapshot_id=$(xmlstarlet sel -t -v "//snapshot/id" < ${status_log}) | |
766 | ||
767 | while true; do | |
768 | for s in 0.2 0.4 0.8 1.6 2 2 4 4 8 8 16 16 32 32; do | |
769 | sleep ${s} | |
770 | ||
771 | get_newest_mirror_snapshot "${local_cluster}" "${pool}" "${image}" "${local_status_log}" | |
772 | local primary_snapshot_id=$(xmlstarlet sel -t -v "//snapshot/namespace/primary_snap_id" < ${local_status_log}) | |
773 | ||
774 | test "${snapshot_id}" = "${primary_snapshot_id}" && return 0 | |
775 | done | |
776 | ||
777 | return 1 | |
778 | done | |
779 | return 1 | |
780 | } | |
781 | ||
782 | wait_for_replay_complete() | |
783 | { | |
784 | local local_cluster=$1 | |
785 | local cluster=$2 | |
786 | local pool=$3 | |
787 | local image=$4 | |
788 | ||
789 | if [ "${MIRROR_IMAGE_MODE}" = "journal" ]; then | |
790 | wait_for_journal_replay_complete ${local_cluster} ${cluster} ${pool} ${image} | |
791 | elif [ "${MIRROR_IMAGE_MODE}" = "snapshot" ]; then | |
792 | wait_for_snapshot_sync_complete ${local_cluster} ${cluster} ${pool} ${image} | |
793 | else | |
794 | return 1 | |
795 | fi | |
796 | } | |
797 | ||
798 | ||
7c673cae FG |
799 | test_status_in_pool_dir() |
800 | { | |
801 | local cluster=$1 | |
802 | local pool=$2 | |
803 | local image=$3 | |
11fdf7f2 TL |
804 | local state_pattern="$4" |
805 | local description_pattern="$5" | |
806 | local service_pattern="$6" | |
7c673cae | 807 | |
9f95a23c TL |
808 | local status_log=${TEMPDIR}/$(mkfname ${cluster}-${pool}-${image}.mirror_status) |
809 | CEPH_ARGS='' rbd --cluster ${cluster} mirror image status ${pool}/${image} | | |
810 | tee ${status_log} >&2 | |
811 | grep "^ state: .*${state_pattern}" ${status_log} || return 1 | |
812 | grep "^ description: .*${description_pattern}" ${status_log} || return 1 | |
11fdf7f2 TL |
813 | |
814 | if [ -n "${service_pattern}" ]; then | |
815 | grep "service: *${service_pattern}" ${status_log} || return 1 | |
816 | elif echo ${state_pattern} | grep '^up+'; then | |
817 | grep "service: *${MIRROR_USER_ID_PREFIX}.* on " ${status_log} || return 1 | |
818 | else | |
819 | grep "service: " ${status_log} && return 1 | |
820 | fi | |
821 | ||
eafe8130 TL |
822 | # recheck using `mirror pool status` command to stress test it. |
823 | ||
9f95a23c | 824 | local last_update="$(sed -nEe 's/^ last_update: *(.*) *$/\1/p' ${status_log})" |
eafe8130 TL |
825 | test_mirror_pool_status_verbose \ |
826 | ${cluster} ${pool} ${image} "${state_pattern}" "${last_update}" && | |
11fdf7f2 | 827 | return 0 |
eafe8130 TL |
828 | |
829 | echo "'mirror pool status' test failed" >&2 | |
830 | exit 1 | |
831 | } | |
832 | ||
833 | test_mirror_pool_status_verbose() | |
834 | { | |
835 | local cluster=$1 | |
836 | local pool=$2 | |
837 | local image=$3 | |
838 | local state_pattern="$4" | |
839 | local prev_last_update="$5" | |
840 | ||
9f95a23c | 841 | local status_log=${TEMPDIR}/$(mkfname ${cluster}-${pool}.mirror_status) |
eafe8130 TL |
842 | |
843 | rbd --cluster ${cluster} mirror pool status ${pool} --verbose --format xml \ | |
844 | > ${status_log} | |
845 | ||
846 | local last_update state | |
847 | last_update=$($XMLSTARLET sel -t -v \ | |
848 | "//images/image[name='${image}']/last_update" < ${status_log}) | |
849 | state=$($XMLSTARLET sel -t -v \ | |
850 | "//images/image[name='${image}']/state" < ${status_log}) | |
851 | ||
852 | echo "${state}" | grep "${state_pattern}" || | |
853 | test "${last_update}" '>' "${prev_last_update}" | |
7c673cae FG |
854 | } |
855 | ||
856 | wait_for_status_in_pool_dir() | |
857 | { | |
858 | local cluster=$1 | |
859 | local pool=$2 | |
860 | local image=$3 | |
11fdf7f2 TL |
861 | local state_pattern="$4" |
862 | local description_pattern="$5" | |
863 | local service_pattern="$6" | |
7c673cae FG |
864 | |
865 | for s in 1 2 4 8 8 8 8 8 8 8 8 16 16; do | |
9f95a23c TL |
866 | sleep ${s} |
867 | test_status_in_pool_dir ${cluster} ${pool} ${image} "${state_pattern}" \ | |
11fdf7f2 TL |
868 | "${description_pattern}" "${service_pattern}" && |
869 | return 0 | |
7c673cae FG |
870 | done |
871 | return 1 | |
872 | } | |
873 | ||
874 | create_image() | |
875 | { | |
876 | local cluster=$1 ; shift | |
877 | local pool=$1 ; shift | |
878 | local image=$1 ; shift | |
879 | local size=128 | |
880 | ||
881 | if [ -n "$1" ]; then | |
9f95a23c TL |
882 | size=$1 |
883 | shift | |
7c673cae FG |
884 | fi |
885 | ||
9f95a23c TL |
886 | rbd --cluster ${cluster} create --size ${size} \ |
887 | --image-feature "${RBD_IMAGE_FEATURES}" $@ ${pool}/${image} | |
888 | } | |
889 | ||
890 | create_image_and_enable_mirror() | |
891 | { | |
892 | local cluster=$1 ; shift | |
893 | local pool=$1 ; shift | |
894 | local image=$1 ; shift | |
895 | local mode=${1:-${MIRROR_IMAGE_MODE}} | |
896 | if [ -n "$1" ]; then | |
897 | shift | |
898 | fi | |
899 | ||
900 | create_image ${cluster} ${pool} ${image} $@ | |
901 | enable_mirror ${cluster} ${pool} ${image} ${mode} | |
902 | } | |
903 | ||
904 | enable_journaling() | |
905 | { | |
906 | local cluster=$1 | |
907 | local pool=$2 | |
908 | local image=$3 | |
909 | ||
910 | rbd --cluster ${cluster} feature enable ${pool}/${image} journaling | |
7c673cae FG |
911 | } |
912 | ||
913 | set_image_meta() | |
914 | { | |
915 | local cluster=$1 | |
916 | local pool=$2 | |
917 | local image=$3 | |
918 | local key=$4 | |
919 | local val=$5 | |
920 | ||
9f95a23c | 921 | rbd --cluster ${cluster} image-meta set ${pool}/${image} $key $val |
7c673cae FG |
922 | } |
923 | ||
b32b8144 FG |
924 | compare_image_meta() |
925 | { | |
926 | local cluster=$1 | |
927 | local pool=$2 | |
928 | local image=$3 | |
929 | local key=$4 | |
930 | local value=$5 | |
931 | ||
9f95a23c | 932 | test `rbd --cluster ${cluster} image-meta get ${pool}/${image} ${key}` = "${value}" |
b32b8144 FG |
933 | } |
934 | ||
3efd9988 FG |
935 | rename_image() |
936 | { | |
937 | local cluster=$1 | |
938 | local pool=$2 | |
939 | local image=$3 | |
940 | local new_name=$4 | |
941 | ||
9f95a23c | 942 | rbd --cluster=${cluster} rename ${pool}/${image} ${pool}/${new_name} |
3efd9988 FG |
943 | } |
944 | ||
7c673cae FG |
945 | remove_image() |
946 | { | |
947 | local cluster=$1 | |
948 | local pool=$2 | |
949 | local image=$3 | |
950 | ||
9f95a23c TL |
951 | rbd --cluster=${cluster} snap purge ${pool}/${image} |
952 | rbd --cluster=${cluster} rm ${pool}/${image} | |
7c673cae FG |
953 | } |
954 | ||
955 | remove_image_retry() | |
956 | { | |
957 | local cluster=$1 | |
958 | local pool=$2 | |
959 | local image=$3 | |
960 | ||
11fdf7f2 | 961 | for s in 0 1 2 4 8 16 32; do |
7c673cae | 962 | sleep ${s} |
11fdf7f2 | 963 | remove_image ${cluster} ${pool} ${image} && return 0 |
7c673cae FG |
964 | done |
965 | return 1 | |
966 | } | |
967 | ||
11fdf7f2 TL |
968 | trash_move() { |
969 | local cluster=$1 | |
970 | local pool=$2 | |
971 | local image=$3 | |
972 | ||
9f95a23c | 973 | rbd --cluster=${cluster} trash move ${pool}/${image} |
11fdf7f2 TL |
974 | } |
975 | ||
976 | trash_restore() { | |
977 | local cluster=$1 | |
978 | local pool=$2 | |
979 | local image_id=$3 | |
980 | ||
9f95a23c | 981 | rbd --cluster=${cluster} trash restore ${pool}/${image_id} |
11fdf7f2 TL |
982 | } |
983 | ||
7c673cae FG |
984 | clone_image() |
985 | { | |
986 | local cluster=$1 | |
987 | local parent_pool=$2 | |
988 | local parent_image=$3 | |
989 | local parent_snap=$4 | |
990 | local clone_pool=$5 | |
991 | local clone_image=$6 | |
992 | ||
92f5a8d4 TL |
993 | shift 6 |
994 | ||
995 | rbd --cluster ${cluster} clone \ | |
996 | ${parent_pool}/${parent_image}@${parent_snap} \ | |
9f95a23c TL |
997 | ${clone_pool}/${clone_image} --image-feature "${RBD_IMAGE_FEATURES}" $@ |
998 | } | |
999 | ||
1000 | clone_image_and_enable_mirror() | |
1001 | { | |
1002 | local cluster=$1 | |
1003 | local parent_pool=$2 | |
1004 | local parent_image=$3 | |
1005 | local parent_snap=$4 | |
1006 | local clone_pool=$5 | |
1007 | local clone_image=$6 | |
1008 | shift 6 | |
1009 | ||
1010 | local mode=${1:-${MIRROR_IMAGE_MODE}} | |
1011 | if [ -n "$1" ]; then | |
1012 | shift | |
1013 | fi | |
1014 | ||
1015 | clone_image ${cluster} ${parent_pool} ${parent_image} ${parent_snap} ${clone_pool} ${clone_image} $@ | |
1016 | enable_mirror ${cluster} ${clone_pool} ${clone_image} ${mode} | |
7c673cae FG |
1017 | } |
1018 | ||
1019 | disconnect_image() | |
1020 | { | |
1021 | local cluster=$1 | |
1022 | local pool=$2 | |
1023 | local image=$3 | |
1024 | ||
9f95a23c TL |
1025 | rbd --cluster ${cluster} journal client disconnect \ |
1026 | --image ${pool}/${image} | |
7c673cae FG |
1027 | } |
1028 | ||
1029 | create_snapshot() | |
1030 | { | |
1031 | local cluster=$1 | |
1032 | local pool=$2 | |
1033 | local image=$3 | |
1034 | local snap=$4 | |
1035 | ||
9f95a23c | 1036 | rbd --cluster ${cluster} snap create ${pool}/${image}@${snap} |
7c673cae FG |
1037 | } |
1038 | ||
1039 | remove_snapshot() | |
1040 | { | |
1041 | local cluster=$1 | |
1042 | local pool=$2 | |
1043 | local image=$3 | |
1044 | local snap=$4 | |
1045 | ||
9f95a23c | 1046 | rbd --cluster ${cluster} snap rm ${pool}/${image}@${snap} |
7c673cae FG |
1047 | } |
1048 | ||
1049 | rename_snapshot() | |
1050 | { | |
1051 | local cluster=$1 | |
1052 | local pool=$2 | |
1053 | local image=$3 | |
1054 | local snap=$4 | |
1055 | local new_snap=$5 | |
1056 | ||
9f95a23c TL |
1057 | rbd --cluster ${cluster} snap rename ${pool}/${image}@${snap} \ |
1058 | ${pool}/${image}@${new_snap} | |
7c673cae FG |
1059 | } |
1060 | ||
1061 | purge_snapshots() | |
1062 | { | |
1063 | local cluster=$1 | |
1064 | local pool=$2 | |
1065 | local image=$3 | |
1066 | ||
9f95a23c | 1067 | rbd --cluster ${cluster} snap purge ${pool}/${image} |
7c673cae FG |
1068 | } |
1069 | ||
1070 | protect_snapshot() | |
1071 | { | |
1072 | local cluster=$1 | |
1073 | local pool=$2 | |
1074 | local image=$3 | |
1075 | local snap=$4 | |
1076 | ||
9f95a23c | 1077 | rbd --cluster ${cluster} snap protect ${pool}/${image}@${snap} |
7c673cae FG |
1078 | } |
1079 | ||
1080 | unprotect_snapshot() | |
1081 | { | |
1082 | local cluster=$1 | |
1083 | local pool=$2 | |
1084 | local image=$3 | |
1085 | local snap=$4 | |
1086 | ||
9f95a23c | 1087 | rbd --cluster ${cluster} snap unprotect ${pool}/${image}@${snap} |
7c673cae FG |
1088 | } |
1089 | ||
1090 | wait_for_snap_present() | |
1091 | { | |
1092 | local cluster=$1 | |
1093 | local pool=$2 | |
1094 | local image=$3 | |
1095 | local snap_name=$4 | |
1096 | local s | |
1097 | ||
1098 | for s in 1 2 4 8 8 8 8 8 8 8 8 16 16 16 16 32 32 32 32; do | |
9f95a23c TL |
1099 | sleep ${s} |
1100 | rbd --cluster ${cluster} info ${pool}/${image}@${snap_name} || continue | |
7c673cae FG |
1101 | return 0 |
1102 | done | |
1103 | return 1 | |
1104 | } | |
1105 | ||
92f5a8d4 TL |
1106 | test_snap_moved_to_trash() |
1107 | { | |
1108 | local cluster=$1 | |
1109 | local pool=$2 | |
1110 | local image=$3 | |
1111 | local snap_name=$4 | |
1112 | ||
1113 | rbd --cluster ${cluster} snap ls ${pool}/${image} --all | | |
1114 | grep -F " trash (${snap_name})" | |
1115 | } | |
1116 | ||
1117 | wait_for_snap_moved_to_trash() | |
1118 | { | |
1119 | local s | |
1120 | ||
1121 | for s in 1 2 4 8 8 8 8 8 8 8 8 16 16 16 16 32 32 32 32; do | |
9f95a23c | 1122 | sleep ${s} |
92f5a8d4 TL |
1123 | test_snap_moved_to_trash $@ || continue |
1124 | return 0 | |
1125 | done | |
1126 | return 1 | |
1127 | } | |
1128 | ||
1129 | test_snap_removed_from_trash() | |
1130 | { | |
1131 | test_snap_moved_to_trash $@ && return 1 | |
1132 | return 0 | |
1133 | } | |
1134 | ||
1135 | wait_for_snap_removed_from_trash() | |
1136 | { | |
1137 | local s | |
1138 | ||
1139 | for s in 1 2 4 8 8 8 8 8 8 8 8 16 16 16 16 32 32 32 32; do | |
9f95a23c | 1140 | sleep ${s} |
92f5a8d4 TL |
1141 | test_snap_removed_from_trash $@ || continue |
1142 | return 0 | |
1143 | done | |
1144 | return 1 | |
1145 | } | |
1146 | ||
7c673cae FG |
1147 | write_image() |
1148 | { | |
1149 | local cluster=$1 | |
1150 | local pool=$2 | |
1151 | local image=$3 | |
1152 | local count=$4 | |
1153 | local size=$5 | |
1154 | ||
1155 | test -n "${size}" || size=4096 | |
1156 | ||
9f95a23c TL |
1157 | rbd --cluster ${cluster} bench ${pool}/${image} --io-type write \ |
1158 | --io-size ${size} --io-threads 1 --io-total $((size * count)) \ | |
1159 | --io-pattern rand | |
7c673cae FG |
1160 | } |
1161 | ||
1162 | stress_write_image() | |
1163 | { | |
1164 | local cluster=$1 | |
1165 | local pool=$2 | |
1166 | local image=$3 | |
1167 | local duration=$(awk 'BEGIN {srand(); print int(10 * rand()) + 5}') | |
1168 | ||
1169 | timeout ${duration}s ceph_test_rbd_mirror_random_write \ | |
9f95a23c TL |
1170 | --cluster ${cluster} ${pool} ${image} \ |
1171 | --debug-rbd=20 --debug-journaler=20 \ | |
1172 | 2> ${TEMPDIR}/rbd-mirror-random-write.log || true | |
1173 | } | |
1174 | ||
1175 | show_diff() | |
1176 | { | |
1177 | local file1=$1 | |
1178 | local file2=$2 | |
1179 | ||
1180 | xxd ${file1} > ${file1}.xxd | |
1181 | xxd ${file2} > ${file2}.xxd | |
1182 | sdiff -s ${file1}.xxd ${file2}.xxd | head -n 64 | |
1183 | rm -f ${file1}.xxd ${file2}.xxd | |
7c673cae FG |
1184 | } |
1185 | ||
1186 | compare_images() | |
1187 | { | |
1188 | local pool=$1 | |
1189 | local image=$2 | |
9f95a23c | 1190 | local ret=0 |
7c673cae | 1191 | |
9f95a23c TL |
1192 | local rmt_export=${TEMPDIR}/$(mkfname ${CLUSTER2}-${pool}-${image}.export) |
1193 | local loc_export=${TEMPDIR}/$(mkfname ${CLUSTER1}-${pool}-${image}.export) | |
7c673cae FG |
1194 | |
1195 | rm -f ${rmt_export} ${loc_export} | |
9f95a23c TL |
1196 | rbd --cluster ${CLUSTER2} export ${pool}/${image} ${rmt_export} |
1197 | rbd --cluster ${CLUSTER1} export ${pool}/${image} ${loc_export} | |
1198 | if ! cmp ${rmt_export} ${loc_export} | |
1199 | then | |
1200 | show_diff ${rmt_export} ${loc_export} | |
1201 | ret=1 | |
1202 | fi | |
11fdf7f2 | 1203 | rm -f ${rmt_export} ${loc_export} |
9f95a23c | 1204 | return ${ret} |
11fdf7f2 TL |
1205 | } |
1206 | ||
1207 | compare_image_snapshots() | |
1208 | { | |
1209 | local pool=$1 | |
1210 | local image=$2 | |
9f95a23c | 1211 | local ret=0 |
11fdf7f2 TL |
1212 | |
1213 | local rmt_export=${TEMPDIR}/${CLUSTER2}-${pool}-${image}.export | |
1214 | local loc_export=${TEMPDIR}/${CLUSTER1}-${pool}-${image}.export | |
1215 | ||
9f95a23c TL |
1216 | for snap_name in $(rbd --cluster ${CLUSTER1} --format xml \ |
1217 | snap list ${pool}/${image} | \ | |
11fdf7f2 TL |
1218 | $XMLSTARLET sel -t -v "//snapshot/name" | \ |
1219 | grep -E -v "^\.rbd-mirror\."); do | |
1220 | rm -f ${rmt_export} ${loc_export} | |
9f95a23c TL |
1221 | rbd --cluster ${CLUSTER2} export ${pool}/${image}@${snap_name} ${rmt_export} |
1222 | rbd --cluster ${CLUSTER1} export ${pool}/${image}@${snap_name} ${loc_export} | |
1223 | if ! cmp ${rmt_export} ${loc_export} | |
1224 | then | |
1225 | show_diff ${rmt_export} ${loc_export} | |
1226 | ret=1 | |
1227 | fi | |
11fdf7f2 | 1228 | done |
7c673cae | 1229 | rm -f ${rmt_export} ${loc_export} |
9f95a23c | 1230 | return ${ret} |
7c673cae FG |
1231 | } |
1232 | ||
1233 | demote_image() | |
1234 | { | |
1235 | local cluster=$1 | |
1236 | local pool=$2 | |
1237 | local image=$3 | |
1238 | ||
1239 | rbd --cluster=${cluster} mirror image demote ${pool}/${image} | |
1240 | } | |
1241 | ||
1242 | promote_image() | |
1243 | { | |
1244 | local cluster=$1 | |
1245 | local pool=$2 | |
1246 | local image=$3 | |
1247 | local force=$4 | |
1248 | ||
1249 | rbd --cluster=${cluster} mirror image promote ${pool}/${image} ${force} | |
1250 | } | |
1251 | ||
1252 | set_pool_mirror_mode() | |
1253 | { | |
1254 | local cluster=$1 | |
1255 | local pool=$2 | |
9f95a23c | 1256 | local mode=${3:-${MIRROR_POOL_MODE}} |
7c673cae | 1257 | |
9f95a23c | 1258 | rbd --cluster=${cluster} mirror pool enable ${pool} ${mode} |
7c673cae FG |
1259 | } |
1260 | ||
1261 | disable_mirror() | |
1262 | { | |
1263 | local cluster=$1 | |
1264 | local pool=$2 | |
1265 | local image=$3 | |
1266 | ||
1267 | rbd --cluster=${cluster} mirror image disable ${pool}/${image} | |
1268 | } | |
1269 | ||
1270 | enable_mirror() | |
1271 | { | |
1272 | local cluster=$1 | |
1273 | local pool=$2 | |
1274 | local image=$3 | |
9f95a23c | 1275 | local mode=${4:-${MIRROR_IMAGE_MODE}} |
7c673cae | 1276 | |
9f95a23c | 1277 | rbd --cluster=${cluster} mirror image enable ${pool}/${image} ${mode} |
7c673cae FG |
1278 | } |
1279 | ||
1280 | test_image_present() | |
1281 | { | |
1282 | local cluster=$1 | |
1283 | local pool=$2 | |
1284 | local image=$3 | |
1285 | local test_state=$4 | |
1286 | local image_id=$5 | |
1287 | local current_state=deleted | |
1288 | local current_image_id | |
1289 | ||
1290 | current_image_id=$(get_image_id ${cluster} ${pool} ${image}) | |
1291 | test -n "${current_image_id}" && | |
1292 | test -z "${image_id}" -o "${image_id}" = "${current_image_id}" && | |
1293 | current_state=present | |
1294 | ||
1295 | test "${test_state}" = "${current_state}" | |
1296 | } | |
1297 | ||
1298 | wait_for_image_present() | |
1299 | { | |
1300 | local cluster=$1 | |
1301 | local pool=$2 | |
1302 | local image=$3 | |
1303 | local state=$4 | |
1304 | local image_id=$5 | |
1305 | local s | |
1306 | ||
1307 | test -n "${image_id}" || | |
1308 | image_id=$(get_image_id ${cluster} ${pool} ${image}) | |
1309 | ||
1310 | # TODO: add a way to force rbd-mirror to update replayers | |
1311 | for s in 0.1 1 2 4 8 8 8 8 8 8 8 8 16 16 32 32; do | |
9f95a23c TL |
1312 | sleep ${s} |
1313 | test_image_present \ | |
7c673cae FG |
1314 | "${cluster}" "${pool}" "${image}" "${state}" "${image_id}" && |
1315 | return 0 | |
1316 | done | |
1317 | return 1 | |
1318 | } | |
1319 | ||
1320 | get_image_id() | |
1321 | { | |
1322 | local cluster=$1 | |
1323 | local pool=$2 | |
1324 | local image=$3 | |
1325 | ||
9f95a23c TL |
1326 | rbd --cluster=${cluster} info ${pool}/${image} | |
1327 | sed -ne 's/^.*block_name_prefix: rbd_data\.//p' | |
7c673cae FG |
1328 | } |
1329 | ||
1330 | request_resync_image() | |
1331 | { | |
1332 | local cluster=$1 | |
1333 | local pool=$2 | |
1334 | local image=$3 | |
b32b8144 | 1335 | local image_id_var_name=$4 |
7c673cae FG |
1336 | |
1337 | eval "${image_id_var_name}='$(get_image_id ${cluster} ${pool} ${image})'" | |
1338 | eval 'test -n "$'${image_id_var_name}'"' | |
1339 | ||
9f95a23c | 1340 | rbd --cluster=${cluster} mirror image resync ${pool}/${image} |
7c673cae FG |
1341 | } |
1342 | ||
b5b8bbf5 FG |
1343 | get_image_data_pool() |
1344 | { | |
1345 | local cluster=$1 | |
1346 | local pool=$2 | |
1347 | local image=$3 | |
1348 | ||
9f95a23c | 1349 | rbd --cluster ${cluster} info ${pool}/${image} | |
b5b8bbf5 FG |
1350 | awk '$1 == "data_pool:" {print $2}' |
1351 | } | |
1352 | ||
92f5a8d4 TL |
1353 | get_clone_format() |
1354 | { | |
1355 | local cluster=$1 | |
1356 | local pool=$2 | |
1357 | local image=$3 | |
1358 | ||
1359 | rbd --cluster ${cluster} info ${pool}/${image} | | |
1360 | awk 'BEGIN { | |
1361 | format = 1 | |
1362 | } | |
1363 | $1 == "parent:" { | |
1364 | parent = $2 | |
1365 | } | |
1366 | /op_features: .*clone-child/ { | |
1367 | format = 2 | |
1368 | } | |
1369 | END { | |
1370 | if (!parent) exit 1 | |
1371 | print format | |
1372 | }' | |
1373 | } | |
1374 | ||
7c673cae FG |
1375 | # |
1376 | # Main | |
1377 | # | |
1378 | ||
1379 | if [ "$#" -gt 0 ] | |
1380 | then | |
1381 | if [ -z "${RBD_MIRROR_TEMDIR}" ] | |
1382 | then | |
1383 | echo "RBD_MIRROR_TEMDIR is not set" >&2 | |
1384 | exit 1 | |
1385 | fi | |
1386 | ||
1387 | TEMPDIR="${RBD_MIRROR_TEMDIR}" | |
1388 | cd ${TEMPDIR} | |
1389 | $@ | |
1390 | exit $? | |
1391 | fi |