3 # Copyright (C) 2019 Red Hat <contact@redhat.com>
5 # Author: David Zafman <dzafman@redhat.com>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU Library Public License as published by
9 # the Free Software Foundation; either version 2, or (at your option)
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Library Public License for more details.
18 source $CEPH_ROOT/qa
/standalone
/ceph-helpers.sh
25 export CEPH_MON
="127.0.0.1:7114" # git grep '\<7114\>' : there must be only one
27 CEPH_ARGS
+="--fsid=$(uuidgen) --auth-supported=none "
28 CEPH_ARGS
+="--mon-host=$CEPH_MON --osd_max_backfills=1 --debug_reserver=20"
30 export poolprefix
=test
31 export FORCE_PRIO
="255" # See OSD_RECOVERY_PRIORITY_FORCED
32 export NORMAL_PRIO
="180" # See OSD_RECOVERY_PRIORITY_BASE
34 local funcs
=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')}
35 for func
in $funcs ; do
36 setup
$dir ||
return 1
37 $func $dir ||
return 1
38 teardown
$dir ||
return 1
43 function TEST_recovery_priority
() {
48 run_mon
$dir a ||
return 1
49 run_mgr
$dir x ||
return 1
52 for osd
in $
(seq 0 $
(expr $OSDS - 1))
54 run_osd
$dir $osd ||
return 1
57 for p
in $
(seq 1 $pools)
59 create_pool
"${poolprefix}$p" 1 1
60 ceph osd pool
set "${poolprefix}$p" size
2
64 wait_for_clean ||
return 1
68 # Find 3 pools with a pg with the same primaries but second
69 # replica on another osd.
85 for p
in $
(seq 1 $pools)
87 ceph pg map
${p}.0 --format=json | jq
'.acting[]' > $dir/acting
88 local test_osd1
=$
(head -1 $dir/acting
)
89 local test_osd2
=$
(tail -1 $dir/acting
)
94 pool1
="${poolprefix}$p"
97 elif [ -z "$PG2" -a $chk_osd1_1 = $test_osd1 -a $chk_osd1_2 != $test_osd2 ];
101 pool2
="${poolprefix}$p"
103 elif [ -n "$PG2" -a $chk_osd1_1 = $test_osd1 -a $chk_osd1_2 != $test_osd2 -a "$chk_osd2" != $test_osd2 ];
107 pool3
="${poolprefix}$p"
113 if [ "$pool2" = "" -o "pool3" = "" ];
115 echo "Failure to find appropirate PGs"
119 for p
in $
(seq 1 $pools)
121 if [ $p != $POOLNUM1 -a $p != $POOLNUM2 -a $p != $POOLNUM3 ];
123 delete_pool
${poolprefix}$p
127 ceph osd pool
set $pool2 size
1
128 ceph osd pool
set $pool3 size
1
129 wait_for_clean ||
return 1
131 dd if=/dev
/urandom of
=$dir/data bs
=1M count
=10
133 for pname
in $pool1 $pool2 $pool3
135 for i
in $
(seq 1 $objects)
137 rados
-p ${pname} put obj${i}-p${p} $dir/data
142 local otherosd
=$
(get_not_primary
$pool1 obj1-p1
)
147 ceph osd
set norecover
150 # Get a pg to want to recover and quickly force it
152 ceph osd pool
set $pool3 size
2
154 CEPH_ARGS
='' ceph
--admin-daemon $
(get_asok_path osd.
${chk_osd1_1}) dump_reservations ||
return 1
156 # 3. Item is in progress, adjust priority with no higher priority waiting
157 while(ceph pg force-recovery
$PG3 2>&1 |
grep -q "doesn't require recovery")
161 flush_pg_stats ||
return 1
162 CEPH_ARGS
='' ceph
--admin-daemon $
(get_asok_path osd.
${chk_osd1_1}) dump_reservations ||
return 1
164 ceph osd out osd.
$chk_osd1_2
166 flush_pg_stats ||
return 1
167 CEPH_ARGS
='' ceph
--admin-daemon $
(get_asok_path osd.
${chk_osd1_1}) dump_reservations ||
return 1
170 ceph osd pool
set $pool2 size
2
172 flush_pg_stats ||
return 1
173 CEPH_ARGS
='' ceph
--admin-daemon $
(get_asok_path osd.
${chk_osd1_1}) dump_reservations
> $dir/out ||
return 1
177 PRIO
=$
(cat $dir/out | jq
"(.local_reservations.queues[].items[] | select(.item == \"${PG1}\")).prio")
178 if [ "$PRIO" != "$NORMAL_PRIO" ];
180 echo "The normal PG ${PG1} doesn't have prio $NORMAL_PRIO queued waiting"
181 ERRORS
=$
(expr $ERRORS + 1)
184 # Using eval will strip double-quotes from item
185 eval ITEM
=$
(cat $dir/out | jq
'.local_reservations.in_progress[0].item')
186 if [ "$ITEM" != ${PG3} ];
188 echo "The first force-recovery PG $PG3 didn't become the in progress item"
189 ERRORS
=$
(expr $ERRORS + 1)
191 PRIO
=$
(cat $dir/out | jq
'.local_reservations.in_progress[0].prio')
192 if [ "$PRIO" != $FORCE_PRIO ];
194 echo "The first force-recovery PG ${PG3} doesn't have prio $FORCE_PRIO"
195 ERRORS
=$
(expr $ERRORS + 1)
199 # 1. Item is queued, re-queue with new priority
200 while(ceph pg force-recovery
$PG2 2>&1 |
grep -q "doesn't require recovery")
205 CEPH_ARGS
='' ceph
--admin-daemon $
(get_asok_path osd.
${chk_osd1_1}) dump_reservations
> $dir/out ||
return 1
207 PRIO
=$
(cat $dir/out | jq
"(.local_reservations.queues[].items[] | select(.item == \"${PG2}\")).prio")
208 if [ "$PRIO" != "$FORCE_PRIO" ];
210 echo "The second force-recovery PG ${PG2} doesn't have prio $FORCE_PRIO"
211 ERRORS
=$
(expr $ERRORS + 1)
213 flush_pg_stats ||
return 1
215 # 4. Item is in progress, if higher priority items waiting prempt item
216 #ceph osd unset norecover
217 ceph pg cancel-force-recovery
$PG3 ||
return 1
219 #ceph osd set norecover
220 CEPH_ARGS
='' ceph
--admin-daemon $
(get_asok_path osd.
${chk_osd1_1}) dump_reservations
> $dir/out ||
return 1
222 PRIO
=$
(cat $dir/out | jq
"(.local_reservations.queues[].items[] | select(.item == \"${PG3}\")).prio")
223 if [ "$PRIO" != "$NORMAL_PRIO" ];
225 echo "After cancel-recovery PG ${PG3} doesn't have prio $NORMAL_PRIO"
226 ERRORS
=$
(expr $ERRORS + 1)
229 eval ITEM
=$
(cat $dir/out | jq
'.local_reservations.in_progress[0].item')
230 if [ "$ITEM" != ${PG2} ];
232 echo "The force-recovery PG $PG2 didn't become the in progress item"
233 ERRORS
=$
(expr $ERRORS + 1)
235 PRIO
=$
(cat $dir/out | jq
'.local_reservations.in_progress[0].prio')
236 if [ "$PRIO" != $FORCE_PRIO ];
238 echo "The first force-recovery PG ${PG2} doesn't have prio $FORCE_PRIO"
239 ERRORS
=$
(expr $ERRORS + 1)
243 ceph pg cancel-force-recovery
$PG2 ||
return 1
245 CEPH_ARGS
='' ceph
--admin-daemon $
(get_asok_path osd.
${chk_osd1_1}) dump_reservations ||
return 1
247 # 2. Item is queued, re-queue and preempt because new priority higher than an in progress item
248 flush_pg_stats ||
return 1
249 ceph pg force-recovery
$PG3 ||
return 1
252 CEPH_ARGS
='' ceph
--admin-daemon $
(get_asok_path osd.
${chk_osd1_1}) dump_reservations
> $dir/out ||
return 1
254 PRIO
=$
(cat $dir/out | jq
"(.local_reservations.queues[].items[] | select(.item == \"${PG2}\")).prio")
255 if [ "$PRIO" != "$NORMAL_PRIO" ];
257 echo "After cancel-force-recovery PG ${PG3} doesn't have prio $NORMAL_PRIO"
258 ERRORS
=$
(expr $ERRORS + 1)
261 eval ITEM
=$
(cat $dir/out | jq
'.local_reservations.in_progress[0].item')
262 if [ "$ITEM" != ${PG3} ];
264 echo "The force-recovery PG $PG3 didn't get promoted to an in progress item"
265 ERRORS
=$
(expr $ERRORS + 1)
267 PRIO
=$
(cat $dir/out | jq
'.local_reservations.in_progress[0].prio')
268 if [ "$PRIO" != $FORCE_PRIO ];
270 echo "The force-recovery PG ${PG2} doesn't have prio $FORCE_PRIO"
271 ERRORS
=$
(expr $ERRORS + 1)
276 ceph osd
unset norecover
278 wait_for_clean
"CEPH_ARGS='' ceph --admin-daemon $(get_asok_path osd.${chk_osd1_1}) dump_reservations" ||
return 1
282 CEPH_ARGS
='' ceph
--admin-daemon $
(get_asok_path osd.
${chk_osd1_1}) dump_pgstate_history
284 if [ $ERRORS != "0" ];
286 echo "$ERRORS error(s) found"
294 kill_daemons
$dir ||
return 1
299 # Show that pool recovery_priority is added to recovery priority
301 # Create 2 pools with 2 OSDs with different primarys
302 # pool 1 with recovery_priority 1
303 # pool 2 with recovery_priority 2
305 # Start recovery by changing the pool sizes from 1 to 2
306 # Use dump_reservations to verify priorities
307 function TEST_recovery_pool_priority
() {
309 local pools
=3 # Don't assume the first 2 pools are exact what we want
312 run_mon
$dir a ||
return 1
313 run_mgr
$dir x ||
return 1
316 for osd
in $
(seq 0 $
(expr $OSDS - 1))
318 run_osd
$dir $osd ||
return 1
321 for p
in $
(seq 1 $pools)
323 create_pool
"${poolprefix}$p" 1 1
324 ceph osd pool
set "${poolprefix}$p" size
2
328 wait_for_clean ||
return 1
332 # Find 2 pools with different primaries which
333 # means the replica must be on another osd.
346 for p
in $
(seq 1 $pools)
348 ceph pg map
${p}.0 --format=json | jq
'.acting[]' > $dir/acting
349 local test_osd1
=$
(head -1 $dir/acting
)
350 local test_osd2
=$
(tail -1 $dir/acting
)
355 pool1
="${poolprefix}$p"
356 chk_osd1_1
=$test_osd1
357 chk_osd1_2
=$test_osd2
358 elif [ $chk_osd1_1 != $test_osd1 ];
362 pool2
="${poolprefix}$p"
363 chk_osd2_1
=$test_osd1
364 chk_osd2_2
=$test_osd2
370 if [ "$pool2" = "" ];
372 echo "Failure to find appropirate PGs"
376 for p
in $
(seq 1 $pools)
378 if [ $p != $POOLNUM1 -a $p != $POOLNUM2 ];
380 delete_pool
${poolprefix}$p
386 pool1_prio
=$
(expr $NORMAL_PRIO + $pool1_extra_prio)
387 pool2_prio
=$
(expr $NORMAL_PRIO + $pool2_extra_prio)
389 ceph osd pool
set $pool1 size
1
390 ceph osd pool
set $pool1 recovery_priority
$pool1_extra_prio
391 ceph osd pool
set $pool2 size
1
392 ceph osd pool
set $pool2 recovery_priority
$pool2_extra_prio
393 wait_for_clean ||
return 1
395 dd if=/dev
/urandom of
=$dir/data bs
=1M count
=10
397 for pname
in $pool1 $pool2
399 for i
in $
(seq 1 $objects)
401 rados
-p ${pname} put obj${i}-p${p} $dir/data
406 local otherosd
=$
(get_not_primary
$pool1 obj1-p1
)
411 ceph osd pool
set $pool1 size
2
412 ceph osd pool
set $pool2 size
2
414 CEPH_ARGS
='' ceph
--admin-daemon $
(get_asok_path osd.
${chk_osd1_1}) dump_reservations
> $dir/dump.
${chk_osd1_1}.out
415 echo osd.
${chk_osd1_1}
416 cat $dir/dump.
${chk_osd1_1}.out
417 CEPH_ARGS
='' ceph
--admin-daemon $
(get_asok_path osd.
${chk_osd1_2}) dump_reservations
> $dir/dump.
${chk_osd1_2}.out
418 echo osd.
${chk_osd1_2}
419 cat $dir/dump.
${chk_osd1_2}.out
421 # Using eval will strip double-quotes from item
422 eval ITEM
=$
(cat $dir/dump.
${chk_osd1_1}.out | jq
'.local_reservations.in_progress[0].item')
423 if [ "$ITEM" != ${PG1} ];
425 echo "The primary PG for $pool1 didn't become the in progress item"
426 ERRORS
=$
(expr $ERRORS + 1)
428 PRIO
=$
(cat $dir/dump.
${chk_osd1_1}.out | jq
'.local_reservations.in_progress[0].prio')
429 if [ "$PRIO" != $pool1_prio ];
431 echo "The primary PG ${PG1} doesn't have prio $pool1_prio"
432 ERRORS
=$
(expr $ERRORS + 1)
436 # Using eval will strip double-quotes from item
437 eval ITEM
=$
(cat $dir/dump.
${chk_osd1_2}.out | jq
'.remote_reservations.in_progress[0].item')
438 if [ "$ITEM" != ${PG1} ];
440 echo "The primary PG for $pool1 didn't become the in progress item on remote"
441 ERRORS
=$
(expr $ERRORS + 1)
443 PRIO
=$
(cat $dir/dump.
${chk_osd1_2}.out | jq
'.remote_reservations.in_progress[0].prio')
444 if [ "$PRIO" != $pool1_prio ];
446 echo "The primary PG ${PG1} doesn't have prio $pool1_prio on remote"
447 ERRORS
=$
(expr $ERRORS + 1)
451 # Using eval will strip double-quotes from item
452 eval ITEM
=$
(cat $dir/dump.
${chk_osd2_1}.out | jq
'.local_reservations.in_progress[0].item')
453 if [ "$ITEM" != ${PG2} ];
455 echo "The primary PG for $pool2 didn't become the in progress item"
456 ERRORS
=$
(expr $ERRORS + 1)
458 PRIO
=$
(cat $dir/dump.
${chk_osd2_1}.out | jq
'.local_reservations.in_progress[0].prio')
459 if [ "$PRIO" != $pool2_prio ];
461 echo "The primary PG ${PG2} doesn't have prio $pool2_prio"
462 ERRORS
=$
(expr $ERRORS + 1)
466 # Using eval will strip double-quotes from item
467 eval ITEM
=$
(cat $dir/dump.
${chk_osd2_2}.out | jq
'.remote_reservations.in_progress[0].item')
468 if [ "$ITEM" != ${PG2} ];
470 echo "The primary PG $PG2 didn't become the in progress item on remote"
471 ERRORS
=$
(expr $ERRORS + 1)
473 PRIO
=$
(cat $dir/dump.
${chk_osd2_2}.out | jq
'.remote_reservations.in_progress[0].prio')
474 if [ "$PRIO" != $pool2_prio ];
476 echo "The primary PG ${PG2} doesn't have prio $pool2_prio on remote"
477 ERRORS
=$
(expr $ERRORS + 1)
481 wait_for_clean ||
return 1
483 if [ $ERRORS != "0" ];
485 echo "$ERRORS error(s) found"
492 kill_daemons
$dir ||
return 1
496 main osd-recovery-prio
"$@"
499 # compile-command: "make -j4 && ../qa/run-standalone.sh osd-recovery-prio.sh"