def test_one_block(self, offset, length, expected_length, qcow2_compat): with namedTemporaryDir() as tmpdir: size = 1048576 image = os.path.join(tmpdir, "base.img") qemuimg.create(image, size=size, format=self.FORMAT, qcow2Compat=qcow2_compat) qemu_pattern_write(image, self.FORMAT, offset=offset, len=length, pattern=0xf0) expected = [ # run 1 - empty { "start": 0, "length": offset, "data": False, "zero": True, }, # run 2 - data { "start": offset, "length": expected_length, "data": True, "zero": False, }, # run 3 - empty { "start": offset + expected_length, "length": size - offset - expected_length, "data": False, "zero": True, }, ] self.check_map(qemuimg.map(image), expected)
def test_check(self): with namedTemporaryDir() as tmpdir: path = os.path.join(tmpdir, 'test.qcow2') qemuimg.create(path, size=1048576, format=qemuimg.FORMAT.QCOW2) info = qemuimg.check(path) # The exact value depends on qcow2 internals self.assertEqual(int, type(info['offset']))
def clone(self, dstPath, volFormat): """ Clone self volume to the specified dst_image_dir/dst_volUUID """ wasleaf = False taskName = "parent volume rollback: " + self.volUUID vars.task.pushRecovery( task.Recovery(taskName, "volume", "Volume", "parentVolumeRollback", [self.sdUUID, self.imgUUID, self.volUUID])) if self.isLeaf(): wasleaf = True self.setInternal() try: self.prepare(rw=False) self.log.debug('cloning volume %s to %s', self.volumePath, dstPath) parent = getBackingVolumePath(self.imgUUID, self.volUUID) domain = sdCache.produce(self.sdUUID) qemuimg.create(dstPath, backing=parent, format=sc.fmt2str(volFormat), qcow2Compat=domain.qcow2_compat(), backingFormat=sc.fmt2str(self.getFormat())) self.teardown(self.sdUUID, self.volUUID) except Exception as e: self.log.exception('cannot clone image %s volume %s to %s', self.imgUUID, self.volUUID, dstPath) # FIXME: might race with other clones if wasleaf: self.setLeaf() self.teardown(self.sdUUID, self.volUUID) raise se.CannotCloneVolume(self.volumePath, dstPath, str(e))
def test_wrong_format_raises(self, vol_fmt, qemu_fmt): with self.fake_volume(vol_fmt) as vol: qemuimg.create(vol.volumePath, size=self.SIZE, format=qemu_fmt) h = FakeHSM() self.assertRaises(se.ImageVerificationError, h.verify_untrusted_volume, 'sp', vol.sdUUID, vol.imgUUID, vol.volUUID)
def _create(cls, dom, imgUUID, volUUID, size, volFormat, preallocate, volParent, srcImgUUID, srcVolUUID, volPath, initialSize=None): """ Class specific implementation of volumeCreate. All the exceptions are properly handled and logged in volume.create() """ if initialSize: cls.log.error("initialSize is not supported for file-based " "volumes") raise se.InvalidParameterException("initial size", initialSize) sizeBytes = size * BLOCK_SIZE truncSize = sizeBytes if volFormat == volume.RAW_FORMAT else 0 try: oop.getProcessPool(dom.sdUUID).truncateFile( volPath, truncSize, mode=VOLUME_PERMISSIONS, creatExcl=True) except OSError as e: if e.errno == errno.EEXIST: raise se.VolumeAlreadyExists(volUUID) raise if preallocate == volume.PREALLOCATED_VOL: try: # ddWatchCopy expects size to be in bytes misc.ddWatchCopy("/dev/zero", volPath, vars.task.aborting, sizeBytes) except ActionStopped: raise except Exception: cls.log.error("Unexpected error", exc_info=True) raise se.VolumesZeroingError(volPath) if not volParent: cls.log.info( "Request to create %s volume %s with size = %s " "sectors", volume.type2name(volFormat), volPath, size) if volFormat == volume.COW_FORMAT: qemuimg.create(volPath, sizeBytes, volume.fmt2str(volFormat)) else: # Create hardlink to template and its meta file cls.log.info("Request to create snapshot %s/%s of volume %s/%s", imgUUID, volUUID, srcImgUUID, srcVolUUID) volParent.clone(volPath, volFormat) # Forcing the volume permissions in case one of the tools we use # (dd, qemu-img, etc.) will mistakenly change the file permissiosn. dom.oop.os.chmod(volPath, VOLUME_PERMISSIONS) return (volPath, )
def test_invalid_config(self): config = make_config([('irs', 'qcow2_compat', '1.2')]) with MonkeyPatchScope([(qemuimg, '_supports_qcow2_compat', self.supported('create', True)), (qemuimg, 'config', config)]): with self.assertRaises(exception.InvalidConfiguration): qemuimg.create('image', format='qcow2')
def make_qemu_chain(env, size, base_vol_fmt, chain_len, qcow2_compat='0.10'): vol_list = [] img_id = make_uuid() parent_vol_id = sc.BLANK_UUID vol_fmt = base_vol_fmt for i in range(chain_len): vol_id = make_uuid() if parent_vol_id != sc.BLANK_UUID: vol_fmt = sc.COW_FORMAT env.make_volume(size, img_id, vol_id, parent_vol_id=parent_vol_id, vol_format=vol_fmt) vol = env.sd_manifest.produceVolume(img_id, vol_id) if vol_fmt == sc.COW_FORMAT: backing = parent_vol_id if parent_vol_id != sc.BLANK_UUID else None qemuimg.create(vol.volumePath, size=size, format=qemuimg.FORMAT.QCOW2, qcow2Compat=qcow2_compat, backing=backing) vol_list.append(vol) parent_vol_id = vol_id return vol_list
def test_no_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, pattern=2) self.assertRaises(ChainVerificationError, qemu_pattern_verify, path, img_format, pattern=4)
def test_ok(self, vol_fmt): with self.fake_volume(vol_fmt) as vol: qemu_fmt = sc.FMT2STR[vol_fmt] qemuimg.create(vol.volumePath, size=self.SIZE, format=qemu_fmt) h = FakeHSM() self.assertNotRaises(h.verify_untrusted_volume, 'sp', vol.sdUUID, vol.imgUUID, vol.volUUID)
def clone(self, dstPath, volFormat): """ Clone self volume to the specified dst_image_dir/dst_volUUID """ wasleaf = False taskName = "parent volume rollback: " + self.volUUID vars.task.pushRecovery( task.Recovery(taskName, "volume", "Volume", "parentVolumeRollback", [self.sdUUID, self.imgUUID, self.volUUID])) if self.isLeaf(): wasleaf = True self.setInternal() try: self.prepare(rw=False) self.log.debug('cloning volume %s to %s', self.volumePath, dstPath) parent = getBackingVolumePath(self.imgUUID, self.volUUID) qemuimg.create(dstPath, backing=parent, format=fmt2str(volFormat), backingFormat=fmt2str(self.getFormat())) self.teardown(self.sdUUID, self.volUUID) except Exception as e: self.log.exception('cannot clone image %s volume %s to %s', self.imgUUID, self.volUUID, dstPath) # FIXME: might race with other clones if wasleaf: self.setLeaf() self.teardown(self.sdUUID, self.volUUID) raise se.CannotCloneVolume(self.volumePath, dstPath, str(e))
def make_volume(env, size, md_fmt, real_fmt): img_id = make_uuid() vol_id = make_uuid() env.make_volume(size, img_id, vol_id, vol_format=md_formats[md_fmt]) vol = env.sd_manifest.produceVolume(img_id, vol_id) qemuimg.create(vol.getVolumePath(), size, qemu_formats[real_fmt]) return vol
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_zero_size(self): def create(cmd, **kw): expected = [QEMU_IMG, 'create', 'image', '0'] self.assertEqual(cmd, expected) return 0, '', '' with MonkeyPatchScope([(commands, "execCmd", create)]): qemuimg.create('image', size=0)
def test_zero_size(self): def create(cmd, **kw): expected = [QEMU_IMG, 'create', 'image', '0'] self.assertEqual(cmd, expected) return 0, '', '' with MonkeyPatchScope([(utils, "execCmd", create)]): qemuimg.create('image', size=0)
def test_no_format(self): def create_no_format(cmd, **kw): assert cmd == [qemuimg._qemuimg.cmd, 'create', 'image'] return 0, '', '' with FakeExecCmd(create_no_format): qemuimg.create('image')
def test_no_format(self): def create(cmd, **kw): expected = [QEMU_IMG, 'create', 'image'] self.assertEqual(cmd, expected) return 0, '', '' with MonkeyPatchScope([(utils, "execCmd", create)]): qemuimg.create('image')
def test_no_format(self): def create(cmd, **kw): expected = [QEMU_IMG, 'create', 'image'] self.assertEqual(cmd, expected) return 0, '', '' with MonkeyPatchScope([(commands, "execCmd", create)]): qemuimg.create('image')
def test_no_format(self): def create(cmd, **kw): expected = [QEMU_IMG, 'create', 'image'] self.assertEqual(cmd, expected) return 0, '', '' with FakeCmd(utils, 'execCmd', create): qemuimg.create('image')
def _create(cls, dom, imgUUID, volUUID, size, volFormat, preallocate, volParent, srcImgUUID, srcVolUUID, volPath, initialSize=None): """ Class specific implementation of volumeCreate. All the exceptions are properly handled and logged in volume.create() """ if initialSize: cls.log.error("initialSize is not supported for file-based " "volumes") raise se.InvalidParameterException("initial size", initialSize) sizeBytes = size * BLOCK_SIZE truncSize = sizeBytes if volFormat == sc.RAW_FORMAT else 0 try: oop.getProcessPool(dom.sdUUID).truncateFile( volPath, truncSize, mode=sc.FILE_VOLUME_PERMISSIONS, creatExcl=True) except OSError as e: if e.errno == errno.EEXIST: raise se.VolumeAlreadyExists(volUUID) raise if preallocate == sc.PREALLOCATED_VOL: try: operation = fallocate.allocate(volPath, sizeBytes) with vars.task.abort_callback(operation.abort): with utils.stopwatch("Preallocating volume %s" % volPath): operation.run() except exception.ActionStopped: raise except Exception: cls.log.error("Unexpected error", exc_info=True) raise se.VolumesZeroingError(volPath) if not volParent: cls.log.info("Request to create %s volume %s with size = %s " "sectors", sc.type2name(volFormat), volPath, size) if volFormat == sc.COW_FORMAT: qemuimg.create(volPath, size=sizeBytes, format=sc.fmt2str(volFormat), qcow2Compat=dom.qcow2_compat()) else: # Create hardlink to template and its meta file cls.log.info("Request to create snapshot %s/%s of volume %s/%s", imgUUID, volUUID, srcImgUUID, srcVolUUID) volParent.clone(volPath, volFormat) # Forcing the volume permissions in case one of the tools we use # (dd, qemu-img, etc.) will mistakenly change the file permissiosn. dom.oop.os.chmod(volPath, sc.FILE_VOLUME_PERMISSIONS) return (volPath,)
def test_backingfile_raises(self): with self.fake_volume(sc.COW_FORMAT) as vol: qemu_fmt = qemuimg.FORMAT.QCOW2 qemuimg.create(vol.volumePath, size=self.SIZE, format=qemu_fmt, backing='foo') h = FakeHSM() self.assertRaises(se.ImageVerificationError, h.verify_untrusted_volume, 'sp', vol.sdUUID, vol.imgUUID, vol.volUUID)
def test_qcow2_compat_unsupported(self): def create(cmd, **kw): expected = [QEMU_IMG, 'create', '-f', 'qcow2', 'image'] self.assertEqual(cmd, expected) return 0, '', '' with MonkeyPatchScope([(qemuimg, '_supports_qcow2_compat', self.supported('create', False)), (utils, 'execCmd', create)]): qemuimg.create('image', format='qcow2')
def _create(cls, dom, imgUUID, volUUID, size, volFormat, preallocate, volParent, srcImgUUID, srcVolUUID, volPath): """ Class specific implementation of volumeCreate. All the exceptions are properly handled and logged in volume.create() """ if preallocate == volume.SPARSE_VOL: volSize = "%s" % config.get("irs", "volume_utilization_chunk_mb") else: volSize = "%s" % ((size + SECTORS_TO_MB - 1) / SECTORS_TO_MB) lvm.createLV(dom.sdUUID, volUUID, volSize, activate=True, initialTag=TAG_VOL_UNINIT) utils.rmFile(volPath) os.symlink(lvm.lvPath(dom.sdUUID, volUUID), volPath) if not volParent: cls.log.info( "Request to create %s volume %s with size = %s " "sectors", volume.type2name(volFormat), volPath, size) if volFormat == volume.COW_FORMAT: qemuimg.create(volPath, size * BLOCK_SIZE, volume.fmt2str(volFormat)) else: # Create hardlink to template and its meta file cls.log.info("Request to create snapshot %s/%s of volume %s/%s", imgUUID, volUUID, srcImgUUID, srcVolUUID) volParent.clone(volPath, volFormat) with cls._tagCreateLock: mdSlot = dom.getVolumeMetadataSlot(volUUID, VOLUME_MDNUMBLKS) mdTags = [ "%s%s" % (TAG_PREFIX_MD, mdSlot), "%s%s" % (TAG_PREFIX_PARENT, srcVolUUID), "%s%s" % (TAG_PREFIX_IMAGE, imgUUID) ] lvm.changeLVTags(dom.sdUUID, volUUID, delTags=[TAG_VOL_UNINIT], addTags=mdTags) try: lvm.deactivateLVs(dom.sdUUID, volUUID) except se.CannotDeactivateLogicalVolume: cls.log.warn("Cannot deactivate new created volume %s/%s", dom.sdUUID, volUUID, exc_info=True) return (dom.sdUUID, mdSlot)
def test_empty_image(self, qcow2_compat, desired_qcow2_compat): with namedTemporaryDir() as tmpdir: base_path = os.path.join(tmpdir, 'base.img') leaf_path = os.path.join(tmpdir, 'leaf.img') size = 1048576 qemuimg.create(base_path, size=size, format=qemuimg.FORMAT.RAW) qemuimg.create(leaf_path, format=qemuimg.FORMAT.QCOW2, backing=base_path) qemuimg.amend(leaf_path, desired_qcow2_compat) self.assertEquals(qemuimg.info(leaf_path)['compat'], desired_qcow2_compat)
def test_qcow2_compat_version3(self): def create(cmd, **kw): expected = [ QEMU_IMG, 'create', '-f', 'qcow2', '-o', 'compat=1.1', 'image' ] self.assertEqual(cmd, expected) return 0, '', '' with MonkeyPatchScope([(qemuimg, 'config', CONFIG), (commands, 'execCmd', create)]): qemuimg.create('image', format='qcow2', qcow2Compat='1.1')
def test_qcow2_compat(self): def create(cmd, **kw): expected = [QEMU_IMG, 'create', '-f', 'qcow2', '-o', 'compat=0.10', 'image'] self.assertEqual(cmd, expected) return 0, '', '' with MonkeyPatchScope([(qemuimg, 'config', CONFIG), (commands, 'execCmd', create)]): qemuimg.create('image', format='qcow2')
def make_volume(self, env, img_id, vol_id, parent_vol_id, vol_fmt): if parent_vol_id != sc.BLANK_UUID: vol_fmt = sc.COW_FORMAT env.make_volume(self.SIZE, img_id, vol_id, parent_vol_id=parent_vol_id, vol_format=vol_fmt) vol = env.sd_manifest.produceVolume(img_id, vol_id) if vol_fmt == sc.COW_FORMAT: backing = parent_vol_id if parent_vol_id != sc.BLANK_UUID else None qemuimg.create(vol.volumePath, size=self.SIZE, format=qemuimg.FORMAT.QCOW2, backing=backing) return vol
def test_disabled_compat_raises(self, qemu_compat, hsm_compat): with self.fake_volume(sc.COW_FORMAT) as vol: create_conf = make_config([('irs', 'qcow2_compat', qemu_compat)]) check_conf = make_config([('irs', 'qcow2_compat', hsm_compat)]) with MonkeyPatchScope([(qemuimg, 'config', create_conf), (hsm, 'config', check_conf)]): qemuimg.create(vol.volumePath, size=self.SIZE, format=qemuimg.FORMAT.QCOW2) h = FakeHSM() self.assertRaises(se.ImageVerificationError, h.verify_untrusted_volume, 'sp', vol.sdUUID, vol.imgUUID, vol.volUUID)
def test_valid_qcow2_compat(self, hsm_compat, config_compat, sd_version): with self.fake_volume(vol_fmt=sc.COW_FORMAT, sd_version=sd_version) as vol: create_conf = make_config([('irs', 'qcow2_compat', config_compat)]) info = {"format": qemuimg.FORMAT.QCOW2, "compat": hsm_compat} with MonkeyPatchScope([(qemuimg, 'config', create_conf), (qemuimg, 'info', lambda unused: info)]): qemuimg.create(vol.volumePath, size=self.SIZE, format=qemuimg.FORMAT.QCOW2) h = FakeHSM() self.assertNotRaises(h.verify_untrusted_volume, 'sp', vol.sdUUID, vol.imgUUID, vol.volUUID)
def make_image(path, size, format, index, qcow2_compat, backing=None): qemuimg.create(path, size=size, format=format, qcow2Compat=qcow2_compat, backing=backing) offset = index * 1024 qemu_pattern_write(path, format, offset=offset, len=1024, pattern=0xf0 + index)
def test_qcow2_compat_unsupported(self): def qcow2_compat_unsupported(cmd, **kw): self.check_supports_qcow2_compat(cmd, **kw) return 0, 'Supported options:\nsize ...\n', '' def create(cmd, **kw): expected = [QEMU_IMG, 'create', '-f', 'qcow2', 'image'] self.assertEqual(cmd, expected) return 0, '', '' with FakeCmd(utils, 'execCmd', qcow2_compat_unsupported, create): qemuimg.create('image', format='qcow2')
def test_qcow2_compat_supported(self): def qcow2_compat_supported(cmd, **kw): assert cmd == [qemuimg._qemuimg.cmd, 'create', '-f', 'qcow2', '-o', '?', '/dev/null'] return 0, 'Supported options:\ncompat ...\n', '' def create_qcow2_compat(cmd, **kw): assert cmd == [qemuimg._qemuimg.cmd, 'create', '-f', 'qcow2', '-o', 'compat=0.10', 'image'] return 0, '', '' with FakeExecCmd(qcow2_compat_supported, create_qcow2_compat): qemuimg.create('image', format='qcow2')
def test_info(self): with namedTemporaryDir() as tmpdir: base_path = os.path.join(tmpdir, 'base.img') leaf_path = os.path.join(tmpdir, 'leaf.img') size = 1048576 leaf_fmt = qemuimg.FORMAT.QCOW2 with MonkeyPatchScope([(qemuimg, 'config', CONFIG)]): qemuimg.create(base_path, size=size, format=qemuimg.FORMAT.RAW) qemuimg.create(leaf_path, format=leaf_fmt, backing=base_path) info = qemuimg.info(leaf_path) self.assertEqual(leaf_fmt, info['format']) self.assertEqual(size, info['virtualsize']) self.assertEqual(self.CLUSTER_SIZE, info['clustersize']) self.assertEqual(base_path, info['backingfile']) self.assertEqual('0.10', info['compat'])
def make_volume(self, env, img_id, vol_id, parent_vol_id, vol_fmt): if parent_vol_id != sc.BLANK_UUID: vol_fmt = sc.COW_FORMAT env.make_volume(self.DEFAULT_SIZE, img_id, vol_id, parent_vol_id=parent_vol_id, vol_format=vol_fmt) vol = env.sd_manifest.produceVolume(img_id, vol_id) if vol_fmt == sc.COW_FORMAT: backing = parent_vol_id if parent_vol_id != sc.BLANK_UUID else None qemuimg.create(vol.volumePath, size=self.DEFAULT_SIZE, format=qemuimg.FORMAT.QCOW2, backing=backing) return vol
def _create(cls, dom, imgUUID, volUUID, size, volFormat, preallocate, volParent, srcImgUUID, srcVolUUID, volPath): """ Class specific implementation of volumeCreate. All the exceptions are properly handled and logged in volume.create() """ if preallocate == volume.SPARSE_VOL: volSize = "%s" % config.get("irs", "volume_utilization_chunk_mb") else: volSize = "%s" % ((size + SECTORS_TO_MB - 1) / SECTORS_TO_MB) lvm.createLV(dom.sdUUID, volUUID, volSize, activate=True, initialTag=TAG_VOL_UNINIT) utils.rmFile(volPath) os.symlink(lvm.lvPath(dom.sdUUID, volUUID), volPath) if not volParent: cls.log.info("Request to create %s volume %s with size = %s " "sectors", volume.type2name(volFormat), volPath, size) if volFormat == volume.COW_FORMAT: qemuimg.create( volPath, size * BLOCK_SIZE, volume.fmt2str(volFormat)) else: # Create hardlink to template and its meta file cls.log.info("Request to create snapshot %s/%s of volume %s/%s", imgUUID, volUUID, srcImgUUID, srcVolUUID) volParent.clone(volPath, volFormat) with cls._tagCreateLock: mdSlot = dom.getVolumeMetadataSlot(volUUID, VOLUME_MDNUMBLKS) mdTags = ["%s%s" % (TAG_PREFIX_MD, mdSlot), "%s%s" % (TAG_PREFIX_PARENT, srcVolUUID), "%s%s" % (TAG_PREFIX_IMAGE, imgUUID)] lvm.changeLVTags(dom.sdUUID, volUUID, delTags=[TAG_VOL_UNINIT], addTags=mdTags) try: lvm.deactivateLVs(dom.sdUUID, volUUID) except se.CannotDeactivateLogicalVolume: cls.log.warn("Cannot deactivate new created volume %s/%s", dom.sdUUID, volUUID, exc_info=True) return (dom.sdUUID, mdSlot)
def _create(cls, dom, imgUUID, volUUID, size, volFormat, preallocate, volParent, srcImgUUID, srcVolUUID, volPath, initialSize=None): """ Class specific implementation of volumeCreate. All the exceptions are properly handled and logged in volume.create() """ lvSize = cls.calculate_volume_alloc_size(preallocate, size, initialSize) lvm.createLV(dom.sdUUID, volUUID, "%s" % lvSize, activate=True, initialTags=(sc.TAG_VOL_UNINIT,)) fileutils.rm_file(volPath) os.symlink(lvm.lvPath(dom.sdUUID, volUUID), volPath) if not volParent: cls.log.info("Request to create %s volume %s with size = %s " "sectors", sc.type2name(volFormat), volPath, size) if volFormat == sc.COW_FORMAT: qemuimg.create(volPath, size=size * BLOCK_SIZE, format=sc.fmt2str(volFormat), qcow2Compat=dom.qcow2_compat()) else: # Create hardlink to template and its meta file cls.log.info("Request to create snapshot %s/%s of volume %s/%s", imgUUID, volUUID, srcImgUUID, srcVolUUID) volParent.clone(volPath, volFormat) with dom.acquireVolumeMetadataSlot( volUUID, sc.VOLUME_MDNUMBLKS) as slot: mdTags = ["%s%s" % (sc.TAG_PREFIX_MD, slot), "%s%s" % (sc.TAG_PREFIX_PARENT, srcVolUUID), "%s%s" % (sc.TAG_PREFIX_IMAGE, imgUUID)] lvm.changeLVTags(dom.sdUUID, volUUID, delTags=[sc.TAG_VOL_UNINIT], addTags=mdTags) try: lvm.deactivateLVs(dom.sdUUID, [volUUID]) except se.CannotDeactivateLogicalVolume: cls.log.warn("Cannot deactivate new created volume %s/%s", dom.sdUUID, volUUID, exc_info=True) return (dom.sdUUID, slot)
def _create(cls, dom, imgUUID, volUUID, size, volFormat, preallocate, volParent, srcImgUUID, srcVolUUID, volPath): """ Class specific implementation of volumeCreate. All the exceptions are properly handled and logged in volume.create() """ sizeBytes = size * BLOCK_SIZE truncSize = sizeBytes if volFormat == volume.RAW_FORMAT else 0 try: oop.getProcessPool(dom.sdUUID).truncateFile( volPath, truncSize, mode=VOLUME_PERMISSIONS, creatExcl=True) except OSError as e: if e.errno == errno.EEXIST: raise se.VolumeAlreadyExists(volUUID) raise if preallocate == volume.PREALLOCATED_VOL: try: # ddWatchCopy expects size to be in bytes misc.ddWatchCopy("/dev/zero", volPath, vars.task.aborting, sizeBytes) except ActionStopped: raise except Exception: cls.log.error("Unexpected error", exc_info=True) raise se.VolumesZeroingError(volPath) if not volParent: cls.log.info("Request to create %s volume %s with size = %s " "sectors", volume.type2name(volFormat), volPath, size) if volFormat == volume.COW_FORMAT: qemuimg.create(volPath, sizeBytes, volume.fmt2str(volFormat)) else: # Create hardlink to template and its meta file cls.log.info("Request to create snapshot %s/%s of volume %s/%s", imgUUID, volUUID, srcImgUUID, srcVolUUID) volParent.clone(volPath, volFormat) # Forcing the volume permissions in case one of the tools we use # (dd, qemu-img, etc.) will mistakenly change the file permissiosn. dom.oop.os.chmod(volPath, VOLUME_PERMISSIONS) return (volPath,)
def test_empty_image(self, qcow2_compat): with namedTemporaryDir() as tmpdir: size = 1048576 image = os.path.join(tmpdir, "base.img") qemuimg.create(image, size=size, format=self.FORMAT, qcow2Compat=qcow2_compat) expected = [ # single run - empty { "start": 0, "length": size, "data": False, "zero": True, }, ] self.check_map(qemuimg.map(image), expected)
def _create(cls, dom, imgUUID, volUUID, size, volFormat, preallocate, volParent, srcImgUUID, srcVolUUID, volPath, initialSize=None): """ Class specific implementation of volumeCreate. All the exceptions are properly handled and logged in volume.create() """ lvSize = cls.calculate_volume_alloc_size(preallocate, size, initialSize) lvm.createLV(dom.sdUUID, volUUID, "%s" % lvSize, activate=True, initialTags=(sc.TAG_VOL_UNINIT,)) utils.rmFile(volPath) os.symlink(lvm.lvPath(dom.sdUUID, volUUID), volPath) if not volParent: cls.log.info("Request to create %s volume %s with size = %s " "sectors", sc.type2name(volFormat), volPath, size) if volFormat == sc.COW_FORMAT: qemuimg.create( volPath, size * BLOCK_SIZE, sc.fmt2str(volFormat)) else: # Create hardlink to template and its meta file cls.log.info("Request to create snapshot %s/%s of volume %s/%s", imgUUID, volUUID, srcImgUUID, srcVolUUID) volParent.clone(volPath, volFormat) with dom.acquireVolumeMetadataSlot( volUUID, sc.VOLUME_MDNUMBLKS) as slot: mdTags = ["%s%s" % (sc.TAG_PREFIX_MD, slot), "%s%s" % (sc.TAG_PREFIX_PARENT, srcVolUUID), "%s%s" % (sc.TAG_PREFIX_IMAGE, imgUUID)] lvm.changeLVTags(dom.sdUUID, volUUID, delTags=[sc.TAG_VOL_UNINIT], addTags=mdTags) try: lvm.deactivateLVs(dom.sdUUID, [volUUID]) except se.CannotDeactivateLogicalVolume: cls.log.warn("Cannot deactivate new created volume %s/%s", dom.sdUUID, volUUID, exc_info=True) return (dom.sdUUID, slot)
def make_qemu_chain(env, size, base_vol_fmt, chain_len): vol_list = [] img_id = str(uuid.uuid4()) parent_vol_id = sc.BLANK_UUID vol_fmt = base_vol_fmt for i in range(chain_len): vol_id = str(uuid.uuid4()) if parent_vol_id != sc.BLANK_UUID: vol_fmt = sc.COW_FORMAT env.make_volume(size, img_id, vol_id, parent_vol_id=parent_vol_id, vol_format=vol_fmt) vol = env.sd_manifest.produceVolume(img_id, vol_id) if vol_fmt == sc.COW_FORMAT: backing = parent_vol_id if parent_vol_id != sc.BLANK_UUID else None qemuimg.create(vol.volumePath, size=size, format=qemuimg.FORMAT.QCOW2, backing=backing) vol_list.append(vol) parent_vol_id = vol_id return vol_list
def make_qemu_chain(env, size, base_vol_fmt, chain_len, qcow2_compat='0.10'): vol_list = [] img_id = make_uuid() parent_vol_id = sc.BLANK_UUID vol_fmt = base_vol_fmt for i in range(chain_len): vol_id = make_uuid() if parent_vol_id != sc.BLANK_UUID: vol_fmt = sc.COW_FORMAT vol_type = sc.LEAF_VOL if i == chain_len - 1 else sc.INTERNAL_VOL env.make_volume(size, img_id, vol_id, parent_vol_id=parent_vol_id, vol_format=vol_fmt, vol_type=vol_type) vol = env.sd_manifest.produceVolume(img_id, vol_id) if vol_fmt == sc.COW_FORMAT: backing = parent_vol_id if parent_vol_id != sc.BLANK_UUID else None qemuimg.create(vol.volumePath, size=size, format=qemuimg.FORMAT.QCOW2, qcow2Compat=qcow2_compat, backing=backing) vol_list.append(vol) parent_vol_id = vol_id return vol_list
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 _initialize_volume(self, vol_format, size): if vol_format == sc.COW_FORMAT: qemuimg.create(self.volume_path, size, sc.fmt2str(vol_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)
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_qcow2_compat_invalid(self): with self.assertRaises(ValueError): qemuimg.create('image', format='qcow2', qcow2Compat='1.11')