def test_parse_error(self): def call(cmd, **kw): out = b"image: leaf.img\ninvalid file format line" return 0, out, "" with MonkeyPatchScope([(commands, "execCmd", call)]): with pytest.raises(cmdutils.Error): qemuimg.check('unused')
def test_optimal_size_cow_leaf_empty(self): # verify optimal size equals to actual size + one chunk. with self.make_volume(size=GIB, format=sc.COW_FORMAT) as vol: chunk_size = 1024 * constants.MEGAB check = qemuimg.check(vol.getVolumePath(), qemuimg.FORMAT.QCOW2) actual_size = check['offset'] + chunk_size self.assertEqual(vol.optimal_size(), actual_size)
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 test_check(self): with namedTemporaryDir() as tmpdir: path = os.path.join(tmpdir, 'test.qcow2') op = qemuimg.create(path, size=MiB, format=qemuimg.FORMAT.QCOW2) op.run() info = qemuimg.check(path) # The exact value depends on qcow2 internals assert isinstance(info['offset'], int)
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) op.run() 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. qemuio.verify_pattern( 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"] assert actual_offset == orig_offset
def test_check(self): with namedTemporaryDir() as tmpdir: path = os.path.join(tmpdir, 'test.qcow2') op = qemuimg.create(path, size=1048576, format=qemuimg.FORMAT.QCOW2) op.run() info = qemuimg.check(path) # The exact value depends on qcow2 internals assert isinstance(info['offset'], int)
def test_optimal_size_cow_leaf_max(self): # Optimal size is limited to maximum size. size = 512 * MiB with self.make_volume(size=size, format=sc.COW_FORMAT) as vol: max_size = vol.max_size(size, vol.getFormat()) self.assertEqual(vol.optimal_size(), max_size) check = qemuimg.check(vol.getVolumePath(), qemuimg.FORMAT.QCOW2) self.assertEqual( vol.optimal_cow_size(check["offset"], 512 * MiB, vol.isLeaf()), max_size)
def test_optimal_size_cow_leaf(self): # Optimal size calculated using actual size and chunk size. with self.make_volume(size=2 * GiB, format=sc.COW_FORMAT) as vol: chunk_size = GiB check = qemuimg.check(vol.getVolumePath(), qemuimg.FORMAT.QCOW2) optimal_size = utils.round(check['offset'] + chunk_size, vol.align_size) self.assertEqual(vol.optimal_size(), optimal_size) self.assertEqual( vol.optimal_cow_size(check["offset"], 2 * GiB, vol.isLeaf()), optimal_size)
def optimal_size(self): """ Return the optimal size of the volume. Returns: optimal size is the minimum of the volume maximum size and the volume actual size plus padding. For leaf volumes, the padding is one chunk, and for internal volumes the padding is `MIN_PADDING`. Size is returned in bytes. Note: the volume must be prepared when calling this helper. """ if self.getFormat() == sc.RAW_FORMAT: virtual_size = self.getSize() * sc.BLOCK_SIZE self.log.debug("RAW format, using virtual size: %s", virtual_size) return virtual_size # Read actual size. check = qemuimg.check(self.getVolumePath(), qemuimg.FORMAT.QCOW2) actual_size = check['offset'] # Add padding. if self.isLeaf(): # For leaf volumes, the padding is one chunk. chnuk_size_mb = int(config.get("irs", "volume_utilization_chunk_mb")) padding = chnuk_size_mb * constants.MEGAB self.log.debug("Leaf volume, using padding: %s", padding) potential_optimal_size = actual_size + padding else: # For internal volumes, using minimal padding. padding = MIN_PADDING self.log.debug("Internal volume, using padding: %s", padding) potential_optimal_size = actual_size + padding # Limit optimal size to the minimal volume size. potential_optimal_size = max(sc.MIN_CHUNK, potential_optimal_size) # Limit optimal size by maximum size. max_size = self.max_size(self.getSize() * sc.BLOCK_SIZE, self.getFormat()) optimal_size = min(potential_optimal_size, max_size) self.log.debug("COW format, actual_size: %s, max_size: %s, " "optimal_size: %s", actual_size, max_size, optimal_size) return optimal_size
def optimal_size(self, as_leaf=False): """ Return the optimal size of the volume, based on actual allocation. If as_leaf is True, calculate the optimal size as if this volume is a leaf. This is used when calculating the optimal size for the base volume after a merge, before the top volume is deleted and the base volume becomes the leaf. NOTE: The volume must be prepared so we can check the actual allocation. """ if self.getFormat() == sc.RAW_FORMAT: virtual_size = self.getCapacity() self.log.debug("RAW format, using virtual size: %s", virtual_size) return virtual_size else: check = qemuimg.check(self.getVolumePath(), qemuimg.FORMAT.QCOW2) return self.optimal_cow_size(check['offset'], self.getCapacity(), self.isLeaf() or as_leaf)
def test_offset_no_match(self): with MonkeyPatchScope([(commands, "execCmd", partial(fake_json_call, {}))]): with pytest.raises(cmdutils.Error): qemuimg.check('unused')