#!/usr/bin/env python3 # # This test covers the basic fleecing workflow, which provides a # point-in-time snapshot of a node that can be queried over NBD. # # Copyright (C) 2018 Red Hat, Inc. # John helped, too. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Creator/Owner: John Snow import iotests from iotests import log, qemu_img, qemu_io, qemu_io_silent iotests.verify_platform(['linux']) iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk', 'vhdx', 'raw']) patterns = [("0x5d", "0", "64k"), ("0xd5", "1M", "64k"), ("0xdc", "32M", "64k"), ("0xcd", "0x3ff0000", "64k")] # 64M - 64K overwrite = [("0xab", "0", "64k"), # Full overwrite ("0xad", "0x00f8000", "64k"), # Partial-left (1M-32K) ("0x1d", "0x2008000", "64k"), # Partial-right (32M+32K) ("0xea", "0x3fe0000", "64k")] # Adjacent-left (64M - 128K) zeroes = [("0", "0x00f8000", "32k"), # Left-end of partial-left (1M-32K) ("0", "0x2010000", "32k"), # Right-end of partial-right (32M+64K) ("0", "0x3fe0000", "64k")] # overwrite[3] remainder = [("0xd5", "0x108000", "32k"), # Right-end of partial-left [1] ("0xdc", "32M", "32k"), # Left-end of partial-right [2] ("0xcd", "0x3ff0000", "64k")] # patterns[3] with iotests.FilePath('base.img') as base_img_path, \ iotests.FilePath('fleece.img') as fleece_img_path, \ iotests.FilePath('nbd.sock', iotests.sock_dir) as nbd_sock_path, \ iotests.VM() as vm: log('--- Setting up images ---') log('') assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0 assert qemu_img('create', '-f', "qcow2", fleece_img_path, '64M') == 0 for p in patterns: qemu_io('-f', iotests.imgfmt, '-c', 'write -P%s %s %s' % p, base_img_path) log('Done') log('') log('--- Launching VM ---') log('') vm.add_drive(base_img_path) vm.launch() log('Done') log('') log('--- Setting up Fleecing Graph ---') log('') src_node = "drive0" tgt_node = "fleeceNode" # create tgt_node backed by src_node log(vm.qmp("blockdev-add", **{ "driver": "qcow2", "node-name": tgt_node, "file": { "driver": "file", "filename": fleece_img_path, }, "backing": src_node, })) # Establish COW from source to fleecing node log(vm.qmp("blockdev-backup", device=src_node, target=tgt_node, sync="none")) log('') log('--- Setting up NBD Export ---') log('') nbd_uri = 'nbd+unix:///%s?socket=%s' % (tgt_node, nbd_sock_path) log(vm.qmp("nbd-server-start", **{"addr": { "type": "unix", "data": { "path": nbd_sock_path } } })) log(vm.qmp("nbd-server-add", device=tgt_node)) log('') log('--- Sanity Check ---') log('') for p in (patterns + zeroes): cmd = "read -P%s %s %s" % p log(cmd) assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0 log('') log('--- Testing COW ---') log('') for p in overwrite: cmd = "write -P%s %s %s" % p log(cmd) log(vm.hmp_qemu_io(src_node, cmd)) log('') log('--- Verifying Data ---') log('') for p in (patterns + zeroes): cmd = "read -P%s %s %s" % p log(cmd) assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0 log('') log('--- Cleanup ---') log('') log(vm.qmp('block-job-cancel', device=src_node)) log(vm.event_wait('BLOCK_JOB_CANCELLED'), filters=[iotests.filter_qmp_event]) log(vm.qmp('nbd-server-stop')) log(vm.qmp('blockdev-del', node_name=tgt_node)) vm.shutdown() log('') log('--- Confirming writes ---') log('') for p in (overwrite + remainder): cmd = "read -P%s %s %s" % p log(cmd) assert qemu_io_silent(base_img_path, '-c', cmd) == 0 log('') log('Done')