Пример #1
0
def test_roundtrip(nbd_env, format, allocation, discard):
    # Volume served by qemu-nd.
    img_id = str(uuid.uuid4())
    vol_id = str(uuid.uuid4())
    nbd_env.make_volume(
        nbd_env.virtual_size,
        img_id,
        vol_id,
        vol_format=format,
        prealloc=allocation)

    # Server configuration.
    config = {
        "sd_id": nbd_env.sd_manifest.sdUUID,
        "img_id": img_id,
        "vol_id": vol_id,
        "discard": discard,
    }

    with nbd_server(config) as nbd_url:
        # Copy data from source to NBD server, and from NBD server to dst.
        # Both files should match byte for byte after the operation.
        op = qemuimg.convert(
            nbd_env.src, nbd_url, srcFormat="raw", create=False)
        op.run()
        op = qemuimg.convert(nbd_url, nbd_env.dst, dstFormat="raw")
        op.run()

    with io.open(nbd_env.src) as s, io.open(nbd_env.dst) as d:
        assert s.read() == d.read()

    # Now the server should not be accessible.
    with pytest.raises(cmdutils.Error):
        qemuimg.info(nbd_url)
Пример #2
0
def test_roundtrip(nbd_env, format, allocation, discard):
    # Volume served by qemu-nd.
    img_id = str(uuid.uuid4())
    vol_id = str(uuid.uuid4())
    nbd_env.make_volume(nbd_env.virtual_size,
                        img_id,
                        vol_id,
                        vol_format=format,
                        prealloc=allocation)

    # Server configuration.
    config = {
        "sd_id": nbd_env.sd_manifest.sdUUID,
        "img_id": img_id,
        "vol_id": vol_id,
        "discard": discard,
    }

    with nbd_server(config) as nbd_url:
        # Copy data from source to NBD server, and from NBD server to dst.
        # Both files should match byte for byte after the operation.
        op = qemuimg.convert(nbd_env.src,
                             nbd_url,
                             srcFormat="raw",
                             create=False)
        op.run()
        op = qemuimg.convert(nbd_url, nbd_env.dst, dstFormat="raw")
        op.run()

    with io.open(nbd_env.src) as s, io.open(nbd_env.dst) as d:
        assert s.read() == d.read()

    # Now the server should not be accessible.
    with pytest.raises(cmdutils.Error):
        qemuimg.info(nbd_url)
Пример #3
0
    def test_no_create(self):
        def convert(cmd, **kw):
            expected = [QEMU_IMG, 'convert', '-p', '-t', 'none', '-T', 'none',
                        '-n', 'src', 'dst']
            assert cmd == expected

        with MonkeyPatchScope([(qemuimg, 'ProgressCommand', convert)]):
            qemuimg.convert('src', 'dst', create=False)
Пример #4
0
 def test_qcow2_compat_invalid(self):
     with self.assertRaises(ValueError):
         qemuimg.convert('image',
                         'dst',
                         dstFormat='qcow2',
                         backing='bak',
                         backingFormat='qcow2',
                         dstQcow2Compat='1.11')
Пример #5
0
    def test_no_create(self):
        def convert(cmd, **kw):
            expected = [QEMU_IMG, 'convert', '-p', '-t', 'none', '-T', 'none',
                        '-n', 'src', 'dst']
            assert cmd == expected

        with MonkeyPatchScope([(qemuimg, 'ProgressCommand', convert)]):
            qemuimg.convert('src', 'dst', create=False)
Пример #6
0
    def test_qcow2_no_backing_file(self):
        def convert(cmd, **kw):
            expected = [QEMU_IMG, 'convert', '-p', '-t', 'none', '-T', 'none',
                        'src', '-O', 'qcow2', '-o', 'compat=0.10', 'dst']
            assert cmd == expected

        with MonkeyPatchScope([(qemuimg, 'config', CONFIG),
                               (qemuimg, 'ProgressCommand', convert)]):
            qemuimg.convert('src', 'dst', dstFormat='qcow2')
Пример #7
0
    def test_qcow2_no_backing_file(self):
        def convert(cmd, **kw):
            expected = [QEMU_IMG, 'convert', '-p', '-t', 'none', '-T', 'none',
                        'src', '-O', 'qcow2', '-o', 'compat=0.10', 'dst']
            assert cmd == expected

        with MonkeyPatchScope([(qemuimg, 'config', CONFIG),
                               (qemuimg, 'ProgressCommand', convert)]):
            qemuimg.convert('src', 'dst', dstFormat='qcow2')
Пример #8
0
    def test_no_format(self):
        def convert(cmd, **kw):
            expected = [
                QEMU_IMG, 'convert', '-p', '-t', 'none', '-T', 'none', 'src',
                'dst'
            ]
            self.assertEqual(cmd, expected)

        with MonkeyPatchScope([(qemuimg, 'ProgressCommand', convert)]):
            qemuimg.convert('src', 'dst')
Пример #9
0
    def test_qcow2_compat_version3(self):
        def convert(cmd, **kw):
            expected = [
                QEMU_IMG, 'convert', '-p', '-t', 'none', '-T', 'none', 'src',
                '-O', 'qcow2', '-o', 'compat=1.1', 'dst'
            ]
            self.assertEqual(cmd, expected)

        with MonkeyPatchScope([(qemuimg, 'config', CONFIG),
                               (qemuimg, 'ProgressCommand', convert)]):
            qemuimg.convert('src',
                            'dst',
                            dstFormat='qcow2',
                            dstQcow2Compat='1.1')
Пример #10
0
    def _run(self):
        with guarded.context(self._source.locks + self._dest.locks):
            with self._source.prepare(), self._dest.prepare():
                # Do not start copying if we have already been aborted
                if self._status == jobs.STATUS.ABORTED:
                    return

                # Workaround for volumes containing VM configuration info that
                # were created with invalid vdsm metadata.
                if self._source.is_invalid_vm_conf_disk():
                    src_format = dst_format = qemuimg.FORMAT.RAW
                else:
                    src_format = self._source.qemu_format
                    dst_format = self._dest.qemu_format

                with self._dest.volume_operation():
                    self._operation = qemuimg.convert(
                        self._source.path,
                        self._dest.path,
                        srcFormat=src_format,
                        dstFormat=dst_format,
                        dstQcow2Compat=self._dest.qcow2_compat,
                        backing=self._dest.backing_path,
                        backingFormat=self._dest.backing_qemu_format,
                        preallocation=self._dest.preallocation,
                        unordered_writes=self._dest
                            .recommends_unordered_writes)
                    self._operation.run()
Пример #11
0
    def _run(self):
        with guarded.context(self._source.locks + self._dest.locks):
            with self._source.prepare(), self._dest.prepare():
                # Do not start copying if we have already been aborted
                if self._status == jobs.STATUS.ABORTED:
                    return

                # Workaround for volumes containing VM configuration info that
                # were created with invalid vdsm metadata.
                if self._source.is_invalid_vm_conf_disk():
                    src_format = dst_format = qemuimg.FORMAT.RAW
                else:
                    src_format = self._source.qemu_format
                    dst_format = self._dest.qemu_format

                with self._dest.volume_operation():
                    self._operation = qemuimg.convert(
                        self._source.path,
                        self._dest.path,
                        srcFormat=src_format,
                        dstFormat=dst_format,
                        dstQcow2Compat=self._dest.qcow2_compat,
                        backing=self._dest.backing_path,
                        backingFormat=self._dest.backing_qemu_format,
                        unordered_writes=self._dest.
                        recommends_unordered_writes,
                        create=self._dest.requires_create)
                    with utils.stopwatch("Copy volume {}".format(
                            self._source.path),
                                         level=logging.INFO,
                                         log=self.log):
                        self._operation.run()
Пример #12
0
    def test_qcow2_backing_file_and_format(self):
        def convert(cmd, **kw):
            expected = [
                QEMU_IMG, 'convert', '-p', '-t', 'none', '-T', 'none', 'src',
                '-O', 'qcow2', '-o',
                'compat=0.10,backing_file=bak,backing_fmt=qcow2', 'dst'
            ]
            self.assertEqual(cmd, expected)

        with MonkeyPatchScope([(qemuimg, 'config', CONFIG),
                               (qemuimg, 'ProgressCommand', convert)]):
            qemuimg.convert('src',
                            'dst',
                            dstFormat='qcow2',
                            backing='bak',
                            backingFormat='qcow2')
Пример #13
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
Пример #14
0
def upload_to_nbd(filename, nbd_url):
    op = qemuimg.convert(filename,
                         nbd_url,
                         srcFormat="qcow2",
                         create=False,
                         target_is_zero=True)
    op.run()
Пример #15
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)
Пример #16
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)
Пример #17
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
Пример #18
0
def test_readonly(nbd_env, format, allocation):
    vol = create_volume(nbd_env, format, allocation)

    op = qemuimg.convert(nbd_env.src,
                         vol.getVolumePath(),
                         srcFormat="qcow2",
                         dstFormat=format,
                         dstQcow2Compat="1.1",
                         preallocation=PREALLOCATION.get(format))
    op.run()

    config = {
        "sd_id": vol.sdUUID,
        "img_id": vol.imgUUID,
        "vol_id": vol.volUUID,
        "readonly": True,
    }

    with nbd_server(config) as nbd_url:
        # Writing to read-only NBD server must fail.
        with pytest.raises(cmdutils.Error):
            upload_to_nbd(nbd_env.src, nbd_url)

        # Download must not fail.
        download_from_nbd(nbd_url, nbd_env.dst)

    compare_images(nbd_env.src, nbd_env.dst, strict=True)

    # Now the server should not be accessible.
    with pytest.raises(cmdutils.Error):
        qemuimg.info(nbd_url)
Пример #19
0
    def _run(self):
        with guarded.context(self._source.locks + self._dest.locks):
            with self._source.prepare(), self._dest.prepare():
                # Do not start copying if we have already been aborted
                if self._status == jobs.STATUS.ABORTED:
                    return

                # Workaround for volumes containing VM configuration info that
                # were created with invalid vdsm metadata.
                if self._source.is_invalid_vm_conf_disk():
                    src_format = dst_format = qemuimg.FORMAT.RAW
                else:
                    src_format = self._source.qemu_format
                    dst_format = self._dest.qemu_format

                with self._dest.volume_operation():
                    self._operation = qemuimg.convert(
                        self._source.path,
                        self._dest.path,
                        srcFormat=src_format,
                        dstFormat=dst_format,
                        dstQcow2Compat=self._dest.qcow2_compat,
                        backing=self._dest.backing_path,
                        backingFormat=self._dest.backing_qemu_format,
                        preallocation=self._dest.preallocation)
                    self._operation.run()
Пример #20
0
def test_readonly(nbd_env, format, allocation):
    # Volume served by qemu-nd.
    img_id = str(uuid.uuid4())
    vol_id = str(uuid.uuid4())
    nbd_env.make_volume(nbd_env.virtual_size,
                        img_id,
                        vol_id,
                        vol_format=format,
                        prealloc=allocation)

    # Fill volume with data before starting the server.
    vol = nbd_env.sd_manifest.produceVolume(img_id, vol_id)
    op = qemuimg.convert(nbd_env.src,
                         vol.getVolumePath(),
                         dstFormat=sc.fmt2str(format),
                         preallocation=PREALLOCATION.get(format))
    op.run()

    # Server configuration.
    config = {
        "sd_id": nbd_env.sd_manifest.sdUUID,
        "img_id": img_id,
        "vol_id": vol_id,
        "readonly": True,
    }

    with nbd_server(config) as nbd_url:
        # Writing to NBD server must fail.
        with pytest.raises(cmdutils.Error):
            op = qemuimg.convert(nbd_env.src,
                                 nbd_url,
                                 srcFormat="raw",
                                 create=False)
            op.run()

        # Copy data from NBD server to dst. Both files should match byte
        # for byte after the operation.
        op = qemuimg.convert(nbd_url, nbd_env.dst, dstFormat="raw")
        op.run()

    with io.open(nbd_env.src) as s, io.open(nbd_env.dst) as d:
        assert s.read() == d.read()

    # Now the server should not be accessible.
    with pytest.raises(cmdutils.Error):
        qemuimg.info(nbd_url)
Пример #21
0
def test_readonly(nbd_env, format, allocation):
    # Volume served by qemu-nd.
    img_id = str(uuid.uuid4())
    vol_id = str(uuid.uuid4())
    nbd_env.make_volume(
        nbd_env.virtual_size,
        img_id,
        vol_id,
        vol_format=format,
        prealloc=allocation)

    # Fill volume with data before starting the server.
    vol = nbd_env.sd_manifest.produceVolume(img_id, vol_id)
    op = qemuimg.convert(
        nbd_env.src,
        vol.getVolumePath(),
        dstFormat=sc.fmt2str(format),
        preallocation=PREALLOCATION.get(format))
    op.run()

    # Server configuration.
    config = {
        "sd_id": nbd_env.sd_manifest.sdUUID,
        "img_id": img_id,
        "vol_id": vol_id,
        "readonly": True,
    }

    with nbd_server(config) as nbd_url:
        # Writing to NBD server must fail.
        with pytest.raises(cmdutils.Error):
            op = qemuimg.convert(
                nbd_env.src, nbd_url, srcFormat="raw", create=False)
            op.run()

        # Copy data from NBD server to dst. Both files should match byte
        # for byte after the operation.
        op = qemuimg.convert(nbd_url, nbd_env.dst, dstFormat="raw")
        op.run()

    with io.open(nbd_env.src) as s, io.open(nbd_env.dst) as d:
        assert s.read() == d.read()

    # Now the server should not be accessible.
    with pytest.raises(cmdutils.Error):
        qemuimg.info(nbd_url)
Пример #22
0
def converted_size(filename, compat):
    converted = filename + ".qcow2"
    operation = qemuimg.convert(filename,
                                converted,
                                srcFormat=qemuimg.FORMAT.RAW,
                                dstFormat=qemuimg.FORMAT.QCOW2,
                                dstQcow2Compat=compat)
    operation.run()
    return os.stat(converted).st_size
Пример #23
0
def convert_to_qcow2(src, compressed=False, compat="1.1"):
    dst = src + ".qcow2"
    convert_cmd = qemuimg.convert(src,
                                  dst,
                                  dstFormat=qemuimg.FORMAT.QCOW2,
                                  dstQcow2Compat=compat,
                                  compressed=compressed)
    convert_cmd.run()
    os.remove(src)
    return dst
Пример #24
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()
Пример #25
0
def convert_to_qcow2(src, compressed=False, compat="1.1"):
    dst = src + ".qcow2"
    convert_cmd = qemuimg.convert(
        src,
        dst,
        dstFormat=qemuimg.FORMAT.QCOW2,
        dstQcow2Compat=compat,
        compressed=compressed)
    convert_cmd.run()
    os.remove(src)
    return dst
Пример #26
0
    def test_qcow2_to_raw_sparse(self, preallocation):
        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="qcow2")
            op.run()

            op = qemuimg.convert(src, dst, srcFormat="qcow2", dstFormat="raw",
                                 preallocation=preallocation)
            op.run()
            check_raw_sparse_image(dst, virtual_size)
Пример #27
0
    def test_raw_to_raw_preallocation_off(self, preallocation):
        virtual_size = 10 * 1024**2
        with namedTemporaryDir() as tmpdir:
            src = os.path.join(tmpdir, 'src')
            dst = os.path.join(tmpdir, 'dst')

            with io.open(src, "wb") as f:
                f.truncate(virtual_size)

            op = qemuimg.convert(src, dst, srcFormat="raw", dstFormat="raw",
                                 preallocation=preallocation)
            op.run()
            check_raw_sparse_image(dst, virtual_size)
Пример #28
0
    def test_raw_to_raw(self, preallocation, virtual_size, actual_size):
        with namedTemporaryDir() as tmpdir:
            src = os.path.join(tmpdir, 'src')
            dst = os.path.join(tmpdir, 'dst')

            with io.open(src, "wb") as f:
                f.truncate(virtual_size)

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

            stat = os.stat(dst)
            assert stat.st_size == virtual_size
            assert stat.st_blocks * 512 == actual_size
Пример #29
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
Пример #30
0
    def test_raw_to_compressed_qcow2(self, tmpdir):
        src_file = str(tmpdir.join("test.raw"))
        dst_file = str(tmpdir.join("test.qcow2"))
        with io.open(src_file, "wb") as f:
            f.truncate(1 * GIB)
            f.write(b"x" * MEGAB)

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

        assert src_file_size > dst_file_size
Пример #31
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
Пример #32
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
Пример #33
0
    def test_raw_to_compressed_qcow2(self, tmpdir):
        src_file = str(tmpdir.join("test.raw"))
        dst_file = str(tmpdir.join("test.qcow2"))
        with io.open(src_file, "wb") as f:
            f.truncate(1 * GIB)
            f.write(b"x" * MEGAB)

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

        assert src_file_size > dst_file_size
Пример #34
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)
Пример #35
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)
Пример #36
0
 def test_raw_invalid_preallocation(self):
     with pytest.raises(ValueError):
         qemuimg.convert(
             'src', 'dst', dstFormat="raw",
             preallocation=qemuimg.PREALLOCATION.METADATA)
Пример #37
0
def download_from_nbd(nbd_url, filename):
    op = qemuimg.convert(nbd_url,
                         filename,
                         dstFormat="qcow2",
                         dstQcow2Compat="1.1")
    op.run()
Пример #38
0
 def test_raw_invalid_preallocation(self):
     with pytest.raises(ValueError):
         qemuimg.convert(
             'src', 'dst', dstFormat="raw",
             preallocation=qemuimg.PREALLOCATION.METADATA)
Пример #39
0
 def test_qcow2_compat_invalid(self):
     with pytest.raises(ValueError):
         qemuimg.convert('image', 'dst', dstFormat='qcow2',
                         backing='bak', backingFormat='qcow2',
                         dstQcow2Compat='1.11')
Пример #40
0
    def _interImagesCopy(self, destDom, srcSdUUID, imgUUID, chains):
        srcLeafVol = chains['srcChain'][-1]
        dstLeafVol = chains['dstChain'][-1]
        try:
            # Prepare the whole chains before the copy
            srcLeafVol.prepare(rw=False)
            dstLeafVol.prepare(rw=True, chainrw=True, setrw=True)
        except Exception:
            self.log.error("Unexpected error", exc_info=True)
            # teardown volumes
            self.__cleanupMove(srcLeafVol, dstLeafVol)
            raise

        try:
            for srcVol in chains['srcChain']:
                # Do the actual copy
                try:
                    dstVol = destDom.produceVolume(imgUUID=imgUUID,
                                                   volUUID=srcVol.volUUID)

                    if workarounds.invalid_vm_conf_disk(srcVol):
                        srcFormat = dstFormat = qemuimg.FORMAT.RAW
                    else:
                        srcFormat = sc.fmt2str(srcVol.getFormat())
                        dstFormat = sc.fmt2str(dstVol.getFormat())

                    parentVol = dstVol.getParentVolume()

                    if parentVol is not None:
                        backing = volume.getBackingVolumePath(
                            imgUUID, parentVol.volUUID)
                        backingFormat = sc.fmt2str(parentVol.getFormat())
                    else:
                        backing = None
                        backingFormat = None

                    if (destDom.supportsSparseness
                            and dstVol.getType() == sc.PREALLOCATED_VOL):
                        preallocation = qemuimg.PREALLOCATION.FALLOC
                    else:
                        preallocation = None

                    operation = qemuimg.convert(
                        srcVol.getVolumePath(),
                        dstVol.getVolumePath(),
                        srcFormat=srcFormat,
                        dstFormat=dstFormat,
                        dstQcow2Compat=destDom.qcow2_compat(),
                        backing=backing,
                        backingFormat=backingFormat,
                        preallocation=preallocation,
                        unordered_writes=destDom.recommends_unordered_writes(
                            dstVol.getFormat()),
                        create=not destDom.is_block(),
                    )
                    with utils.stopwatch("Copy volume %s" % srcVol.volUUID):
                        self._run_qemuimg_operation(operation)
                except ActionStopped:
                    raise
                except se.StorageException:
                    self.log.error("Unexpected error", exc_info=True)
                    raise
                except Exception:
                    self.log.error(
                        "Copy image error: image=%s, src domain=%s,"
                        " dst domain=%s",
                        imgUUID,
                        srcSdUUID,
                        destDom.sdUUID,
                        exc_info=True)
                    raise se.CopyImageError()
        finally:
            # teardown volumes
            self.__cleanupMove(srcLeafVol, dstLeafVol)
Пример #41
0
    def test_qcow2_backing_file_without_creation(self):
        virtual_size = MiB
        with namedTemporaryDir() as tmpdir:
            # Create source chain.
            src_base = os.path.join(tmpdir, '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(tmpdir, '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 dest chain
            dst_base = os.path.join(tmpdir, 'dst_base.img')
            op = qemuimg.create(
                dst_base,
                size=virtual_size,
                format=qemuimg.FORMAT.QCOW2,
                qcow2Compat='1.1'
            )
            op.run()

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

            # Write data to the source chain.
            cluster_size = 64 * KiB
            for i, path in enumerate([src_base, src_top]):
                qemuio.write_pattern(
                    path,
                    "qcow2",
                    offset=i * cluster_size,
                    len=cluster_size,
                    pattern=0xf0 + i)

            # Copy base to base.
            op = qemuimg.convert(
                src_base,
                dst_base,
                srcFormat='qcow2',
                dstFormat='qcow2',
                dstQcow2Compat='1.1',
                create=False
            )
            op.run()

            # Copy top to top.
            op = qemuimg.convert(
                src_top,
                dst_top,
                srcFormat='qcow2',
                dstFormat='qcow2',
                backing=dst_base,
                dstQcow2Compat='1.1',
                create=False
            )
            op.run()

            # Run comparisons, if there is a mismatch in content or size
            # op.run() will raise and fail the test.
            op = qemuimg.compare(
                src_base,
                dst_base,
                img1_format='qcow2',
                img2_format='qcow2',
                strict=True
            )
            op.run()

            op = qemuimg.compare(
                src_top,
                dst_top,
                img1_format='qcow2',
                img2_format='qcow2',
                strict=True
            )
            op.run()
Пример #42
0
    def test_qcow2(self, user_mount, dst_compat, create):
        virtual_size = MiB
        # Create 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 dest chain
        dst_base = os.path.join(user_mount.path, 'dst_base.img')
        op = qemuimg.create(
            dst_base,
            size=virtual_size,
            format=qemuimg.FORMAT.QCOW2,
            qcow2Compat=dst_compat,
        )
        op.run()

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

        # Write data to the source chain.
        cluster_size = 64 * KiB
        for i, path in enumerate([src_base, src_top]):
            qemuio.write_pattern(
                path,
                "qcow2",
                offset=i * cluster_size,
                len=cluster_size,
                pattern=0xf0 + i)

        # Copy base to base.
        op = qemuimg.convert(
            src_base,
            dst_base,
            srcFormat='qcow2',
            dstFormat='qcow2',
            dstQcow2Compat=dst_compat,
            create=create
        )
        op.run()

        # Copy top to top.
        op = qemuimg.convert(
            src_top,
            dst_top,
            srcFormat='qcow2',
            dstFormat='qcow2',
            backing=dst_base,
            backingFormat='qcow2',
            dstQcow2Compat=dst_compat,
            # With a backing we can always use False.
            create=False
        )
        op.run()

        # Run comparisons, if there is a mismatch in content or size
        # op.run() will raise and fail the test.
        op = qemuimg.compare(
            src_base,
            dst_base,
            img1_format='qcow2',
            img2_format='qcow2',
            strict=True
        )
        op.run()

        op = qemuimg.compare(
            src_top,
            dst_top,
            img1_format='qcow2',
            img2_format='qcow2',
            strict=True
        )
        op.run()
Пример #43
0
    def copyCollapsed(self, sdUUID, vmUUID, srcImgUUID, srcVolUUID, dstImgUUID,
                      dstVolUUID, descr, dstSdUUID, volType, volFormat,
                      preallocate, postZero, force, discard):
        """
        Create new template/volume from VM.
        Do it by collapse and copy the whole chain (baseVolUUID->srcVolUUID)
        """
        self.log.info(
            "sdUUID=%s vmUUID=%s srcImgUUID=%s srcVolUUID=%s "
            "dstImgUUID=%s dstVolUUID=%s dstSdUUID=%s volType=%s "
            "volFormat=%s preallocate=%s force=%s postZero=%s "
            "discard=%s", sdUUID, vmUUID, srcImgUUID, srcVolUUID, dstImgUUID,
            dstVolUUID, dstSdUUID, volType, sc.type2name(volFormat),
            sc.type2name(preallocate), str(force), str(postZero), discard)
        try:
            srcVol = dstVol = None

            # Find out dest sdUUID
            if dstSdUUID == sd.BLANK_UUID:
                dstSdUUID = sdUUID
            volclass = sdCache.produce(sdUUID).getVolumeClass()
            destDom = sdCache.produce(dstSdUUID)

            # find src volume
            try:
                srcVol = volclass(self.repoPath, sdUUID, srcImgUUID,
                                  srcVolUUID)
            except se.StorageException:
                raise
            except Exception as e:
                self.log.error(e, exc_info=True)
                raise se.SourceImageActionError(srcImgUUID, sdUUID, str(e))

            # Create dst volume
            try:
                # Before reading source volume parameters from volume metadata,
                # prepare the volume. This ensure that the volume capacity will
                # match the actual virtual size, see
                # https://bugzilla.redhat.com/1700623.
                srcVol.prepare(rw=False)

                volParams = srcVol.getVolumeParams()

                if volFormat in [sc.COW_FORMAT, sc.RAW_FORMAT]:
                    dstVolFormat = volFormat
                else:
                    dstVolFormat = volParams['volFormat']

                # TODO: This is needed only when copying to qcow2-thin volume
                # on block storage. Move into calculate_initial_size.
                dst_vol_allocation = self.calculate_vol_alloc(
                    sdUUID, volParams, dstSdUUID, dstVolFormat)

                # Find out dest volume parameters
                if preallocate in [sc.PREALLOCATED_VOL, sc.SPARSE_VOL]:
                    volParams['prealloc'] = preallocate

                initial_size = self.calculate_initial_size(
                    destDom.supportsSparseness, dstVolFormat,
                    volParams['prealloc'], dst_vol_allocation)

                self.log.info(
                    "Copy source %s:%s:%s to destination %s:%s:%s "
                    "capacity=%s, initial size=%s", sdUUID, srcImgUUID,
                    srcVolUUID, dstSdUUID, dstImgUUID, dstVolUUID,
                    volParams['capacity'], initial_size)

                # If image already exists check whether it illegal/fake,
                # overwrite it
                if not self.isLegal(dstSdUUID, dstImgUUID):
                    force = True

                # We must first remove the previous instance of image (if
                # exists) in destination domain, if we got the overwrite
                # command
                if force:
                    self.log.info(
                        "delete image %s on domain %s before "
                        "overwriting", dstImgUUID, dstSdUUID)
                    _deleteImage(destDom, dstImgUUID, postZero, discard)

                destDom.createVolume(imgUUID=dstImgUUID,
                                     capacity=volParams['capacity'],
                                     volFormat=dstVolFormat,
                                     preallocate=volParams['prealloc'],
                                     diskType=volParams['disktype'],
                                     volUUID=dstVolUUID,
                                     desc=descr,
                                     srcImgUUID=sc.BLANK_UUID,
                                     srcVolUUID=sc.BLANK_UUID,
                                     initial_size=initial_size)

                dstVol = sdCache.produce(dstSdUUID).produceVolume(
                    imgUUID=dstImgUUID, volUUID=dstVolUUID)

            except se.StorageException:
                self.log.error("Unexpected error", exc_info=True)
                raise
            except Exception as e:
                self.log.error("Unexpected error", exc_info=True)
                raise se.CopyImageError("Destination volume %s error: %s" %
                                        (dstVolUUID, str(e)))

            try:
                # Start the actual copy image procedure
                dstVol.prepare(rw=True, setrw=True)

                if (destDom.supportsSparseness
                        and dstVol.getType() == sc.PREALLOCATED_VOL):
                    preallocation = qemuimg.PREALLOCATION.FALLOC
                else:
                    preallocation = None

                try:
                    operation = qemuimg.convert(
                        volParams['path'],
                        dstVol.getVolumePath(),
                        srcFormat=sc.fmt2str(volParams['volFormat']),
                        dstFormat=sc.fmt2str(dstVolFormat),
                        dstQcow2Compat=destDom.qcow2_compat(),
                        preallocation=preallocation,
                        unordered_writes=destDom.recommends_unordered_writes(
                            dstVolFormat),
                        create=not destDom.is_block(),
                    )
                    with utils.stopwatch("Copy volume %s" % srcVol.volUUID):
                        self._run_qemuimg_operation(operation)
                except ActionStopped:
                    raise
                except cmdutils.Error as e:
                    self.log.exception('conversion failure for volume %s',
                                       srcVol.volUUID)
                    raise se.CopyImageError(str(e))

                # Mark volume as SHARED
                if volType == sc.SHARED_VOL:
                    dstVol.setShared()

                dstVol.setLegality(sc.LEGAL_VOL)

                if force:
                    # Now we should re-link all deleted hardlinks, if exists
                    destDom.templateRelink(dstImgUUID, dstVolUUID)
            except se.StorageException:
                self.log.error("Unexpected error", exc_info=True)
                raise
            except Exception as e:
                self.log.error("Unexpected error", exc_info=True)
                raise se.CopyImageError("src image=%s, dst image=%s: msg=%s" %
                                        (srcImgUUID, dstImgUUID, str(e)))

            self.log.info("Finished copying %s:%s -> %s:%s", sdUUID,
                          srcVolUUID, dstSdUUID, dstVolUUID)
            # TODO: handle return status
            return dstVolUUID
        finally:
            self.__cleanupCopy(srcVol=srcVol, dstVol=dstVol)