def test_chain_after_finalize(self, base_fmt): with self.make_env(format=base_fmt, chain_len=3) as env: base_vol = env.chain[0] # We write data to the base and will read it from the child volume # to verify that the chain is valid after qemu-rebase. offset = 0 pattern = 0xf0 length = 1024 qemu_pattern_write(base_vol.volumePath, sc.fmt2str(base_vol.getFormat()), offset=offset, len=length, pattern=pattern) top_vol = env.chain[1] child_vol = env.chain[2] subchain_info = dict(sd_id=base_vol.sdUUID, img_id=base_vol.imgUUID, base_id=base_vol.volUUID, top_id=top_vol.volUUID, base_generation=0) subchain = merge.SubchainInfo(subchain_info, 0) merge.finalize(subchain) qemu_pattern_verify(child_vol.volumePath, sc.fmt2str(child_vol.getFormat()), offset=offset, len=length, pattern=pattern)
def test_subchain_validation(self): job_id = make_uuid() with self.make_env(sd_type='file', chain_len=2) as env: write_qemu_chain(env.chain) base_index = 0 top_index = 1 base_vol = env.chain[base_index] base_vol.setLegality(sc.ILLEGAL_VOL) top_vol = env.chain[top_index] subchain_info = dict(sd_id=top_vol.sdUUID, img_id=top_vol.imgUUID, base_id=base_vol.imgUUID, top_id=top_vol.volUUID, base_generation=0) subchain = merge.SubchainInfo(subchain_info, 0) def fail(): raise se.VolumeIsNotInChain(None, None, None) # We already tested that subchain validate does the right thing, # here we test that this job care to call subchain validate. subchain.validate = fail job = storage.sdm.api.merge.Job(job_id, subchain) job.run() wait_for_job(job) self.assertEqual(job.status, jobs.STATUS.FAILED) self.assertEqual(type(job.error), se.VolumeIsNotInChain) # Check that validate is called *before* attempting - verify that # the chain data was *not* merged offset = base_index * 1024 pattern = 0xf0 + base_index qemu_pattern_verify(base_vol.volumePath, qemuimg.FORMAT.RAW, offset=offset, len=1024, pattern=pattern) self.assertEqual(base_vol.getMetaParam(sc.GENERATION), 0)
def test_match_custom_offset_and_len(self, offset, len): with namedTemporaryDir() as tmpdir: path = os.path.join(tmpdir, 'test') qemuimg.create(path, '1m', qemuimg.FORMAT.QCOW2) qemu_pattern_write(path, qemuimg.FORMAT.QCOW2, offset=offset, len=len) qemu_pattern_verify(path, qemuimg.FORMAT.QCOW2, offset=offset, len=len)
def test_commit(self, qcow2_compat, base, top, use_base): size = 1048576 with namedTemporaryDir() as tmpdir: chain = [] parent = None # Create a chain of 4 volumes. for i in range(4): vol = os.path.join(tmpdir, "vol%d.img" % i) format = (qemuimg.FORMAT.RAW if i == 0 else qemuimg.FORMAT.QCOW2) make_image(vol, size, format, i, qcow2_compat, parent) orig_offset = qemuimg.check(vol)["offset"] if i > 0 else None chain.append((vol, orig_offset)) parent = vol base_vol = chain[base][0] top_vol = chain[top][0] op = qemuimg.commit(top_vol, topFormat=qemuimg.FORMAT.QCOW2, base=base_vol if use_base else None) with utils.closing(op): op.wait_for_completion() base_fmt = (qemuimg.FORMAT.RAW if base == 0 else qemuimg.FORMAT.QCOW2) for i in range(base, top + 1): offset = i * 1024 pattern = 0xf0 + i # The base volume must have the data from all the volumes # merged into it. qemu_pattern_verify(base_vol, base_fmt, offset=offset, len=1024, pattern=pattern) if i > base: # internal and top volumes should keep the data, we # may want to wipe this data when deleting the volumes # later. vol, orig_offset = chain[i] actual_offset = qemuimg.check(vol)["offset"] self.assertEqual(actual_offset, orig_offset)
def test_read_bad_chain_raises(self): with namedTemporaryDir() as tmpdir: # Create a good chain. base_qcow2 = os.path.join(tmpdir, "base.qcow2") qemuimg.create(base_qcow2, "1m", qemuimg.FORMAT.QCOW2) top = os.path.join(tmpdir, "top.qcow2") qemuimg.create(top, "1m", qemuimg.FORMAT.QCOW2, backing=base_qcow2, backingFormat=qemuimg.FORMAT.QCOW2) # Create a broken chain using unsafe rebase with the wrong backing # format. base_raw = os.path.join(tmpdir, "base.raw") qemuimg.create(base_raw, "1m", qemuimg.FORMAT.RAW) operation = qemuimg.rebase(top, backing=base_raw, format=qemuimg.FORMAT.QCOW2, backingFormat=qemuimg.FORMAT.QCOW2, unsafe=True) operation.run() with self.assertRaises(cmdutils.Error): qemu_pattern_verify(top, qemuimg.FORMAT.QCOW2)
def test_merge_subchain(self, sd_type, chain_len, base_index, top_index): job_id = make_uuid() with self.make_env(sd_type=sd_type, chain_len=chain_len) as env: write_qemu_chain(env.chain) base_vol = env.chain[base_index] top_vol = env.chain[top_index] subchain_info = dict(sd_id=base_vol.sdUUID, img_id=base_vol.imgUUID, base_id=base_vol.volUUID, top_id=top_vol.volUUID, base_generation=0) subchain = merge.SubchainInfo(subchain_info, 0) job = storage.sdm.api.merge.Job(job_id, subchain) job.run() wait_for_job(job) self.assertEqual(job.status, jobs.STATUS.DONE) # Verify that the chain data was merged for i in range(base_index, top_index + 1): offset = i * 1024 pattern = 0xf0 + i # We expect to read all data from top qemu_pattern_verify(top_vol.volumePath, qemuimg.FORMAT.QCOW2, offset=offset, len=1024, pattern=pattern) # And base, since top was merged into base qemu_pattern_verify(base_vol.volumePath, sc.fmt2str(base_vol.getFormat()), offset=offset, len=1024, pattern=pattern) self.assertEqual(sorted(self.expected_locks(base_vol)), sorted(guarded.context.locks)) self.assertEqual(base_vol.getLegality(), sc.LEGAL_VOL) self.assertEqual(base_vol.getMetaParam(sc.GENERATION), 1)
def test_commit(self, qcow2_compat, base, top, use_base): size = 1048576 with namedTemporaryDir() as tmpdir: chain = [] parent = None # Create a chain of 4 volumes. for i in range(4): vol = os.path.join(tmpdir, "vol%d.img" % i) format = (qemuimg.FORMAT.RAW if i == 0 else qemuimg.FORMAT.QCOW2) make_image(vol, size, format, i, qcow2_compat, parent) blocks = os.stat(vol).st_blocks chain.append((vol, blocks)) parent = vol base_vol = chain[base][0] top_vol = chain[top][0] op = qemuimg.commit(top_vol, topFormat=qemuimg.FORMAT.QCOW2, base=base_vol if use_base else None) with utils.closing(op): op.wait_for_completion() for i in range(base, top + 1): offset = i * 1024 pattern = 0xf0 + i # The base volume must have the data from all the volumes # merged into it. format = (qemuimg.FORMAT.RAW if i == 0 else qemuimg.FORMAT.QCOW2) qemu_pattern_verify(base_vol, format, offset=offset, len=1024, pattern=pattern) if i > base: # internal and top volumes should keep the data, we # may want to wipe this data when deleting the volumes # later. vol, blocks = chain[i] self.assertEqual(os.stat(vol).st_blocks, blocks)
def test_merge_subchain(self, sd_type, chain_len, base_index, top_index): job_id = make_uuid() with self.make_env(sd_type=sd_type, chain_len=chain_len) as env: write_qemu_chain(env.chain) base_vol = env.chain[base_index] base_vol.setLegality(sc.ILLEGAL_VOL) top_vol = env.chain[top_index] subchain_info = dict(sd_id=base_vol.sdUUID, img_id=base_vol.imgUUID, base_id=base_vol.volUUID, top_id=top_vol.volUUID, base_generation=0) subchain = merge.SubchainInfo(subchain_info, 0) job = storage.sdm.api.merge.Job(job_id, subchain) job.run() wait_for_job(job) self.assertEqual(job.status, jobs.STATUS.DONE) # Verify that the chain data was merged for i in range(base_index, top_index + 1): offset = i * 1024 pattern = 0xf0 + i # We expect to read all data from top qemu_pattern_verify(top_vol.volumePath, qemuimg.FORMAT.QCOW2, offset=offset, len=1024, pattern=pattern) base_format = (qemuimg.FORMAT.RAW if i == 0 else qemuimg.FORMAT.QCOW2) # And base, since top was merged into base qemu_pattern_verify(base_vol.volumePath, base_format, offset=offset, len=1024, pattern=pattern) self.assertEqual(sorted(self.expected_locks(base_vol)), sorted(guarded.context.locks)) self.assertEqual(base_vol.getLegality(), sc.ILLEGAL_VOL) self.assertEqual(base_vol.getMetaParam(sc.GENERATION), 1)
def test_read_missing_file_raises(self, format): with self.assertRaises(cmdutils.Error): qemu_pattern_verify("/no/such/file", format)
def test_match(self, img_format): with namedTemporaryDir() as tmpdir: path = os.path.join(tmpdir, 'test') qemuimg.create(path, '1m', img_format) qemu_pattern_write(path, img_format) qemu_pattern_verify(path, img_format)
def test_read_wrong_format_raises(self): with namedTemporaryDir() as tmpdir: path = os.path.join(tmpdir, "test.qcow2") qemuimg.create(path, "1m", qemuimg.FORMAT.RAW) with self.assertRaises(cmdutils.Error): qemu_pattern_verify(path, qemuimg.FORMAT.QCOW2)