1*0f62cd82SMax Reitz#!/usr/bin/env python 2*0f62cd82SMax Reitz# 3*0f62cd82SMax Reitz# Test for when a backing file is considered overridden (thus, a 4*0f62cd82SMax Reitz# json:{} filename is generated for the overlay) and when it is not 5*0f62cd82SMax Reitz# 6*0f62cd82SMax Reitz# Copyright (C) 2018 Red Hat, Inc. 7*0f62cd82SMax Reitz# 8*0f62cd82SMax Reitz# This program is free software; you can redistribute it and/or modify 9*0f62cd82SMax Reitz# it under the terms of the GNU General Public License as published by 10*0f62cd82SMax Reitz# the Free Software Foundation; either version 2 of the License, or 11*0f62cd82SMax Reitz# (at your option) any later version. 12*0f62cd82SMax Reitz# 13*0f62cd82SMax Reitz# This program is distributed in the hope that it will be useful, 14*0f62cd82SMax Reitz# but WITHOUT ANY WARRANTY; without even the implied warranty of 15*0f62cd82SMax Reitz# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*0f62cd82SMax Reitz# GNU General Public License for more details. 17*0f62cd82SMax Reitz# 18*0f62cd82SMax Reitz# You should have received a copy of the GNU General Public License 19*0f62cd82SMax Reitz# along with this program. If not, see <http://www.gnu.org/licenses/>. 20*0f62cd82SMax Reitz# 21*0f62cd82SMax Reitz# Creator/Owner: Max Reitz <mreitz@redhat.com> 22*0f62cd82SMax Reitz 23*0f62cd82SMax Reitzimport iotests 24*0f62cd82SMax Reitzfrom iotests import log, qemu_img, filter_testfiles, filter_imgfmt, \ 25*0f62cd82SMax Reitz filter_qmp_testfiles, filter_qmp_imgfmt 26*0f62cd82SMax Reitz 27*0f62cd82SMax Reitz# Need backing file and change-backing-file support 28*0f62cd82SMax Reitziotests.verify_image_format(supported_fmts=['qcow2', 'qed']) 29*0f62cd82SMax Reitziotests.verify_platform(['linux']) 30*0f62cd82SMax Reitz 31*0f62cd82SMax Reitz 32*0f62cd82SMax Reitzdef log_node_info(node): 33*0f62cd82SMax Reitz log('') 34*0f62cd82SMax Reitz 35*0f62cd82SMax Reitz log('bs->filename: ' + node['image']['filename'], 36*0f62cd82SMax Reitz filters=[filter_testfiles, filter_imgfmt]) 37*0f62cd82SMax Reitz log('bs->backing_file: ' + node['backing_file'], 38*0f62cd82SMax Reitz filters=[filter_testfiles, filter_imgfmt]) 39*0f62cd82SMax Reitz 40*0f62cd82SMax Reitz if 'backing-image' in node['image']: 41*0f62cd82SMax Reitz log('bs->backing->bs->filename: ' + 42*0f62cd82SMax Reitz node['image']['backing-image']['filename'], 43*0f62cd82SMax Reitz filters=[filter_testfiles, filter_imgfmt]) 44*0f62cd82SMax Reitz else: 45*0f62cd82SMax Reitz log('bs->backing: (none)') 46*0f62cd82SMax Reitz 47*0f62cd82SMax Reitz log('') 48*0f62cd82SMax Reitz 49*0f62cd82SMax Reitz 50*0f62cd82SMax Reitzwith iotests.FilePath('base.img') as base_img_path, \ 51*0f62cd82SMax Reitz iotests.FilePath('top.img') as top_img_path, \ 52*0f62cd82SMax Reitz iotests.VM() as vm: 53*0f62cd82SMax Reitz 54*0f62cd82SMax Reitz assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0 55*0f62cd82SMax Reitz # Choose a funny way to describe the backing filename 56*0f62cd82SMax Reitz assert qemu_img('create', '-f', iotests.imgfmt, '-b', 57*0f62cd82SMax Reitz 'file:' + base_img_path, top_img_path) == 0 58*0f62cd82SMax Reitz 59*0f62cd82SMax Reitz vm.launch() 60*0f62cd82SMax Reitz 61*0f62cd82SMax Reitz log('--- Implicit backing file ---') 62*0f62cd82SMax Reitz log('') 63*0f62cd82SMax Reitz 64*0f62cd82SMax Reitz vm.qmp_log('blockdev-add', 65*0f62cd82SMax Reitz node_name='node0', 66*0f62cd82SMax Reitz driver=iotests.imgfmt, 67*0f62cd82SMax Reitz file={ 68*0f62cd82SMax Reitz 'driver': 'file', 69*0f62cd82SMax Reitz 'filename': top_img_path 70*0f62cd82SMax Reitz }, 71*0f62cd82SMax Reitz filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) 72*0f62cd82SMax Reitz 73*0f62cd82SMax Reitz # Filename should be plain, and the backing filename should not 74*0f62cd82SMax Reitz # contain the "file:" prefix 75*0f62cd82SMax Reitz log_node_info(vm.node_info('node0')) 76*0f62cd82SMax Reitz 77*0f62cd82SMax Reitz vm.qmp_log('blockdev-del', node_name='node0') 78*0f62cd82SMax Reitz 79*0f62cd82SMax Reitz log('') 80*0f62cd82SMax Reitz log('--- change-backing-file ---') 81*0f62cd82SMax Reitz log('') 82*0f62cd82SMax Reitz 83*0f62cd82SMax Reitz vm.qmp_log('blockdev-add', 84*0f62cd82SMax Reitz node_name='node0', 85*0f62cd82SMax Reitz driver=iotests.imgfmt, 86*0f62cd82SMax Reitz file={ 87*0f62cd82SMax Reitz 'driver': 'file', 88*0f62cd82SMax Reitz 'filename': top_img_path 89*0f62cd82SMax Reitz }, 90*0f62cd82SMax Reitz filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) 91*0f62cd82SMax Reitz 92*0f62cd82SMax Reitz # Changing the backing file to a qemu-reported filename should 93*0f62cd82SMax Reitz # result in qemu accepting the corresponding BDS as the implicit 94*0f62cd82SMax Reitz # backing BDS (and thus not generate a json:{} filename). 95*0f62cd82SMax Reitz # So, first, query the backing filename. 96*0f62cd82SMax Reitz 97*0f62cd82SMax Reitz backing_filename = \ 98*0f62cd82SMax Reitz vm.node_info('node0')['image']['backing-image']['filename'] 99*0f62cd82SMax Reitz 100*0f62cd82SMax Reitz # Next, change the backing file to something different 101*0f62cd82SMax Reitz 102*0f62cd82SMax Reitz vm.qmp_log('change-backing-file', 103*0f62cd82SMax Reitz image_node_name='node0', 104*0f62cd82SMax Reitz device='node0', 105*0f62cd82SMax Reitz backing_file='null-co://', 106*0f62cd82SMax Reitz filters=[filter_qmp_testfiles]) 107*0f62cd82SMax Reitz 108*0f62cd82SMax Reitz # Now, verify that we get a json:{} filename 109*0f62cd82SMax Reitz # (Image header says "null-co://", actual backing file still is 110*0f62cd82SMax Reitz # base_img_path) 111*0f62cd82SMax Reitz 112*0f62cd82SMax Reitz log_node_info(vm.node_info('node0')) 113*0f62cd82SMax Reitz 114*0f62cd82SMax Reitz # Change it back 115*0f62cd82SMax Reitz # (To get header and backing file in sync) 116*0f62cd82SMax Reitz 117*0f62cd82SMax Reitz vm.qmp_log('change-backing-file', 118*0f62cd82SMax Reitz image_node_name='node0', 119*0f62cd82SMax Reitz device='node0', 120*0f62cd82SMax Reitz backing_file=backing_filename, 121*0f62cd82SMax Reitz filters=[filter_qmp_testfiles]) 122*0f62cd82SMax Reitz 123*0f62cd82SMax Reitz # And verify that we get our original results 124*0f62cd82SMax Reitz 125*0f62cd82SMax Reitz log_node_info(vm.node_info('node0')) 126*0f62cd82SMax Reitz 127*0f62cd82SMax Reitz # Finally, try a "file:" prefix. While this is actually what we 128*0f62cd82SMax Reitz # originally had in the image header, qemu will not reopen the 129*0f62cd82SMax Reitz # backing file here, so it cannot verify that this filename 130*0f62cd82SMax Reitz # "resolves" to the actual backing BDS's filename and will thus 131*0f62cd82SMax Reitz # consider both to be different. 132*0f62cd82SMax Reitz # (This may be fixed in the future.) 133*0f62cd82SMax Reitz 134*0f62cd82SMax Reitz vm.qmp_log('change-backing-file', 135*0f62cd82SMax Reitz image_node_name='node0', 136*0f62cd82SMax Reitz device='node0', 137*0f62cd82SMax Reitz backing_file=('file:' + backing_filename), 138*0f62cd82SMax Reitz filters=[filter_qmp_testfiles]) 139*0f62cd82SMax Reitz 140*0f62cd82SMax Reitz # So now we should get a json:{} filename 141*0f62cd82SMax Reitz 142*0f62cd82SMax Reitz log_node_info(vm.node_info('node0')) 143*0f62cd82SMax Reitz 144*0f62cd82SMax Reitz # Remove and re-attach so we can see that (as in our first try), 145*0f62cd82SMax Reitz # opening the image anew helps qemu resolve the header backing 146*0f62cd82SMax Reitz # filename. 147*0f62cd82SMax Reitz 148*0f62cd82SMax Reitz vm.qmp_log('blockdev-del', node_name='node0') 149*0f62cd82SMax Reitz 150*0f62cd82SMax Reitz vm.qmp_log('blockdev-add', 151*0f62cd82SMax Reitz node_name='node0', 152*0f62cd82SMax Reitz driver=iotests.imgfmt, 153*0f62cd82SMax Reitz file={ 154*0f62cd82SMax Reitz 'driver': 'file', 155*0f62cd82SMax Reitz 'filename': top_img_path 156*0f62cd82SMax Reitz }, 157*0f62cd82SMax Reitz filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) 158*0f62cd82SMax Reitz 159*0f62cd82SMax Reitz log_node_info(vm.node_info('node0')) 160*0f62cd82SMax Reitz 161*0f62cd82SMax Reitz vm.qmp_log('blockdev-del', node_name='node0') 162*0f62cd82SMax Reitz 163*0f62cd82SMax Reitz log('') 164*0f62cd82SMax Reitz log('--- Override backing file ---') 165*0f62cd82SMax Reitz log('') 166*0f62cd82SMax Reitz 167*0f62cd82SMax Reitz # For this test, we need the plain filename in the image header 168*0f62cd82SMax Reitz # (because qemu cannot "canonicalize"/"resolve" the backing 169*0f62cd82SMax Reitz # filename unless the backing file is opened implicitly with the 170*0f62cd82SMax Reitz # overlay) 171*0f62cd82SMax Reitz assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path, 172*0f62cd82SMax Reitz top_img_path) == 0 173*0f62cd82SMax Reitz 174*0f62cd82SMax Reitz # You can only reliably override backing options by using a node 175*0f62cd82SMax Reitz # reference (or by specifying file.filename, but, well...) 176*0f62cd82SMax Reitz vm.qmp_log('blockdev-add', node_name='null', driver='null-co') 177*0f62cd82SMax Reitz 178*0f62cd82SMax Reitz vm.qmp_log('blockdev-add', 179*0f62cd82SMax Reitz node_name='node0', 180*0f62cd82SMax Reitz driver=iotests.imgfmt, 181*0f62cd82SMax Reitz file={ 182*0f62cd82SMax Reitz 'driver': 'file', 183*0f62cd82SMax Reitz 'filename': top_img_path 184*0f62cd82SMax Reitz }, 185*0f62cd82SMax Reitz backing='null', 186*0f62cd82SMax Reitz filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) 187*0f62cd82SMax Reitz 188*0f62cd82SMax Reitz # Should get a json:{} filename (and bs->backing_file is 189*0f62cd82SMax Reitz # null-co://, because that field actually has not much to do 190*0f62cd82SMax Reitz # with the header backing filename (except that it is changed by 191*0f62cd82SMax Reitz # change-backing-file)) 192*0f62cd82SMax Reitz 193*0f62cd82SMax Reitz log_node_info(vm.node_info('node0')) 194*0f62cd82SMax Reitz 195*0f62cd82SMax Reitz # Detach the backing file by reopening the whole thing 196*0f62cd82SMax Reitz 197*0f62cd82SMax Reitz vm.qmp_log('blockdev-del', node_name='node0') 198*0f62cd82SMax Reitz vm.qmp_log('blockdev-del', node_name='null') 199*0f62cd82SMax Reitz 200*0f62cd82SMax Reitz vm.qmp_log('blockdev-add', 201*0f62cd82SMax Reitz node_name='node0', 202*0f62cd82SMax Reitz driver=iotests.imgfmt, 203*0f62cd82SMax Reitz file={ 204*0f62cd82SMax Reitz 'driver': 'file', 205*0f62cd82SMax Reitz 'filename': top_img_path 206*0f62cd82SMax Reitz }, 207*0f62cd82SMax Reitz backing=None, 208*0f62cd82SMax Reitz filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) 209*0f62cd82SMax Reitz 210*0f62cd82SMax Reitz # Should get a json:{} filename (because we overrode the backing 211*0f62cd82SMax Reitz # file to not be there) 212*0f62cd82SMax Reitz 213*0f62cd82SMax Reitz log_node_info(vm.node_info('node0')) 214*0f62cd82SMax Reitz 215*0f62cd82SMax Reitz # Open the original backing file 216*0f62cd82SMax Reitz 217*0f62cd82SMax Reitz vm.qmp_log('blockdev-add', 218*0f62cd82SMax Reitz node_name='original-backing', 219*0f62cd82SMax Reitz driver=iotests.imgfmt, 220*0f62cd82SMax Reitz file={ 221*0f62cd82SMax Reitz 'driver': 'file', 222*0f62cd82SMax Reitz 'filename': base_img_path 223*0f62cd82SMax Reitz }, 224*0f62cd82SMax Reitz filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) 225*0f62cd82SMax Reitz 226*0f62cd82SMax Reitz # Attach the original backing file to its overlay 227*0f62cd82SMax Reitz 228*0f62cd82SMax Reitz vm.qmp_log('blockdev-snapshot', 229*0f62cd82SMax Reitz node='original-backing', 230*0f62cd82SMax Reitz overlay='node0') 231*0f62cd82SMax Reitz 232*0f62cd82SMax Reitz # This should give us the original plain result 233*0f62cd82SMax Reitz # FIXME: Currently, the block layer considers the runtime backing 234*0f62cd82SMax Reitz # file to be different from the image header, which is 235*0f62cd82SMax Reitz # wrong. This is fixed by a future patch. 236*0f62cd82SMax Reitz 237*0f62cd82SMax Reitz log_node_info(vm.node_info('node0')) 238*0f62cd82SMax Reitz 239*0f62cd82SMax Reitz vm.qmp_log('blockdev-del', node_name='node0') 240*0f62cd82SMax Reitz vm.qmp_log('blockdev-del', node_name='original-backing') 241*0f62cd82SMax Reitz 242*0f62cd82SMax Reitz vm.shutdown() 243