#!/usr/bin/env python3 # # Test for when a backing file is considered overridden (thus, a # json:{} filename is generated for the overlay) and when it is not # # Copyright (C) 2018 Red Hat, Inc. # # 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: Max Reitz import iotests from iotests import log, qemu_img, filter_testfiles, filter_imgfmt, \ filter_qmp_testfiles, filter_qmp_imgfmt # Need backing file and change-backing-file support iotests.verify_image_format(supported_fmts=['qcow2', 'qed']) iotests.verify_platform(['linux']) def log_node_info(node): log('') log('bs->filename: ' + node['image']['filename'], filters=[filter_testfiles, filter_imgfmt]) log('bs->backing_file: ' + node['backing_file'], filters=[filter_testfiles, filter_imgfmt]) if 'backing-image' in node['image']: log('bs->backing->bs->filename: ' + node['image']['backing-image']['filename'], filters=[filter_testfiles, filter_imgfmt]) else: log('bs->backing: (none)') log('') with iotests.FilePath('base.img') as base_img_path, \ iotests.FilePath('top.img') as top_img_path, \ iotests.VM() as vm: assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0 # Choose a funny way to describe the backing filename assert qemu_img('create', '-f', iotests.imgfmt, '-b', 'file:' + base_img_path, top_img_path) == 0 vm.launch() log('--- Implicit backing file ---') log('') vm.qmp_log('blockdev-add', node_name='node0', driver=iotests.imgfmt, file={ 'driver': 'file', 'filename': top_img_path }, filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) # Filename should be plain, and the backing filename should not # contain the "file:" prefix log_node_info(vm.node_info('node0')) vm.qmp_log('blockdev-del', node_name='node0') log('') log('--- change-backing-file ---') log('') vm.qmp_log('blockdev-add', node_name='node0', driver=iotests.imgfmt, file={ 'driver': 'file', 'filename': top_img_path }, filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) # Changing the backing file to a qemu-reported filename should # result in qemu accepting the corresponding BDS as the implicit # backing BDS (and thus not generate a json:{} filename). # So, first, query the backing filename. backing_filename = \ vm.node_info('node0')['image']['backing-image']['filename'] # Next, change the backing file to something different vm.qmp_log('change-backing-file', image_node_name='node0', device='node0', backing_file='null-co://', filters=[filter_qmp_testfiles]) # Now, verify that we get a json:{} filename # (Image header says "null-co://", actual backing file still is # base_img_path) log_node_info(vm.node_info('node0')) # Change it back # (To get header and backing file in sync) vm.qmp_log('change-backing-file', image_node_name='node0', device='node0', backing_file=backing_filename, filters=[filter_qmp_testfiles]) # And verify that we get our original results log_node_info(vm.node_info('node0')) # Finally, try a "file:" prefix. While this is actually what we # originally had in the image header, qemu will not reopen the # backing file here, so it cannot verify that this filename # "resolves" to the actual backing BDS's filename and will thus # consider both to be different. # (This may be fixed in the future.) vm.qmp_log('change-backing-file', image_node_name='node0', device='node0', backing_file=('file:' + backing_filename), filters=[filter_qmp_testfiles]) # So now we should get a json:{} filename log_node_info(vm.node_info('node0')) # Remove and re-attach so we can see that (as in our first try), # opening the image anew helps qemu resolve the header backing # filename. vm.qmp_log('blockdev-del', node_name='node0') vm.qmp_log('blockdev-add', node_name='node0', driver=iotests.imgfmt, file={ 'driver': 'file', 'filename': top_img_path }, filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) log_node_info(vm.node_info('node0')) vm.qmp_log('blockdev-del', node_name='node0') log('') log('--- Override backing file ---') log('') # For this test, we need the plain filename in the image header # (because qemu cannot "canonicalize"/"resolve" the backing # filename unless the backing file is opened implicitly with the # overlay) assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path, top_img_path) == 0 # You can only reliably override backing options by using a node # reference (or by specifying file.filename, but, well...) vm.qmp_log('blockdev-add', node_name='null', driver='null-co') vm.qmp_log('blockdev-add', node_name='node0', driver=iotests.imgfmt, file={ 'driver': 'file', 'filename': top_img_path }, backing='null', filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) # Should get a json:{} filename (and bs->backing_file is # null-co://, because that field actually has not much to do # with the header backing filename (except that it is changed by # change-backing-file)) log_node_info(vm.node_info('node0')) # Detach the backing file by reopening the whole thing vm.qmp_log('blockdev-del', node_name='node0') vm.qmp_log('blockdev-del', node_name='null') vm.qmp_log('blockdev-add', node_name='node0', driver=iotests.imgfmt, file={ 'driver': 'file', 'filename': top_img_path }, backing=None, filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) # Should get a json:{} filename (because we overrode the backing # file to not be there) log_node_info(vm.node_info('node0')) # Open the original backing file vm.qmp_log('blockdev-add', node_name='original-backing', driver=iotests.imgfmt, file={ 'driver': 'file', 'filename': base_img_path }, filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) # Attach the original backing file to its overlay vm.qmp_log('blockdev-snapshot', node='original-backing', overlay='node0') # This should give us the original plain result log_node_info(vm.node_info('node0')) vm.qmp_log('blockdev-del', node_name='node0') vm.qmp_log('blockdev-del', node_name='original-backing') vm.shutdown()