diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/docker/Makefile.include | 2 | ||||
| -rwxr-xr-x | tests/docker/docker.py | 13 | ||||
| -rwxr-xr-x | tests/docker/dockerfiles/debian-bootstrap.pre | 7 | ||||
| -rwxr-xr-x | tests/qemu-iotests/028 | 19 | ||||
| -rw-r--r-- | tests/qemu-iotests/028.out | 11 | ||||
| -rwxr-xr-x | tests/qemu-iotests/197 | 10 | ||||
| -rw-r--r-- | tests/qemu-iotests/197.out | 2 | ||||
| -rwxr-xr-x | tests/qemu-iotests/199 | 250 | ||||
| -rw-r--r-- | tests/qemu-iotests/199.out | 4 | ||||
| -rwxr-xr-x | tests/qemu-iotests/check | 14 | ||||
| -rw-r--r-- | tests/qemu-iotests/group | 12 | ||||
| -rw-r--r-- | tests/vm/basevm.py | 15 |
12 files changed, 276 insertions, 83 deletions
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index a104e9df28..9119dff97d 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -78,7 +78,7 @@ docker-binfmt-image-debian-%: $(DOCKER_FILES_DIR)/debian-bootstrap.docker DEB_ARCH=$(DEB_ARCH) \ DEB_TYPE=$(DEB_TYPE) \ $(if $(DEB_URL),DEB_URL=$(DEB_URL),) \ - $(DOCKER_SCRIPT) build qemu/debian-$* $< \ + $(DOCKER_SCRIPT) build -t qemu/debian-$* -f $< \ $(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \ $(if $(NOUSER),,--add-current-user) \ $(if $(EXTRA_FILES),--extra-files $(EXTRA_FILES)) \ diff --git a/tests/docker/docker.py b/tests/docker/docker.py index c9f20d8d09..356d7618f1 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -24,7 +24,7 @@ import tempfile import re import signal from tarfile import TarFile, TarInfo -from io import StringIO +from io import StringIO, BytesIO from shutil import copy, rmtree from pwd import getpwuid from datetime import datetime, timedelta @@ -541,13 +541,14 @@ class UpdateCommand(SubCommand): # Create a Docker buildfile df = StringIO() - df.write("FROM %s\n" % args.tag) - df.write("ADD . /\n") - df.seek(0) + df.write(u"FROM %s\n" % args.tag) + df.write(u"ADD . /\n") + + df_bytes = BytesIO(bytes(df.getvalue(), "UTF-8")) df_tar = TarInfo(name="Dockerfile") - df_tar.size = len(df.buf) - tmp_tar.addfile(df_tar, fileobj=df) + df_tar.size = df_bytes.getbuffer().nbytes + tmp_tar.addfile(df_tar, fileobj=df_bytes) tmp_tar.close() diff --git a/tests/docker/dockerfiles/debian-bootstrap.pre b/tests/docker/dockerfiles/debian-bootstrap.pre index c164778c30..35c85f7db8 100755 --- a/tests/docker/dockerfiles/debian-bootstrap.pre +++ b/tests/docker/dockerfiles/debian-bootstrap.pre @@ -80,6 +80,13 @@ else fi # +# Add optional args +# +if [ -n "${DEB_KEYRING}" ]; then + DEBOOTSTRAP="${DEBOOTSTRAP} --keyring=${DEB_KEYRING}" +fi + +# # Finally check to see if any qemu's are installed # BINFMT_DIR=/proc/sys/fs/binfmt_misc diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028 index 5d043cef92..6dd3ae09a3 100755 --- a/tests/qemu-iotests/028 +++ b/tests/qemu-iotests/028 @@ -142,6 +142,25 @@ TEST_IMG="${TEST_IMG}.copy" io_zero readv $(( offset + 32 * 1024 )) 512 1024 32 _check_test_img +echo +echo '=== Reading across backing EOF in one operation ===' +echo + +# Use a cluster boundary as the base end here +base_size=$((3 * 1024 * 1024 * 1024)) + +TEST_IMG="$TEST_IMG.base" _make_test_img $base_size +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $image_size + +# Write 16 times 42 at the end of the base image +$QEMU_IO -c "write -P 42 $((base_size - 16)) 16" "$TEST_IMG.base" \ + | _filter_qemu_io + +# Read 32 bytes across the base EOF from the top; +# should be 16 times 0x2a, then 16 times 0x00 +$QEMU_IO -c "read -v $((base_size - 16)) 32" "$TEST_IMG" \ + | _filter_qemu_io + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out index 12f82c6a6c..5a68de5c46 100644 --- a/tests/qemu-iotests/028.out +++ b/tests/qemu-iotests/028.out @@ -730,4 +730,15 @@ read 512/512 bytes at offset 3221257728 read 512/512 bytes at offset 3221258752 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. + +=== Reading across backing EOF in one operation === + +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=3221225472 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294968832 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +wrote 16/16 bytes at offset 3221225456 +16 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +bffffff0: 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a ................ +c0000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +read 32/32 bytes at offset 3221225456 +32 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 index 95f05b0e34..a161c89816 100755 --- a/tests/qemu-iotests/197 +++ b/tests/qemu-iotests/197 @@ -112,9 +112,13 @@ echo echo '=== Partial final cluster ===' echo -_make_test_img 1024 -$QEMU_IO -f $IMGFMT -C -c 'read 0 1024' "$TEST_IMG" | _filter_qemu_io -$QEMU_IO -f $IMGFMT -c map "$TEST_IMG" +# Force compat=1.1, because writing zeroes on a v2 image without a +# backing file would just result in an unallocated cluster +# (Also, note that this is really a pure qcow2 test.) +IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \ + _make_test_img --no-opts -o compat=1.1 1024 +$QEMU_IO -f qcow2 -C -c 'read 0 1024' "$TEST_WRAP" | _filter_qemu_io +$QEMU_IO -f qcow2 -c map "$TEST_WRAP" _check_test_img # success, all done diff --git a/tests/qemu-iotests/197.out b/tests/qemu-iotests/197.out index 7ca46be6e4..ad414c3b0e 100644 --- a/tests/qemu-iotests/197.out +++ b/tests/qemu-iotests/197.out @@ -26,7 +26,7 @@ Images are identical. === Partial final cluster === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1024 +Formatting 'TEST_DIR/t.wrap.IMGFMT', fmt=IMGFMT size=1024 read 1024/1024 bytes at offset 0 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199 index 40774eed74..58fad872a1 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/199 @@ -20,17 +20,76 @@ import os import iotests -import time from iotests import qemu_img +debug = False + disk_a = os.path.join(iotests.test_dir, 'disk_a') disk_b = os.path.join(iotests.test_dir, 'disk_b') size = '256G' fifo = os.path.join(iotests.test_dir, 'mig_fifo') -class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): +granularity = 512 +nb_bitmaps = 15 + +GiB = 1024 * 1024 * 1024 + +discards1 = ( + (0, GiB), + (2 * GiB + 512 * 5, 512), + (3 * GiB + 512 * 5, 512), + (100 * GiB, GiB) +) + +discards2 = ( + (3 * GiB + 512 * 8, 512), + (4 * GiB + 512 * 8, 512), + (50 * GiB, GiB), + (100 * GiB + GiB // 2, GiB) +) + + +def apply_discards(vm, discards): + for d in discards: + vm.hmp_qemu_io('drive0', 'discard {} {}'.format(*d)) + + +def event_seconds(event): + return event['timestamp']['seconds'] + \ + event['timestamp']['microseconds'] / 1000000.0 + + +def event_dist(e1, e2): + return event_seconds(e2) - event_seconds(e1) + + +def check_bitmaps(vm, count): + result = vm.qmp('query-block') + + if count == 0: + assert 'dirty-bitmaps' not in result['return'][0] + else: + assert len(result['return'][0]['dirty-bitmaps']) == count + +class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): def tearDown(self): + if debug: + self.vm_a_events += self.vm_a.get_qmp_events() + self.vm_b_events += self.vm_b.get_qmp_events() + for e in self.vm_a_events: + e['vm'] = 'SRC' + for e in self.vm_b_events: + e['vm'] = 'DST' + events = (self.vm_a_events + self.vm_b_events) + events = [(e['timestamp']['seconds'], + e['timestamp']['microseconds'], + e['vm'], + e['event'], + e.get('data', '')) for e in events] + for e in sorted(events): + print('{}.{:06} {} {} {}'.format(*e)) + self.vm_a.shutdown() self.vm_b.shutdown() os.remove(disk_a) @@ -41,51 +100,66 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): os.mkfifo(fifo) qemu_img('create', '-f', iotests.imgfmt, disk_a, size) qemu_img('create', '-f', iotests.imgfmt, disk_b, size) - self.vm_a = iotests.VM(path_suffix='a').add_drive(disk_a) - self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b) + self.vm_a = iotests.VM(path_suffix='a').add_drive(disk_a, + 'discard=unmap') + self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b, + 'discard=unmap') self.vm_b.add_incoming("exec: cat '" + fifo + "'") self.vm_a.launch() self.vm_b.launch() - def test_postcopy(self): - write_size = 0x40000000 - granularity = 512 - chunk = 4096 + # collect received events for debug + self.vm_a_events = [] + self.vm_b_events = [] - result = self.vm_a.qmp('block-dirty-bitmap-add', node='drive0', - name='bitmap', granularity=granularity) - self.assert_qmp(result, 'return', {}); + def start_postcopy(self): + """ Run migration until RESUME event on target. Return this event. """ + for i in range(nb_bitmaps): + result = self.vm_a.qmp('block-dirty-bitmap-add', node='drive0', + name='bitmap{}'.format(i), + granularity=granularity, + persistent=True) + self.assert_qmp(result, 'return', {}) - s = 0 - while s < write_size: - self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) - s += 0x10000 - s = 0x8000 - while s < write_size: - self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) - s += 0x10000 + result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', + node='drive0', name='bitmap0') + empty_sha256 = result['return']['sha256'] + + apply_discards(self.vm_a, discards1) result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', - node='drive0', name='bitmap') - sha256 = result['return']['sha256'] - - result = self.vm_a.qmp('block-dirty-bitmap-clear', node='drive0', - name='bitmap') - self.assert_qmp(result, 'return', {}); - s = 0 - while s < write_size: - self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) - s += 0x10000 - - bitmaps_cap = {'capability': 'dirty-bitmaps', 'state': True} - events_cap = {'capability': 'events', 'state': True} - - result = self.vm_a.qmp('migrate-set-capabilities', - capabilities=[bitmaps_cap, events_cap]) + node='drive0', name='bitmap0') + self.discards1_sha256 = result['return']['sha256'] + + # Check, that updating the bitmap by discards works + assert self.discards1_sha256 != empty_sha256 + + # We want to calculate resulting sha256. Do it in bitmap0, so, disable + # other bitmaps + for i in range(1, nb_bitmaps): + result = self.vm_a.qmp('block-dirty-bitmap-disable', node='drive0', + name='bitmap{}'.format(i)) + self.assert_qmp(result, 'return', {}) + + apply_discards(self.vm_a, discards2) + + result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', + node='drive0', name='bitmap0') + self.all_discards_sha256 = result['return']['sha256'] + + # Now, enable some bitmaps, to be updated during migration + for i in range(2, nb_bitmaps, 2): + result = self.vm_a.qmp('block-dirty-bitmap-enable', node='drive0', + name='bitmap{}'.format(i)) + self.assert_qmp(result, 'return', {}) + + caps = [{'capability': 'dirty-bitmaps', 'state': True}, + {'capability': 'events', 'state': True}] + + result = self.vm_a.qmp('migrate-set-capabilities', capabilities=caps) self.assert_qmp(result, 'return', {}) - result = self.vm_b.qmp('migrate-set-capabilities', - capabilities=[bitmaps_cap]) + result = self.vm_b.qmp('migrate-set-capabilities', capabilities=caps) self.assert_qmp(result, 'return', {}) result = self.vm_a.qmp('migrate', uri='exec:cat>' + fifo) @@ -94,26 +168,94 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): result = self.vm_a.qmp('migrate-start-postcopy') self.assert_qmp(result, 'return', {}) - while True: - event = self.vm_a.event_wait('MIGRATION') - if event['data']['status'] == 'completed': - break + event_resume = self.vm_b.event_wait('RESUME') + self.vm_b_events.append(event_resume) + return event_resume + + def test_postcopy_success(self): + event_resume = self.start_postcopy() + + # enabled bitmaps should be updated + apply_discards(self.vm_b, discards2) + + match = {'data': {'status': 'completed'}} + event_complete = self.vm_b.event_wait('MIGRATION', match=match) + self.vm_b_events.append(event_complete) + + # take queued event, should already been happened + event_stop = self.vm_a.event_wait('STOP') + self.vm_a_events.append(event_stop) + + downtime = event_dist(event_stop, event_resume) + postcopy_time = event_dist(event_resume, event_complete) + + assert downtime * 10 < postcopy_time + if debug: + print('downtime:', downtime) + print('postcopy_time:', postcopy_time) + + # check that there are no bitmaps stored on source + self.vm_a_events += self.vm_a.get_qmp_events() + self.vm_a.shutdown() + self.vm_a.launch() + check_bitmaps(self.vm_a, 0) + + # check that bitmaps are migrated and persistence works + check_bitmaps(self.vm_b, nb_bitmaps) + self.vm_b.shutdown() + # recreate vm_b, so there is no incoming option, which prevents + # loading bitmaps from disk + self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b) + self.vm_b.launch() + check_bitmaps(self.vm_b, nb_bitmaps) + + # Check content of migrated bitmaps. Still, don't waste time checking + # every bitmap + for i in range(0, nb_bitmaps, 5): + result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256', + node='drive0', name='bitmap{}'.format(i)) + sha = self.discards1_sha256 if i % 2 else self.all_discards_sha256 + self.assert_qmp(result, 'return/sha256', sha) + + def test_early_shutdown_destination(self): + self.start_postcopy() + + self.vm_b_events += self.vm_b.get_qmp_events() + self.vm_b.shutdown() + # recreate vm_b, so there is no incoming option, which prevents + # loading bitmaps from disk + self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b) + self.vm_b.launch() + check_bitmaps(self.vm_b, 0) - s = 0x8000 - while s < write_size: - self.vm_b.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) - s += 0x10000 + # Bitmaps will be lost if we just shutdown the vm, as they are marked + # to skip storing to disk when prepared for migration. And that's + # correct, as actual data may be modified in target vm, so we play + # safe. + # Still, this mark would be taken away if we do 'cont', and bitmaps + # become persistent again. (see iotest 169 for such behavior case) + result = self.vm_a.qmp('query-status') + assert not result['return']['running'] + self.vm_a_events += self.vm_a.get_qmp_events() + self.vm_a.shutdown() + self.vm_a.launch() + check_bitmaps(self.vm_a, 0) + + def test_early_kill_source(self): + self.start_postcopy() + + self.vm_a_events = self.vm_a.get_qmp_events() + self.vm_a.kill() + + self.vm_a.launch() - result = self.vm_b.qmp('query-block'); - while len(result['return'][0]['dirty-bitmaps']) > 1: - time.sleep(2) - result = self.vm_b.qmp('query-block'); + match = {'data': {'status': 'completed'}} + e_complete = self.vm_b.event_wait('MIGRATION', match=match) + self.vm_b_events.append(e_complete) - result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256', - node='drive0', name='bitmap') + check_bitmaps(self.vm_a, 0) + check_bitmaps(self.vm_b, 0) - self.assert_qmp(result, 'return/sha256', sha256); if __name__ == '__main__': - iotests.main(supported_fmts=['qcow2'], supported_cache_modes=['none'], - supported_protocols=['file']) + iotests.main(supported_fmts=['qcow2']) diff --git a/tests/qemu-iotests/199.out b/tests/qemu-iotests/199.out index ae1213e6f8..8d7e996700 100644 --- a/tests/qemu-iotests/199.out +++ b/tests/qemu-iotests/199.out @@ -1,5 +1,5 @@ -. +... ---------------------------------------------------------------------- -Ran 1 tests +Ran 3 tests OK diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index e0d8049012..0657f7286c 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -595,15 +595,19 @@ then fi export QEMU_PROG="$(type -p "$QEMU_PROG")" +export QEMU_OPTIONS="-nodefaults -display none -accel qtest" case "$QEMU_PROG" in *qemu-system-arm|*qemu-system-aarch64) - export QEMU_OPTIONS="-nodefaults -display none -machine virt -accel qtest" + export QEMU_OPTIONS="$QEMU_OPTIONS -machine virt" ;; - *qemu-system-tricore) - export QEMU_OPTIONS="-nodefaults -display none -machine tricore_testboard -accel qtest" + *qemu-system-avr) + export QEMU_OPTIONS="$QEMU_OPTIONS -machine mega2560" + ;; + *qemu-system-rx) + export QEMU_OPTIONS="$QEMU_OPTIONS -machine gdbsim-r5f562n8" ;; - *) - export QEMU_OPTIONS="-nodefaults -display none -accel qtest" + *qemu-system-tricore) + export QEMU_OPTIONS="-$QEMU_OPTIONS -machine tricore_testboard" ;; esac diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 1d0252e1f0..806044642c 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -112,7 +112,7 @@ 088 rw quick 089 rw auto quick 090 rw auto quick -091 rw migration +091 rw migration quick 092 rw quick 093 throttle 094 rw quick @@ -186,7 +186,7 @@ 162 quick 163 rw 165 rw quick -169 rw quick migration +169 rw migration 170 rw auto quick 171 rw quick 172 auto @@ -197,9 +197,9 @@ 177 rw auto quick 178 img 179 rw auto quick -181 rw auto migration +181 rw auto migration quick 182 rw quick -183 rw migration +183 rw migration quick 184 rw auto quick 185 rw 186 rw auto @@ -216,9 +216,9 @@ 198 rw 199 rw migration 200 rw -201 rw migration +201 rw migration quick 202 rw quick -203 rw auto migration +203 rw auto migration quick 204 rw quick 205 rw quick 206 rw diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 7acb48b876..3fac20e929 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -80,6 +80,8 @@ class BaseVM(object): arch = "#arch" # command to halt the guest, can be overridden by subclasses poweroff = "poweroff" + # Time to wait for shutdown to finish. + shutdown_timeout_default = 30 # enable IPv6 networking ipv6 = True # This is the timeout on the wait for console bytes. @@ -87,7 +89,7 @@ class BaseVM(object): # Scale up some timeouts under TCG. # 4 is arbitrary, but greater than 2, # since we found we need to wait more than twice as long. - tcg_ssh_timeout_multiplier = 4 + tcg_timeout_multiplier = 4 def __init__(self, args, config=None): self._guest = None self._genisoimage = args.genisoimage @@ -141,9 +143,12 @@ class BaseVM(object): if args.jobs and args.jobs > 1: self._args += ["-smp", "%d" % args.jobs] if kvm_available(self.arch): + self._shutdown_timeout = self.shutdown_timeout_default self._args += ["-enable-kvm"] else: logging.info("KVM not available, not using -enable-kvm") + self._shutdown_timeout = \ + self.shutdown_timeout_default * self.tcg_timeout_multiplier self._data_args = [] if self._config['qemu_args'] != None: @@ -423,7 +428,7 @@ class BaseVM(object): def wait_ssh(self, wait_root=False, seconds=300, cmd="exit 0"): # Allow more time for VM to boot under TCG. if not kvm_available(self.arch): - seconds *= self.tcg_ssh_timeout_multiplier + seconds *= self.tcg_timeout_multiplier starttime = datetime.datetime.now() endtime = starttime + datetime.timedelta(seconds=seconds) cmd_success = False @@ -441,14 +446,14 @@ class BaseVM(object): raise Exception("Timeout while waiting for guest ssh") def shutdown(self): - self._guest.shutdown() + self._guest.shutdown(timeout=self._shutdown_timeout) def wait(self): - self._guest.wait() + self._guest.wait(timeout=self._shutdown_timeout) def graceful_shutdown(self): self.ssh_root(self.poweroff) - self._guest.wait() + self._guest.wait(timeout=self._shutdown_timeout) def qmp(self, *args, **kwargs): return self._guest.qmp(*args, **kwargs) |