master
text 344 lines 9.8 KB
Raw
1 #!/usr/bin/env bash
2 # group: rw quick
3 #
4 # Test Quorum block driver
5 #
6 # Copyright (C) 2013 Nodalink, SARL.
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) 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 General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #
21
22 # creator
23 owner=benoit@irqsave.net
24
25 seq=`basename $0`
26 echo "QA output created by $seq"
27
28 status=1 # failure is the default!
29
30 _cleanup()
31 {
32 _rm_test_img "$TEST_DIR/1.raw"
33 _rm_test_img "$TEST_DIR/2.raw"
34 _rm_test_img "$TEST_DIR/3.raw"
35 }
36 trap "_cleanup; exit \$status" 0 1 2 3 15
37
38 # get standard environment, filters and checks
39 . ./common.rc
40 . ./common.filter
41
42 _supported_fmt raw
43 _supported_proto file
44 _supported_os Linux
45 _require_drivers quorum
46 _require_devices virtio-scsi
47 _require_hmp
48
49 do_run_qemu()
50 {
51 echo Testing: "$@"
52 $QEMU -nographic -qmp stdio -serial none "$@"
53 echo
54 }
55
56 run_qemu()
57 {
58 do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_imgfmt | _filter_qemu \
59 | _filter_qmp | _filter_qemu_io \
60 | _filter_generated_node_ids
61 }
62
63 quorum="driver=raw,file.driver=quorum,file.vote-threshold=2"
64 quorum="$quorum,file.children.0.file.filename=$TEST_DIR/1.raw"
65 quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw"
66 quorum="$quorum,file.children.2.file.filename=$TEST_DIR/3.raw"
67 quorum="$quorum,file.children.0.driver=raw"
68 quorum="$quorum,file.children.1.driver=raw"
69 quorum="$quorum,file.children.2.driver=raw"
70
71 echo
72 echo "== creating quorum files =="
73
74 size=10M
75
76 TEST_IMG="$TEST_DIR/1.raw" _make_test_img $size
77 TEST_IMG="$TEST_DIR/2.raw" _make_test_img $size
78 TEST_IMG="$TEST_DIR/3.raw" _make_test_img $size
79
80 echo
81 echo "== writing images =="
82
83 $QEMU_IO -c "open -o $quorum" -c "write -P 0x32 0 $size" | _filter_qemu_io
84
85 echo
86 echo "== checking quorum write =="
87
88 $QEMU_IO -c "read -P 0x32 0 $size" "$TEST_DIR/1.raw" | _filter_qemu_io
89 $QEMU_IO -c "read -P 0x32 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io
90 $QEMU_IO -c "read -P 0x32 0 $size" "$TEST_DIR/3.raw" | _filter_qemu_io
91
92 echo
93 echo "== corrupting image =="
94
95 $QEMU_IO -c "write -P 0x42 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io
96
97 echo
98 echo "== checking quorum correction =="
99
100 $QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
101
102 echo
103 echo "== checking mixed reference/option specification =="
104
105 run_qemu <<EOF
106 { "execute": "qmp_capabilities" }
107 { "execute": "blockdev-add",
108 "arguments": {
109 "node-name": "drive2",
110 "driver": "$IMGFMT",
111 "file": {
112 "driver": "file",
113 "filename": "$TEST_DIR/2.raw"
114 }
115 }
116 }
117 { "execute": "blockdev-add",
118 "arguments": {
119 "driver": "quorum",
120 "node-name": "drive0-quorum",
121 "vote-threshold": 2,
122 "children": [
123 {
124 "driver": "$IMGFMT",
125 "file": {
126 "driver": "file",
127 "filename": "$TEST_DIR/1.raw"
128 }
129 },
130 "drive2",
131 {
132 "driver": "$IMGFMT",
133 "file": {
134 "driver": "file",
135 "filename": "$TEST_DIR/3.raw"
136 }
137 }
138 ]
139 }
140 }
141 { "execute": "human-monitor-command",
142 "arguments": {
143 "command-line": 'qemu-io drive0-quorum "read -P 0x32 0 $size"'
144 }
145 }
146 { "execute": "quit" }
147 EOF
148
149 echo
150 echo "== using quorum rewrite corrupted mode =="
151
152 quorum="$quorum,file.rewrite-corrupted=on"
153
154 $QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
155
156 echo
157 echo "== checking that quorum has corrected the corrupted file =="
158
159 $QEMU_IO -c "read -P 0x32 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io
160
161 echo
162 echo "== using quorum rewrite corrupted mode without WRITE permission =="
163
164 # The same as above, but this time, do it on a quorum node whose only
165 # parent will not take the WRITE permission
166
167 echo '-- corrupting --'
168 # Only corrupt a portion: The guest device (scsi-hd on virtio-scsi)
169 # will read some data (looking for a partition table to guess the
170 # disk's geometry), which would trigger a quorum mismatch if the
171 # beginning of the image was corrupted. The subsequent
172 # QUORUM_REPORT_BAD event would be suppressed (because at that point,
173 # there cannot have been a qmp_capabilities on the monitor). Because
174 # that event is rate-limited, the next QUORUM_REPORT_BAD that happens
175 # thanks to our qemu-io read (which should trigger a mismatch) would
176 # then be delayed past the VM quit and not appear in the output.
177 # So we keep the first 1M intact to see a QUORUM_REPORT_BAD resulting
178 # from the qemu-io invocation.
179 $QEMU_IO -c "write -P 0x42 1M 1M" "$TEST_DIR/2.raw" | _filter_qemu_io
180
181 # Fix the corruption (on a read-only quorum node, i.e. without taking
182 # the WRITE permission on it -- its child nodes need to be R/W OTOH,
183 # so that rewrite-corrupted works)
184 echo
185 echo '-- running quorum --'
186 run_qemu \
187 -blockdev file,node-name=file1,filename="$TEST_DIR/1.raw" \
188 -blockdev file,node-name=file2,filename="$TEST_DIR/2.raw" \
189 -blockdev file,node-name=file3,filename="$TEST_DIR/3.raw" \
190 -blockdev '{
191 "driver": "quorum",
192 "node-name": "quorum",
193 "read-only": true,
194 "vote-threshold": 2,
195 "rewrite-corrupted": true,
196 "children": [ "file1", "file2", "file3" ]
197 }' \
198 -device virtio-scsi,id=scsi \
199 -device scsi-hd,id=quorum-drive,bus=scsi.0,drive=quorum \
200 <<EOF
201 { "execute": "qmp_capabilities" }
202 {
203 "execute": "human-monitor-command",
204 "arguments": {
205 "command-line": 'qemu-io -d quorum-drive "read -P 0x32 0 $size"'
206 }
207 }
208 { "execute": "quit" }
209 EOF
210
211 echo '-- checking that the image has been corrected --'
212 $QEMU_IO -c "read -P 0x32 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io
213
214 echo
215 echo "== breaking quorum =="
216
217 $QEMU_IO -c "write -P 0x41 0 $size" "$TEST_DIR/1.raw" | _filter_qemu_io
218 $QEMU_IO -c "write -P 0x42 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io
219
220 echo
221 echo "== checking that quorum is broken =="
222
223 $QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
224
225 echo
226 echo "== checking the blkverify mode with broken content =="
227
228 quorum="driver=raw,file.driver=quorum,file.vote-threshold=2,file.blkverify=on"
229 quorum="$quorum,file.children.0.file.filename=$TEST_DIR/1.raw"
230 quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw"
231 quorum="$quorum,file.children.0.driver=raw"
232 quorum="$quorum,file.children.1.driver=raw"
233
234 $QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
235
236 echo
237 echo "== writing the same data to both files =="
238
239 $QEMU_IO -c "write -P 0x32 0 $size" "$TEST_DIR/1.raw" | _filter_qemu_io
240 $QEMU_IO -c "write -P 0x32 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io
241
242 echo
243 echo "== checking the blkverify mode with valid content =="
244
245 $QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
246
247 echo
248 echo "== checking the blkverify mode with invalid settings =="
249
250 quorum="$quorum,file.children.2.file.filename=$TEST_DIR/3.raw"
251 quorum="$quorum,file.children.2.driver=raw"
252
253 $QEMU_IO -c "open -o $quorum" | _filter_qemu_io
254
255 echo
256 echo "== dynamically adding a child to a quorum =="
257
258 for verify in false true; do
259 run_qemu <<EOF
260 { "execute": "qmp_capabilities" }
261 { "execute": "blockdev-add",
262 "arguments": {
263 "driver": "quorum",
264 "node-name": "drive0-quorum",
265 "vote-threshold": 2,
266 "blkverify": ${verify},
267 "children": [
268 {
269 "driver": "$IMGFMT",
270 "file": {
271 "driver": "file",
272 "filename": "$TEST_DIR/1.raw"
273 }
274 },
275 {
276 "driver": "$IMGFMT",
277 "file": {
278 "driver": "file",
279 "filename": "$TEST_DIR/2.raw"
280 }
281 }
282 ]
283 }
284 }
285 { "execute": "blockdev-add",
286 "arguments": {
287 "node-name": "drive3",
288 "driver": "$IMGFMT",
289 "file": {
290 "driver": "file",
291 "filename": "$TEST_DIR/2.raw"
292 }
293 }
294 }
295 { "execute": "x-blockdev-change",
296 "arguments": { "parent": "drive0-quorum",
297 "node": "drive3" } }
298 { "execute": "quit" }
299 EOF
300 done
301
302 echo
303 echo "== dynamically removing a child from a quorum =="
304
305 for verify in false true; do
306 for vote_threshold in 1 2; do
307 run_qemu <<EOF
308 { "execute": "qmp_capabilities" }
309 { "execute": "blockdev-add",
310 "arguments": {
311 "driver": "quorum",
312 "node-name": "drive0-quorum",
313 "vote-threshold": ${vote_threshold},
314 "blkverify": ${verify},
315 "children": [
316 {
317 "driver": "$IMGFMT",
318 "file": {
319 "driver": "file",
320 "filename": "$TEST_DIR/1.raw"
321 }
322 },
323 {
324 "driver": "$IMGFMT",
325 "file": {
326 "driver": "file",
327 "filename": "$TEST_DIR/2.raw"
328 }
329 }
330 ]
331 }
332 }
333 { "execute": "x-blockdev-change",
334 "arguments": { "parent": "drive0-quorum",
335 "child": "children.1" } }
336 { "execute": "quit" }
337 EOF
338 done
339 done
340
341 # success, all done
342 echo "*** done"
343 rm -f $seq.full
344 status=0