Пример #1
0
    def test_chain(self, tmpdir):
        base = str(tmpdir.join("base"))
        top = str(tmpdir.join("top"))
        dst = str(tmpdir.join("dst"))

        base_offset = 4 * 64 * 1024
        top_offset = 5 * 64 * 1024

        # Create base image with pattern.
        op = qemuimg.create(
            base, size=10 * 64 * 1024, format=qemuimg.FORMAT.RAW)
        op.run()
        qemuio.write_pattern(base, qemuimg.FORMAT.RAW, offset=base_offset)

        # Create top image with pattern.
        op = qemuimg.create(
            top, format=qemuimg.FORMAT.QCOW2, qcow2Compat="1.1", backing=base)
        op.run()
        qemuio.write_pattern(top, qemuimg.FORMAT.QCOW2, offset=top_offset)

        # Convert, collpasing top and base into dst.
        op = qemuimg.convert(
            top,
            dst,
            srcFormat=qemuimg.FORMAT.QCOW2,
            dstFormat=qemuimg.FORMAT.RAW,
            unordered_writes=True)
        op.run()

        # Verify patterns
        qemuio.verify_pattern(dst, qemuimg.FORMAT.RAW, offset=base_offset)
        qemuio.verify_pattern(dst, qemuimg.FORMAT.RAW, offset=top_offset)
Пример #2
0
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
Пример #3
0
 def test_unsafe_create_volume(self):
     with namedTemporaryDir() as tmpdir:
         path = os.path.join(tmpdir, 'test.qcow2')
         # Using unsafe=True to verify that it is possible to create an
         # image based on a non-existing backing file, like an inactive LV.
         qemuimg.create(path, size=1048576, format=qemuimg.FORMAT.QCOW2,
                        backing='no-such-file', unsafe=True)
Пример #4
0
 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']))
Пример #5
0
def vol_chain(tmp_mount):
    virtual_size = MiB

    # Create base volume
    base_vol = os.path.join(tmp_mount.path, 'base.img')
    op = qemuimg.create(
        base_vol,
        size=virtual_size,
        format=qemuimg.FORMAT.QCOW2,
        qcow2Compat='1.1'
    )
    op.run()

    # Create top volume
    top_vol = os.path.join(tmp_mount.path, 'top.img')
    op = qemuimg.create(
        top_vol,
        size=virtual_size,
        format=qemuimg.FORMAT.QCOW2,
        qcow2Compat='1.1',
        backing=base_vol,
        backingFormat='qcow2'
    )
    op.run()

    return Volumes(base_vol, top_vol)
Пример #6
0
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
Пример #7
0
 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)
Пример #8
0
 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)
Пример #9
0
def test_read_bad_chain_raises(tmpdir):
    # Create a good chain.
    base_qcow2 = str(tmpdir.join("base.qcow2"))
    op = qemuimg.create(base_qcow2, "1m", qemuimg.FORMAT.QCOW2)
    op.run()
    top = str(tmpdir.join("top.qcow2"))
    op = qemuimg.create(top,
                        "1m",
                        qemuimg.FORMAT.QCOW2,
                        backing=base_qcow2,
                        backingFormat=qemuimg.FORMAT.QCOW2)
    op.run()

    # Create a broken chain using unsafe rebase with the wrong backing
    # format.
    base_raw = str(tmpdir.join("base.raw"))
    op = qemuimg.create(base_raw, "1m", qemuimg.FORMAT.RAW)
    op.run()
    operation = qemuimg.rebase(top,
                               backing=base_raw,
                               format=qemuimg.FORMAT.QCOW2,
                               backingFormat=qemuimg.FORMAT.QCOW2,
                               unsafe=True)
    operation.run()
    with pytest.raises(cmdutils.Error):
        qemuio.verify_pattern(top, qemuimg.FORMAT.QCOW2)
Пример #10
0
 def test_unsafe_create_volume(self):
     with namedTemporaryDir() as tmpdir:
         path = os.path.join(tmpdir, 'test.qcow2')
         # Using unsafe=True to verify that it is possible to create an
         # image based on a non-existing backing file, like an inactive LV.
         qemuimg.create(path, size=1048576, format=qemuimg.FORMAT.QCOW2,
                        backing='no-such-file', unsafe=True)
Пример #11
0
    def test_chain(self, tmpdir):
        base = str(tmpdir.join("base"))
        top = str(tmpdir.join("top"))
        dst = str(tmpdir.join("dst"))

        base_offset = 4 * 64 * 1024
        top_offset = 5 * 64 * 1024

        # Create base image with pattern.
        op = qemuimg.create(
            base, size=10 * 64 * 1024, format=qemuimg.FORMAT.RAW)
        op.run()
        qemuio.write_pattern(base, qemuimg.FORMAT.RAW, offset=base_offset)

        # Create top image with pattern.
        op = qemuimg.create(
            top, format=qemuimg.FORMAT.QCOW2, qcow2Compat="1.1", backing=base)
        op.run()
        qemuio.write_pattern(top, qemuimg.FORMAT.QCOW2, offset=top_offset)

        # Convert, collpasing top and base into dst.
        op = qemuimg.convert(
            top,
            dst,
            srcFormat=qemuimg.FORMAT.QCOW2,
            dstFormat=qemuimg.FORMAT.RAW,
            unordered_writes=True)
        op.run()

        # Verify patterns
        qemuio.verify_pattern(dst, qemuimg.FORMAT.RAW, offset=base_offset)
        qemuio.verify_pattern(dst, qemuimg.FORMAT.RAW, offset=top_offset)
Пример #12
0
    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)
Пример #13
0
    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,)
Пример #14
0
def make_file_volume(sd_manifest,
                     size,
                     imguuid,
                     voluuid,
                     parent_vol_id=sc.BLANK_UUID,
                     vol_format=sc.RAW_FORMAT,
                     vol_type=sc.LEAF_VOL,
                     prealloc=sc.SPARSE_VOL,
                     disk_type=sc.DATA_DISKTYPE,
                     desc='fake volume',
                     qcow2_compat='0.10',
                     legal=True):
    volpath = os.path.join(sd_manifest.domaindir, "images", imguuid, voluuid)

    # Create needed path components.
    make_file(volpath, size)

    # Create the image.
    if vol_format == sc.COW_FORMAT:
        backing = parent_vol_id if parent_vol_id != sc.BLANK_UUID else None
        if backing:
            backing_path = os.path.join(sd_manifest.domaindir, "images",
                                        imguuid, backing)
            backing_format = qemuimg.info(backing_path)["format"]
        else:
            backing_format = None

        op = qemuimg.create(volpath,
                            size=size,
                            format=qemuimg.FORMAT.QCOW2,
                            qcow2Compat=qcow2_compat,
                            backing=backing,
                            backingFormat=backing_format)
        op.run()
    else:
        # TODO: Use fallocate helper like the real code.
        if prealloc == sc.PREALLOCATED_VOL:
            preallocation = qemuimg.PREALLOCATION.FALLOC
        else:
            preallocation = None
        op = qemuimg.create(volpath,
                            size=size,
                            format=qemuimg.FORMAT.RAW,
                            preallocation=preallocation)
        op.run()

    # Create meta files.
    mdfiles = [volpath + '.meta', volpath + '.lease']
    for mdfile in mdfiles:
        make_file(mdfile)

    vol_class = sd_manifest.getVolumeClass()
    vol_class.newMetadata((volpath, ),
                          sd_manifest.sdUUID, imguuid, parent_vol_id, size,
                          sc.type2name(vol_format), sc.type2name(prealloc),
                          sc.type2name(vol_type), disk_type, desc,
                          sc.LEGAL_VOL if legal else sc.ILLEGAL_VOL)
Пример #15
0
 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)
Пример #16
0
    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')
Пример #17
0
 def test_missing_backing_file(self):
     with fake_file_env() as env:
         vol = make_qemu_chain(env, self.SIZE, sc.COW_FORMAT, 2)[1]
         # Simulate upload of image without backing file to a a snapshot
         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)
Пример #18
0
    def test_qcow2_collapsed(self, user_mount, dst_compat, create):
        virtual_size = MiB
        # Create empty source chain.
        src_base = os.path.join(user_mount.path, 'src_base.img')
        op = qemuimg.create(
            src_base,
            size=virtual_size,
            format=qemuimg.FORMAT.QCOW2,
            qcow2Compat='1.1'
        )
        op.run()

        src_top = os.path.join(user_mount.path, 'src_top.img')
        op = qemuimg.create(
            src_top,
            size=virtual_size,
            format=qemuimg.FORMAT.QCOW2,
            qcow2Compat='1.1',
            backing=src_base,
            backingFormat='qcow2'
        )
        op.run()

        # Create destination image.
        dst = os.path.join(user_mount.path, 'dst.img')
        op = qemuimg.create(
            dst,
            size=virtual_size,
            format=qemuimg.FORMAT.QCOW2,
            qcow2Compat=dst_compat,
        )
        op.run()

        # Copy src chain to dst.
        op = qemuimg.convert(
            src_top,
            dst,
            srcFormat='qcow2',
            dstFormat='qcow2',
            dstQcow2Compat=dst_compat,
            create=create
        )
        op.run()

        # Since source is empty strict compare should work on both source
        # chain and destination.
        op = qemuimg.compare(
            src_top,
            dst,
            img1_format='qcow2',
            img2_format='qcow2',
            strict=True
        )
        op.run()
Пример #19
0
 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)
Пример #20
0
 def test_unexpected_backing_file(self):
     with self.fake_volume(sc.COW_FORMAT) as vol:
         # Simulate upload of qcow2 with backing file to base image
         qemuimg.create(vol.volumePath,
                        size=self.SIZE,
                        format=qemuimg.FORMAT.QCOW2,
                        backing='unexpected')
         h = FakeHSM()
         self.assertRaises(se.ImageVerificationError,
                           h.verify_untrusted_volume, 'sp', vol.sdUUID,
                           vol.imgUUID, vol.volUUID)
Пример #21
0
 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.assertEqual(
             qemuimg.info(leaf_path)['compat'], desired_qcow2_compat)
Пример #22
0
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)
Пример #23
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)
Пример #24
0
 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)
Пример #25
0
 def test_empty_image(self, monkeypatch, qcow2_compat, desired_compat):
     monkeypatch.setattr(qemuimg, 'config', CONFIG)
     with namedTemporaryDir() as tmpdir:
         base_path = os.path.join(tmpdir, 'base.img')
         leaf_path = os.path.join(tmpdir, 'leaf.img')
         size = 1048576
         op_base = qemuimg.create(base_path, size=size,
                                  format=qemuimg.FORMAT.RAW)
         op_base.run()
         op_leaf = qemuimg.create(leaf_path, format=qemuimg.FORMAT.QCOW2,
                                  backing=base_path)
         op_leaf.run()
         qemuimg.amend(leaf_path, desired_compat)
         assert qemuimg.info(leaf_path)['compat'] == desired_compat
Пример #26
0
 def test_empty_image(self, monkeypatch, qcow2_compat, desired_compat):
     monkeypatch.setattr(qemuimg, 'config', CONFIG)
     with namedTemporaryDir() as tmpdir:
         base_path = os.path.join(tmpdir, 'base.img')
         leaf_path = os.path.join(tmpdir, 'leaf.img')
         size = 1048576
         op_base = qemuimg.create(base_path, size=size,
                                  format=qemuimg.FORMAT.RAW)
         op_base.run()
         op_leaf = qemuimg.create(leaf_path, format=qemuimg.FORMAT.QCOW2,
                                  backing=base_path)
         op_leaf.run()
         qemuimg.amend(leaf_path, desired_compat)
         assert qemuimg.info(leaf_path)['compat'] == desired_compat
Пример #27
0
    def test_qcow2_to_compressed_qcow2(self, tmpdir):
        src_file = str(tmpdir.join("test_src.qcow2"))
        dst_file = str(tmpdir.join("test_dst.qcow2"))

        op = qemuimg.create(
            src_file,
            size=1 * GIB,
            format=qemuimg.FORMAT.QCOW2)
        op.run()
        qemuio.write_pattern(
            src_file,
            qemuimg.FORMAT.QCOW2,
            len=1 * MEGAB,
            pattern=0xf0)

        src_file_size = qemuimg.info(src_file)["actualsize"]
        op = qemuimg.convert(
            src_file,
            dst_file,
            srcFormat=qemuimg.FORMAT.QCOW2,
            dstFormat=qemuimg.FORMAT.QCOW2,
            compressed=True)
        op.run()
        dst_file_size = qemuimg.info(dst_file)["actualsize"]

        assert src_file_size > dst_file_size
Пример #28
0
def test_no_match(tmpdir, image_format):
    path = str(tmpdir.join('test.' + image_format))
    op = qemuimg.create(path, '1m', image_format)
    op.run()
    qemuio.write_pattern(path, image_format, pattern=2)
    with pytest.raises(qemuio.VerificationError):
        qemuio.verify_pattern(path, image_format, pattern=4)
Пример #29
0
def test_no_match(tmpdir, image_format):
    path = str(tmpdir.join('test.' + image_format))
    op = qemuimg.create(path, '1m', image_format)
    op.run()
    qemuio.write_pattern(path, image_format, pattern=2)
    with pytest.raises(qemuio.VerificationError):
        qemuio.verify_pattern(path, image_format, pattern=4)
Пример #30
0
    def _create_cow_volume(
            cls, dom, vol_id, capacity, vol_path, initial_size, vol_parent,
            img_id, src_img_id, src_vol_id):
        """
        specific implementation of _create() for COW volumes.
        All the exceptions are properly handled and logged in volume.create()
        """
        if initial_size:
            cls.log.error("initial size is not supported "
                          "for file-based volumes")
            raise se.InvalidParameterException("initial size", initial_size)

        cls._truncate_volume(vol_path, 0, vol_id, dom)

        if not vol_parent:
            cls.log.info("Request to create COW volume %s with capacity = %s",
                         vol_path, capacity)

            operation = qemuimg.create(vol_path,
                                       size=capacity,
                                       format=sc.fmt2str(sc.COW_FORMAT),
                                       qcow2Compat=dom.qcow2_compat())
            operation.run()
        else:
            # Create hardlink to template and its meta file
            cls.log.info("Request to create snapshot %s/%s of volume %s/%s "
                         "with capacity %s",
                         img_id, vol_id, src_img_id, src_vol_id, capacity)
            vol_parent.clone(vol_path, sc.COW_FORMAT, capacity)

        # Forcing the volume permissions in case one of the tools we use
        # (dd, qemu-img, etc.) will mistakenly change the file permissions.
        cls._set_permissions(vol_path, dom)

        return (vol_path,)
Пример #31
0
    def _allocate_volume(cls, vol_path, size, preallocate):
        try:
            # Always create sparse image, since qemu-img create uses
            # posix_fallocate() which is inefficient and harmful.
            op = qemuimg.create(vol_path, size=size, format=qemuimg.FORMAT.RAW)

            # This is fast but it can get stuck if storage is inaccessible.
            with vars.task.abort_callback(op.abort):
                with utils.stopwatch("Creating image {}".format(vol_path),
                                     level=logging.INFO,
                                     log=cls.log):
                    op.run()

            # If the image is preallocated, allocate the rest of the image
            # using fallocate helper. qemu-img create always writes zeroes to
            # the first block so we should skip it during preallocation.
            if preallocate == sc.PREALLOCATED_VOL:
                op = fallocate.allocate(vol_path, size - 4096, offset=4096)

                # This is fast on NFS 4.2, GlusterFS, XFS and ext4, but can be
                # extremely slow on NFS < 4.2, writing zeroes to entire image.
                with vars.task.abort_callback(op.abort):
                    with utils.stopwatch(
                            "Preallocating volume {}".format(vol_path),
                            level=logging.INFO,
                            log=cls.log):
                        op.run()
        except exception.ActionStopped:
            raise
        except Exception:
            cls.log.error("Unexpected error", exc_info=True)
            raise se.VolumesZeroingError(vol_path)
Пример #32
0
    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'])
Пример #33
0
def test_open_write_mode(tmpdir, fmt):
    image = str(tmpdir.join("disk." + fmt))
    op = qemuimg.create(image, "1m", fmt)
    op.run()
    with qemuio.open(image, fmt):
        with pytest.raises(cmdutils.Error):
            qemuimg.info(image, fmt)
Пример #34
0
def test_skip_holes_during_merge_bitmaps(tmp_mount, vol_chain):
    virtual_size = MiB
    bitmap = 'bitmap'

    # Create base parent volume
    base_parent_vol = os.path.join(tmp_mount.path, 'base_parent.img')
    op = qemuimg.create(
        base_parent_vol,
        size=virtual_size,
        format=qemuimg.FORMAT.QCOW2,
        qcow2Compat='1.1'
    )
    op.run()

    # Rebase the volume chain on top of base parent volume
    op = qemuimg.rebase(
        vol_chain.base_vol, base_parent_vol, unsafe=True)
    op.run()

    # Add new bitmap to base parent volume
    op = qemuimg.bitmap_add(base_parent_vol, bitmap)
    op.run()
    # Add new bitmap to top volume, base volume is missing that
    # bitmap so there is a hole
    op = qemuimg.bitmap_add(vol_chain.top_vol, bitmap)
    op.run()

    bitmaps.merge_bitmaps(
        vol_chain.base_vol, vol_chain.top_vol,
        base_parent_path=base_parent_vol)

    info = qemuimg.info(vol_chain.base_vol)
    assert 'bitmaps' not in info
Пример #35
0
    def test_qcow2_to_compressed_qcow2(self, tmpdir):
        src_file = str(tmpdir.join("test_src.qcow2"))
        dst_file = str(tmpdir.join("test_dst.qcow2"))

        op = qemuimg.create(
            src_file,
            size=1 * GIB,
            format=qemuimg.FORMAT.QCOW2)
        op.run()
        qemuio.write_pattern(
            src_file,
            qemuimg.FORMAT.QCOW2,
            len=1 * MEGAB,
            pattern=0xf0)

        src_file_size = qemuimg.info(src_file)["actualsize"]
        op = qemuimg.convert(
            src_file,
            dst_file,
            srcFormat=qemuimg.FORMAT.QCOW2,
            dstFormat=qemuimg.FORMAT.QCOW2,
            compressed=True)
        op.run()
        dst_file_size = qemuimg.info(dst_file)["actualsize"]

        assert src_file_size > dst_file_size
Пример #36
0
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)
    op = qemuimg.create(vol.getVolumePath(), size, qemu_formats[real_fmt])
    op.run()
    return vol
Пример #37
0
 def test_untrusted_image(self):
     with namedTemporaryDir() as tmpdir:
         img = os.path.join(tmpdir, 'untrusted.img')
         size = 500 * 1024**3
         op = qemuimg.create(img, size=size, format=qemuimg.FORMAT.QCOW2)
         op.run()
         info = qemuimg.info(img, trusted_image=False)
         assert size == info['virtualsize']
Пример #38
0
 def test_unsafe_info(self, unsafe):
     with namedTemporaryDir() as tmpdir:
         img = os.path.join(tmpdir, 'img.img')
         size = 1048576
         op = qemuimg.create(img, size=size, format=qemuimg.FORMAT.QCOW2)
         op.run()
         info = qemuimg.info(img, unsafe=unsafe)
         assert size == info['virtualsize']
Пример #39
0
    def test_zero_size(self):
        with namedTemporaryDir() as tmpdir:
            image = os.path.join(tmpdir, "image")
            op = qemuimg.create(image, size=0)
            op.run()

            info = qemuimg.info(image)
            assert info['format'] == qemuimg.FORMAT.RAW
            assert info['virtualsize'] == 0
Пример #40
0
 def test_ok(self, vol_fmt):
     with self.fake_volume(vol_fmt) as vol:
         qemu_fmt = sc.FMT2STR[vol_fmt]
         op = qemuimg.create(vol.volumePath, size=self.SIZE,
                             format=qemu_fmt)
         op.run()
         h = FakeHSM()
         h.verify_untrusted_volume(
             'sp', vol.sdUUID, vol.imgUUID, vol.volUUID)
Пример #41
0
 def test_wrong_format_raises(self, vol_fmt, qemu_fmt):
     with self.fake_volume(vol_fmt) as vol:
         op = qemuimg.create(vol.volumePath, size=self.SIZE,
                             format=qemu_fmt)
         op.run()
         h = FakeHSM()
         with pytest.raises(se.ImageVerificationError):
             h.verify_untrusted_volume(
                 'sp', vol.sdUUID, vol.imgUUID, vol.volUUID)
Пример #42
0
def make_block_volume(lvm, sd_manifest, size, imguuid, voluuid,
                      parent_vol_id=sc.BLANK_UUID,
                      vol_format=sc.RAW_FORMAT,
                      vol_type=sc.LEAF_VOL,
                      prealloc=sc.PREALLOCATED_VOL,
                      disk_type=sc.DATA_DISKTYPE,
                      desc='fake volume', qcow2_compat='0.10'):
    sduuid = sd_manifest.sdUUID
    imagedir = sd_manifest.getImageDir(imguuid)
    if not os.path.exists(imagedir):
        os.makedirs(imagedir)

    size_blk = (size + sc.BLOCK_SIZE - 1) // sc.BLOCK_SIZE
    lv_size = sd_manifest.getVolumeClass().calculate_volume_alloc_size(
        prealloc, size_blk, None)
    lvm.createLV(sduuid, voluuid, lv_size)
    # LVM may create the volume with a larger size due to extent granularity
    lv_size_blk = int(lvm.getLV(sduuid, voluuid).size) // sc.BLOCK_SIZE
    if lv_size_blk > size_blk:
        size_blk = lv_size_blk

    if vol_format == sc.COW_FORMAT:
        volpath = lvm.lvPath(sduuid, voluuid)
        backing = parent_vol_id if parent_vol_id != sc.BLANK_UUID else None

        # Write qcow2 image to the fake block device - truncating the file.
        op = qemuimg.create(
            volpath,
            size=size,
            format=qemuimg.FORMAT.QCOW2,
            qcow2Compat=qcow2_compat,
            backing=backing)
        op.run()

        # Truncate fake block device back ot the proper size.
        with open(volpath, "r+") as f:
            f.truncate(int(lvm.getLV(sduuid, voluuid).size))

    with sd_manifest.acquireVolumeMetadataSlot(voluuid) as slot:
        lvm.addtag(sduuid, voluuid, "%s%s" % (sc.TAG_PREFIX_MD, slot))
        lvm.addtag(sduuid, voluuid, "%s%s" % (sc.TAG_PREFIX_PARENT,
                                              parent_vol_id))
        lvm.addtag(sduuid, voluuid, "%s%s" % (sc.TAG_PREFIX_IMAGE, imguuid))

    vol_class = sd_manifest.getVolumeClass()
    vol_class.newMetadata(
        (sduuid, slot),
        sduuid,
        imguuid,
        parent_vol_id,
        size_blk,
        sc.type2name(vol_format),
        sc.type2name(prealloc),
        sc.type2name(vol_type),
        disk_type,
        desc,
        sc.LEGAL_VOL)
Пример #43
0
 def test_allocate(self, image_format, allocation_mode, allocated_bytes):
     size = 16 * 1024 * 1024
     with temporaryPath() as image:
         op = qemuimg.create(image,
                             size=size,
                             format=image_format,
                             preallocation=allocation_mode)
         op.run()
         allocated = os.stat(image).st_blocks * 512
         assert allocated == allocated_bytes
Пример #44
0
 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)
Пример #45
0
 def test_unexpected_backing_file(self):
     with self.fake_volume(sc.COW_FORMAT) as vol:
         # Simulate upload of qcow2 with backing file to base image
         op = qemuimg.create(vol.volumePath, size=self.SIZE,
                             format=qemuimg.FORMAT.QCOW2,
                             backing='unexpected')
         op.run()
         h = FakeHSM()
         with pytest.raises(se.ImageVerificationError):
             h.verify_untrusted_volume(
                 'sp', vol.sdUUID, vol.imgUUID, vol.volUUID)
Пример #46
0
 def test_missing_backing_file(self):
     with fake_file_env() as env:
         vol = make_qemu_chain(env, self.SIZE, sc.COW_FORMAT, 2)[1]
         # Simulate upload of image without backing file to a a snapshot
         op = qemuimg.create(vol.volumePath, size=self.SIZE,
                             format=qemuimg.FORMAT.QCOW2)
         op.run()
         h = FakeHSM()
         with pytest.raises(se.ImageVerificationError):
             h.verify_untrusted_volume(
                 'sp', vol.sdUUID, vol.imgUUID, vol.volUUID)
Пример #47
0
    def test_qcow2_compat(self):
        with namedTemporaryDir() as tmpdir:
            image = os.path.join(tmpdir, "image")
            size = 1024 * 1024 * 1024 * 10  # 10 GB
            op = qemuimg.create(image, format='qcow2', size=size)
            op.run()

            info = qemuimg.info(image)
            assert info['format'] == qemuimg.FORMAT.QCOW2
            assert info['compat'] == "0.10"
            assert info['virtualsize'] == size
Пример #48
0
 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)])
         with MonkeyPatchScope([(qemuimg, 'config', create_conf)]):
             op = qemuimg.create(vol.volumePath, size=self.SIZE,
                                 format=qemuimg.FORMAT.QCOW2,
                                 qcow2Compat=hsm_compat)
             op.run()
             h = FakeHSM()
             h.verify_untrusted_volume(
                 'sp', vol.sdUUID, vol.imgUUID, vol.volUUID)
Пример #49
0
def make_image(path, size, format, index, qcow2_compat, backing=None):
    op = qemuimg.create(path, size=size, format=format,
                        qcow2Compat=qcow2_compat,
                        backing=backing)
    op.run()
    offset = index * 1024
    qemuio.write_pattern(
        path,
        format,
        offset=offset,
        len=1024,
        pattern=0xf0 + index)
Пример #50
0
 def test_smaller_size_ok(self, vol_fmt, qemu_fmt):
     # Engine < 4.2.6 rounds disk size to a multiple of 1G, creating disks
     # with incorrect virtual size. To be compatible with old engines we
     # cannot fail verification in this case.
     with self.fake_volume(vol_fmt) as vol:
         op = qemuimg.create(
             vol.volumePath,
             size=self.SIZE - sc.BLOCK_SIZE,
             format=qemu_fmt)
         op.run()
         h = FakeHSM()
         h.verify_untrusted_volume(
             'sp', vol.sdUUID, vol.imgUUID, vol.volUUID)
Пример #51
0
    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)]):
                op = qemuimg.create(base_path,
                                    size=size,
                                    format=qemuimg.FORMAT.RAW)
                op.run()
                op = qemuimg.create(leaf_path,
                                    format=leaf_fmt,
                                    backing=base_path)
                op.run()

            info = qemuimg.info(leaf_path)
            assert leaf_fmt == info['format']
            assert size == info['virtualsize']
            assert self.CLUSTER_SIZE == info['clustersize']
            assert base_path == info['backingfile']
            assert '0.10' == info['compat']
Пример #52
0
 def create_image(self, img_path, img_format):
     if img_format == 'raw':
         with open(img_path, 'w') as f:
             f.truncate(VIRTUAL_SIZE)
     elif img_format == 'cow':
         op = qemuimg.create(
             img_path,
             size=VIRTUAL_SIZE,
             format=qemuimg.FORMAT.QCOW2,
             qcow2Compat=QCOW2_COMPAT)
         op.run()
     else:
         raise AssertionError("invalid format: %s" % img_format)
Пример #53
0
    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, lvSize, activate=True,
                     initialTags=(sc.TAG_VOL_UNINIT,))

        fileutils.rm_file(volPath)
        lvPath = lvm.lvPath(dom.sdUUID, volUUID)
        cls.log.info("Creating volume symlink from %r to %r", lvPath, volPath)
        os.symlink(lvPath, volPath)

        if not volParent:
            cls.log.info("Request to create %s volume %s with size = %s "
                         "blocks", sc.type2name(volFormat), volPath,
                         size)
            if volFormat == sc.COW_FORMAT:
                operation = qemuimg.create(volPath,
                                           size=size * BLOCK_SIZE,
                                           format=sc.fmt2str(volFormat),
                                           qcow2Compat=dom.qcow2_compat())
                operation.run()
        else:
            # Create hardlink to template and its meta file
            cls.log.info("Request to create snapshot %s/%s of volume %s/%s "
                         "with size %s (blocks)",
                         imgUUID, volUUID, srcImgUUID, srcVolUUID, size)
            volParent.clone(volPath, volFormat, size)

        with dom.acquireVolumeMetadataSlot(volUUID) 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)
Пример #54
0
def test_read_bad_chain_raises(tmpdir):
    # Create a good chain.
    base_qcow2 = str(tmpdir.join("base.qcow2"))
    op = qemuimg.create(base_qcow2, "1m", qemuimg.FORMAT.QCOW2)
    op.run()
    top = str(tmpdir.join("top.qcow2"))
    op = qemuimg.create(top, "1m", qemuimg.FORMAT.QCOW2,
                        backing=base_qcow2,
                        backingFormat=qemuimg.FORMAT.QCOW2)
    op.run()

    # Create a broken chain using unsafe rebase with the wrong backing
    # format.
    base_raw = str(tmpdir.join("base.raw"))
    op = qemuimg.create(base_raw, "1m", qemuimg.FORMAT.RAW)
    op.run()
    operation = qemuimg.rebase(top,
                               backing=base_raw,
                               format=qemuimg.FORMAT.QCOW2,
                               backingFormat=qemuimg.FORMAT.QCOW2,
                               unsafe=True)
    operation.run()
    with pytest.raises(cmdutils.Error):
        qemuio.verify_pattern(top, qemuimg.FORMAT.QCOW2)
Пример #55
0
    def test_qcow2_to_raw(self, preallocation, virtual_size, actual_size):
        with namedTemporaryDir() as tmpdir:
            src = os.path.join(tmpdir, 'src')
            dst = os.path.join(tmpdir, 'dst')

            op = qemuimg.create(src, size=virtual_size, format="qcow2")
            op.run()

            op = qemuimg.convert(src, dst, srcFormat="qcow2", dstFormat="raw",
                                 preallocation=preallocation)
            op.run()

            stat = os.stat(dst)
            assert stat.st_size == virtual_size
            assert stat.st_blocks * 512 == actual_size
Пример #56
0
    def test_raw_to_qcow2_metadata_prealloc(self):
        virtual_size = 10 * 1024**2
        with namedTemporaryDir() as tmpdir:
            src = os.path.join(tmpdir, 'src')
            dst = os.path.join(tmpdir, 'dst')

            op = qemuimg.create(src, size=virtual_size, format="raw")
            op.run()

            op = qemuimg.convert(src, dst, srcFormat="raw", dstFormat="qcow2",
                                 preallocation=qemuimg.PREALLOCATION.METADATA)
            op.run()

            actual_size = os.stat(dst).st_size
            disk_size = qemuimg.info(dst, format="qcow2")["actualsize"]

            assert actual_size > virtual_size
            assert disk_size < virtual_size
Пример #57
0
    def test_single(self, tmpdir, format):
        src = str(tmpdir.join("src"))
        dst = str(tmpdir.join("dst"))
        offset = 4 * 64 * 1024

        op = qemuimg.create(
            src, size=10 * 64 * 1024, format=format, qcow2Compat="1.1")
        op.run()
        qemuio.write_pattern(src, format, offset=offset)

        op = qemuimg.convert(
            src,
            dst,
            srcFormat=format,
            dstFormat=qemuimg.FORMAT.RAW,
            unordered_writes=True)
        op.run()

        qemuio.verify_pattern(dst, qemuimg.FORMAT.RAW, offset=offset)
Пример #58
0
    def test_empty_image(self, qcow2_compat):
        with namedTemporaryDir() as tmpdir:
            size = 1048576
            image = os.path.join(tmpdir, "base.img")
            op = qemuimg.create(image, size=size, format=self.FORMAT,
                                qcow2Compat=qcow2_compat)
            op.run()

            expected = [
                # single run - empty
                {
                    "start": 0,
                    "length": size,
                    "data": False,
                    "zero": True,
                },
            ]

            self.check_map(qemuimg.map(image), expected)
Пример #59
0
def make_file_volume(sd_manifest, size, imguuid, voluuid,
                     parent_vol_id=sc.BLANK_UUID,
                     vol_format=sc.RAW_FORMAT,
                     vol_type=sc.LEAF_VOL,
                     prealloc=sc.SPARSE_VOL,
                     disk_type=sc.DATA_DISKTYPE,
                     desc='fake volume', qcow2_compat='0.10'):
    volpath = os.path.join(sd_manifest.domaindir, "images", imguuid, voluuid)

    # Create needed path components.
    make_file(volpath, size)

    # Create qcow2 file if needed.
    if vol_format == sc.COW_FORMAT:
        backing = parent_vol_id if parent_vol_id != sc.BLANK_UUID else None
        op = qemuimg.create(
            volpath,
            size=size,
            format=qemuimg.FORMAT.QCOW2,
            qcow2Compat=qcow2_compat,
            backing=backing)
        op.run()

    # Create meta files.
    mdfiles = [volpath + '.meta', volpath + '.lease']
    for mdfile in mdfiles:
        make_file(mdfile)

    size_blk = size // sc.BLOCK_SIZE
    vol_class = sd_manifest.getVolumeClass()
    vol_class.newMetadata(
        (volpath,),
        sd_manifest.sdUUID,
        imguuid,
        parent_vol_id,
        size_blk,
        sc.type2name(vol_format),
        sc.type2name(prealloc),
        sc.type2name(vol_type),
        disk_type,
        desc,
        sc.LEGAL_VOL)
Пример #60
0
    def test_one_block(self, offset, length, expected_length, qcow2_compat):
        with namedTemporaryDir() as tmpdir:
            size = 1048576
            image = os.path.join(tmpdir, "base.img")
            op = qemuimg.create(image, size=size, format=self.FORMAT,
                                qcow2Compat=qcow2_compat)
            op.run()

            qemuio.write_pattern(
                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)