Merge pull request #18598 from dillaman/wip-21958
[ceph.git] / src / test / ceph-disk.sh
1 #!/bin/bash
2 #
3 # Copyright (C) 2014 Cloudwatt <libre.licensing@cloudwatt.com>
4 # Copyright (C) 2014 Red Hat <contact@redhat.com>
5 #
6 # Author: Loic Dachary <loic@dachary.org>
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU Library Public License as published by
10 # the Free Software Foundation; either version 2, or (at your option)
11 # any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU Library Public License for more details.
17 #
18 set -xe
19
20 source test/test_btrfs_common.sh
21
22 PS4='${FUNCNAME[0]}: $LINENO: '
23
24 export PATH=:$PATH # make sure program from sources are prefered
25 DIR=test-ceph-disk
26 OSD_DATA=$DIR/osd
27 MON_ID=a
28 MONA=127.0.0.1:7451
29 TEST_POOL=rbd
30 FSID=$(uuidgen)
31 export CEPH_CONF=$DIR/ceph.conf
32 export CEPH_ARGS="--fsid $FSID"
33 CEPH_ARGS+=" --chdir="
34 CEPH_ARGS+=" --run-dir=$DIR"
35 CEPH_ARGS+=" --osd-failsafe-full-ratio=.99"
36 CEPH_ARGS+=" --mon-host=$MONA"
37 CEPH_ARGS+=" --log-file=$DIR/\$name.log"
38 CEPH_ARGS+=" --pid-file=$DIR/\$name.pidfile"
39 CEPH_ARGS+=" --osd-pool-default-erasure-code-directory=.libs"
40 CEPH_ARGS+=" --auth-supported=none"
41 CEPH_ARGS+=" --osd-journal-size=100"
42 CEPH_DISK_ARGS=
43 CEPH_DISK_ARGS+=" --statedir=$DIR"
44 CEPH_DISK_ARGS+=" --sysconfdir=$DIR"
45 CEPH_DISK_ARGS+=" --prepend-to-path="
46 CEPH_DISK_ARGS+=" --verbose"
47 TIMEOUT=360
48
49 cat=$(which cat)
50 timeout=$(which timeout)
51 diff=$(which diff)
52 mkdir=$(which mkdir)
53 rm=$(which rm)
54
55 function setup() {
56     teardown
57     mkdir $DIR
58     mkdir $OSD_DATA
59 #    mkdir $OSD_DATA/ceph-0
60     touch $DIR/ceph.conf # so ceph-disk think ceph is the cluster
61 }
62
63 function teardown() {
64     kill_daemons
65     if [ $(stat -f -c '%T' .) == "btrfs" ]; then
66         rm -fr $DIR/*/*db
67         teardown_btrfs $DIR
68     fi
69     rm -fr $DIR
70 }
71
72 function run_mon() {
73     local mon_dir=$DIR/$MON_ID
74
75     ./ceph-mon \
76         --id $MON_ID \
77         --mkfs \
78         --mon-data=$mon_dir \
79         --mon-initial-members=$MON_ID \
80         "$@"
81
82     ./ceph-mon \
83         --id $MON_ID \
84         --mon-data=$mon_dir \
85         --mon-osd-full-ratio=.99 \
86         --mon-data-avail-crit=1 \
87         --mon-cluster-log-file=$mon_dir/log \
88         --public-addr $MONA \
89         "$@"
90 }
91
92 function kill_daemons() {
93     for pidfile in $(find $DIR | grep pidfile) ; do
94         pid=$(cat $pidfile)
95         for try in 0 1 1 1 2 3 ; do
96             kill $pid || break
97             sleep $try
98         done
99     done
100 }
101
102 function command_fixture() {
103     local command=$1
104
105     [ $(which $command) = ./$command ] || [ $(which $command) = `readlink -f $(pwd)/$command` ] || return 1
106
107     cat > $DIR/$command <<EOF
108 #!/bin/bash
109 touch $DIR/used-$command
110 exec ./$command "\$@"
111 EOF
112     chmod +x $DIR/$command
113 }
114
115 function tweak_path() {
116     local tweaker=$1
117
118     setup
119
120     command_fixture ceph-conf || return 1
121     command_fixture ceph-osd || return 1
122
123     test_activate_dir
124
125     [ ! -f $DIR/used-ceph-conf ] || return 1
126     [ ! -f $DIR/used-ceph-osd ] || return 1
127
128     teardown
129
130     setup
131
132     command_fixture ceph-conf || return 1
133     command_fixture ceph-osd || return 1
134
135     $tweaker test_activate_dir || return 1
136
137     [ -f $DIR/used-ceph-conf ] || return 1
138     [ -f $DIR/used-ceph-osd ] || return 1
139
140     teardown
141 }
142
143 function use_prepend_to_path() {
144     local ceph_disk_args
145     ceph_disk_args+=" --statedir=$DIR"
146     ceph_disk_args+=" --sysconfdir=$DIR"
147     ceph_disk_args+=" --prepend-to-path=$DIR"
148     ceph_disk_args+=" --verbose"
149     CEPH_DISK_ARGS="$ceph_disk_args" \
150         "$@" || return 1
151 }
152
153 function test_prepend_to_path() {
154     tweak_path use_prepend_to_path || return 1
155 }
156
157 function use_path() {
158     PATH="$DIR:$PATH" \
159         "$@" || return 1
160 }
161
162 function test_path() {
163     tweak_path use_path || return 1
164 }
165
166 function test_no_path() {
167     ( unset PATH ; test_activate_dir ) || return 1
168 }
169
170 function test_zap() {
171     local osd_data=$DIR/dir
172     $mkdir -p $osd_data
173
174     ./ceph-disk $CEPH_DISK_ARGS zap $osd_data 2>&1 | grep 'not full block device' || return 1
175
176     $rm -fr $osd_data
177 }
178
179 # ceph-disk prepare returns immediately on success if the magic file
180 # exists in the --osd-data directory.
181 function test_activate_dir_magic() {
182     local uuid=$(uuidgen)
183     local osd_data=$DIR/osd
184
185     echo a failure to create the fsid file implies the magic file is not created
186
187     mkdir -p $osd_data/fsid
188     CEPH_ARGS="--fsid $uuid" \
189      ./ceph-disk $CEPH_DISK_ARGS prepare $osd_data > $DIR/out 2>&1
190     grep --quiet 'Is a directory' $DIR/out || return 1
191     ! [ -f $osd_data/magic ] || return 1
192     rmdir $osd_data/fsid
193
194     echo successfully prepare the OSD
195
196     CEPH_ARGS="--fsid $uuid" \
197      ./ceph-disk $CEPH_DISK_ARGS prepare $osd_data 2>&1 | tee $DIR/out
198     grep --quiet 'Preparing osd data dir' $DIR/out || return 1
199     grep --quiet $uuid $osd_data/ceph_fsid || return 1
200     [ -f $osd_data/magic ] || return 1
201
202     echo will not override an existing OSD
203
204     CEPH_ARGS="--fsid $(uuidgen)" \
205      ./ceph-disk $CEPH_DISK_ARGS prepare $osd_data 2>&1 | tee $DIR/out
206     grep --quiet 'ceph-disk:Data dir .* already exists' $DIR/out || return 1
207     grep --quiet $uuid $osd_data/ceph_fsid || return 1
208 }
209
210 function test_activate() {
211     local to_prepare=$1
212     local to_activate=$2
213     local journal=$3
214
215     $mkdir -p $OSD_DATA
216
217     ./ceph-disk $CEPH_DISK_ARGS \
218         prepare $to_prepare $journal || return 1
219
220     $timeout $TIMEOUT ./ceph-disk $CEPH_DISK_ARGS \
221         activate \
222         --mark-init=none \
223         $to_activate || return 1
224     $timeout $TIMEOUT ./ceph osd pool set $TEST_POOL size 1 || return 1
225
226     local id=$($cat $OSD_DATA/ceph-?/whoami || $cat $to_activate/whoami)
227     local weight=1
228     ./ceph osd crush add osd.$id $weight root=default host=localhost || return 1
229     echo FOO > $DIR/BAR
230     $timeout $TIMEOUT ./rados --pool $TEST_POOL put BAR $DIR/BAR || return 1
231     $timeout $TIMEOUT ./rados --pool $TEST_POOL get BAR $DIR/BAR.copy || return 1
232     $diff $DIR/BAR $DIR/BAR.copy || return 1
233 }
234
235 function test_activate_dmcrypt() {
236     local to_prepare=$1
237     local to_activate=$2
238     local journal=$3
239     local journal_p=$4
240     local uuid=$5
241     local juuid=$6
242
243     $mkdir -p $OSD_DATA
244
245     ./ceph-disk $CEPH_DISK_ARGS \
246                 prepare --dmcrypt --dmcrypt-key-dir $DIR/keys --osd-uuid=$uuid --journal-uuid=$juuid $to_prepare $journal || return 1
247
248     /sbin/cryptsetup --key-file $DIR/keys/$uuid.luks.key luksOpen $to_activate $uuid
249     /sbin/cryptsetup --key-file $DIR/keys/$juuid.luks.key luksOpen ${journal}${journal_p} $juuid
250     
251     $timeout $TIMEOUT ./ceph-disk $CEPH_DISK_ARGS \
252         activate \
253         --mark-init=none \
254         /dev/mapper/$uuid || return 1
255     $timeout $TIMEOUT ./ceph osd pool set $TEST_POOL size 1 || return 1
256
257     local id=$($cat $OSD_DATA/ceph-?/whoami || $cat $to_activate/whoami)
258     local weight=1
259     ./ceph osd crush add osd.$id $weight root=default host=localhost || return 1
260     echo FOO > $DIR/BAR
261     $timeout $TIMEOUT ./rados --pool $TEST_POOL put BAR $DIR/BAR || return 1
262     $timeout $TIMEOUT ./rados --pool $TEST_POOL get BAR $DIR/BAR.copy || return 1
263     $diff $DIR/BAR $DIR/BAR.copy || return 1
264 }
265
266 function test_activate_dmcrypt_plain() {
267     local to_prepare=$1
268     local to_activate=$2
269     local journal=$3
270     local journal_p=$4
271     local uuid=$5
272     local juuid=$6
273
274     $mkdir -p $OSD_DATA
275
276     echo "osd_dmcrypt_type=plain" > $DIR/ceph.conf
277     
278     ./ceph-disk $CEPH_DISK_ARGS \
279                 prepare --dmcrypt --dmcrypt-key-dir $DIR/keys --osd-uuid=$uuid --journal-uuid=$juuid $to_prepare $journal || return 1
280
281     /sbin/cryptsetup --key-file $DIR/keys/$uuid --key-size 256 create $uuid $to_activate
282     /sbin/cryptsetup --key-file $DIR/keys/$juuid --key-size 256 create $juuid $journal
283     
284     $timeout $TIMEOUT ./ceph-disk $CEPH_DISK_ARGS \
285         activate \
286         --mark-init=none \
287         /dev/mapper/$uuid || return 1
288     $timeout $TIMEOUT ./ceph osd pool set $TEST_POOL size 1 || return 1
289
290     local id=$($cat $OSD_DATA/ceph-?/whoami || $cat $to_activate/whoami)
291     local weight=1
292     ./ceph osd crush add osd.$id $weight root=default host=localhost || return 1
293     echo FOO > $DIR/BAR
294     $timeout $TIMEOUT ./rados --pool $TEST_POOL put BAR $DIR/BAR || return 1
295     $timeout $TIMEOUT ./rados --pool $TEST_POOL get BAR $DIR/BAR.copy || return 1
296     $diff $DIR/BAR $DIR/BAR.copy || return 1
297 }
298
299 function test_activate_dir() {
300     run_mon
301
302     local osd_data=$DIR/dir
303     $mkdir -p $osd_data
304     test_activate $osd_data $osd_data || return 1
305     $rm -fr $osd_data
306 }
307
308 function create_dev() {
309     local name=$1
310
311     dd if=/dev/zero of=$name bs=1024k count=200
312     losetup --find $name
313     local dev=$(losetup --associated $name | cut -f1 -d:)
314     ceph-disk zap $dev > /dev/null 2>&1
315     echo $dev
316 }
317
318 function destroy_dev() {
319     local name=$1
320     local dev=$2
321
322     for partition in 1 2 3 4 ; do
323         umount ${dev}p${partition} || true
324     done
325     losetup --detach $dev
326     rm $name
327 }
328
329 function activate_dev_body() {
330     local disk=$1
331     local journal=$2
332     local newdisk=$3
333
334     setup
335     run_mon
336     test_activate $disk ${disk}p1 $journal || return 1
337     kill_daemons
338     umount ${disk}p1 || return 1
339     teardown
340
341     # reuse the journal partition
342     setup
343     run_mon
344     test_activate $newdisk ${newdisk}p1 ${journal}p1 || return 1
345     kill_daemons
346     umount ${newdisk}p1 || return 1
347     teardown
348 }
349
350 function test_activate_dev() {
351     if test $(id -u) != 0 ; then
352         echo "SKIP because not root"
353         return 0
354     fi
355
356     local disk=$(create_dev vdf.disk)
357     local journal=$(create_dev vdg.disk)
358     local newdisk=$(create_dev vdh.disk)
359
360     activate_dev_body $disk $journal $newdisk
361     status=$?
362
363     destroy_dev vdf.disk $disk
364     destroy_dev vdg.disk $journal
365     destroy_dev vdh.disk $newdisk
366
367     return $status
368 }
369
370 function destroy_dmcrypt_dev() {
371     local name=$1
372     local dev=$2
373     local uuid=$3
374
375     for partition in 1 2 3 4 ; do
376         umount /dev/mapper/$uuid || true
377         /sbin/cryptsetup remove /dev/mapper/$uuid || true
378         dmsetup remove /dev/mapper/$uuid || true
379     done
380     losetup --detach $dev
381     rm $name
382 }
383
384 function activate_dmcrypt_dev_body() {
385     local disk=$1
386     local journal=$2
387     local newdisk=$3
388     local uuid=$(uuidgen)
389     local juuid=$(uuidgen)
390
391     setup
392     run_mon
393     test_activate_dmcrypt $disk ${disk}p1 $journal p1 $uuid $juuid|| return 1
394     kill_daemons
395     umount /dev/mapper/$uuid || return 1
396     teardown
397 }
398
399 function test_activate_dmcrypt_dev() {
400     if test $(id -u) != 0 ; then
401         echo "SKIP because not root"
402         return 0
403     fi
404
405     local disk=$(create_dev vdf.disk)
406     local journal=$(create_dev vdg.disk)
407     local newdisk=$(create_dev vdh.disk)
408
409     activate_dmcrypt_dev_body $disk $journal $newdisk
410     status=$?
411
412     destroy_dmcrypt_dev vdf.disk $disk
413     destroy_dmcrypt_dev vdg.disk $journal
414     destroy_dmcrypt_dev vdh.disk $newdisk
415
416     return $status
417 }
418
419 function activate_dmcrypt_plain_dev_body() {
420     local disk=$1
421     local journal=$2
422     local newdisk=$3
423     local uuid=$(uuidgen)
424     local juuid=$(uuidgen)
425
426     setup
427     run_mon
428     test_activate_dmcrypt_plain $disk ${disk}p1 $journal p1 $uuid $juuid|| return 1
429     kill_daemons
430     umount /dev/mapper/$uuid || return 1
431     teardown
432 }
433
434 function test_activate_dmcrypt_plain_dev() {
435     if test $(id -u) != 0 ; then
436         echo "SKIP because not root"
437         return 0
438     fi
439
440     local disk=$(create_dev vdf.disk)
441     local journal=$(create_dev vdg.disk)
442     local newdisk=$(create_dev vdh.disk)
443
444     activate_dmcrypt_plain_dev_body $disk $journal $newdisk
445     status=$?
446
447     destroy_dmcrypt_dev vdf.disk $disk
448     destroy_dmcrypt_dev vdg.disk $journal
449     destroy_dmcrypt_dev vdh.disk $newdisk
450
451     return $status
452 }
453
454 function test_find_cluster_by_uuid() {
455     setup
456     test_activate_dir 2>&1 | tee $DIR/test_find
457     ! grep "No cluster conf found in $DIR" $DIR/test_find || return 1
458     teardown
459
460     setup
461     rm $DIR/ceph.conf
462     test_activate_dir > $DIR/test_find 2>&1 
463     grep --quiet "No cluster conf found in $DIR" $DIR/test_find || return 1
464     teardown
465 }
466
467 # http://tracker.ceph.com/issues/9653
468 function test_keyring_path() {
469     test_activate_dir 2>&1 | tee $DIR/test_keyring
470     grep --quiet "keyring $DIR/bootstrap-osd/ceph.keyring" $DIR/test_keyring || return 1
471 }
472
473 function run() {
474     local default_actions
475     default_actions+="test_path "
476     default_actions+="test_no_path "
477     default_actions+="test_find_cluster_by_uuid "
478     default_actions+="test_prepend_to_path "
479     default_actions+="test_activate_dir_magic "
480     default_actions+="test_activate_dir "
481     default_actions+="test_keyring_path "
482     default_actions+="test_zap "
483     local actions=${@:-$default_actions}
484     for action in $actions  ; do
485         setup
486         $action || return 1
487         teardown
488     done
489 }
490
491 run $@
492
493 # Local Variables:
494 # compile-command: "cd .. ; test/ceph-disk.sh # test_activate_dir"
495 # End: