xref: /qemu/tests/qemu-iotests/302 (revision c30175d6)
103a970bbSNir Soffer#!/usr/bin/env python3
29dd003a9SVladimir Sementsov-Ogievskiy# group: quick
303a970bbSNir Soffer#
403a970bbSNir Soffer# Tests converting qcow2 compressed to NBD
503a970bbSNir Soffer#
603a970bbSNir Soffer# Copyright (c) 2020 Nir Soffer <nirsof@gmail.com>
703a970bbSNir Soffer#
803a970bbSNir Soffer# This program is free software; you can redistribute it and/or modify
903a970bbSNir Soffer# it under the terms of the GNU General Public License as published by
1003a970bbSNir Soffer# the Free Software Foundation; either version 2 of the License, or
1103a970bbSNir Soffer# (at your option) any later version.
1203a970bbSNir Soffer#
1303a970bbSNir Soffer# This program is distributed in the hope that it will be useful,
1403a970bbSNir Soffer# but WITHOUT ANY WARRANTY; without even the implied warranty of
1503a970bbSNir Soffer# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1603a970bbSNir Soffer# GNU General Public License for more details.
1703a970bbSNir Soffer#
1803a970bbSNir Soffer# You should have received a copy of the GNU General Public License
1903a970bbSNir Soffer# along with this program.  If not, see <http://www.gnu.org/licenses/>.
2003a970bbSNir Soffer#
2103a970bbSNir Soffer# owner=nirsof@gmail.com
2203a970bbSNir Soffer
2303a970bbSNir Sofferimport io
2403a970bbSNir Sofferimport tarfile
2503a970bbSNir Soffer
2603a970bbSNir Sofferimport iotests
2703a970bbSNir Soffer
2803a970bbSNir Sofferfrom iotests import (
2903a970bbSNir Soffer    file_path,
3003a970bbSNir Soffer    qemu_img,
3103a970bbSNir Soffer    qemu_img_check,
3203a970bbSNir Soffer    qemu_img_create,
3303a970bbSNir Soffer    qemu_img_log,
3403a970bbSNir Soffer    qemu_img_measure,
3503a970bbSNir Soffer    qemu_io,
3603a970bbSNir Soffer    qemu_nbd_popen,
37*c30175d6SVladimir Sementsov-Ogievskiy    img_info_log,
3803a970bbSNir Soffer)
3903a970bbSNir Soffer
4003a970bbSNir Sofferiotests.script_initialize(supported_fmts=["qcow2"])
4103a970bbSNir Soffer
4203a970bbSNir Soffer# Create source disk. Using qcow2 to enable strict comparing later, and
4303a970bbSNir Soffer# avoid issues with random filesystem on CI environment.
4403a970bbSNir Soffersrc_disk = file_path("disk.qcow2")
4503a970bbSNir Sofferqemu_img_create("-f", iotests.imgfmt, src_disk, "1g")
4603a970bbSNir Sofferqemu_io("-f", iotests.imgfmt, "-c", "write 1m 64k", src_disk)
4703a970bbSNir Soffer
4803a970bbSNir Soffer# The use case is writing qcow2 image directly into an ova file, which
4903a970bbSNir Soffer# is a tar file with specific layout. This is tricky since we don't know the
5003a970bbSNir Soffer# size of the image before compressing, so we have to do:
5103a970bbSNir Soffer# 1. Add an ovf file.
5203a970bbSNir Soffer# 2. Find the offset of the next member data.
5303a970bbSNir Soffer# 3. Make room for image data, allocating for the worst case.
5403a970bbSNir Soffer# 4. Write compressed image data into the tar.
5503a970bbSNir Soffer# 5. Add a tar entry with the actual image size.
5603a970bbSNir Soffer# 6. Shrink the tar to the actual size, aligned to 512 bytes.
5703a970bbSNir Soffer
5803a970bbSNir Soffertar_file = file_path("test.ova")
5903a970bbSNir Soffer
6003a970bbSNir Sofferwith tarfile.open(tar_file, "w") as tar:
6103a970bbSNir Soffer
6203a970bbSNir Soffer    # 1. Add an ovf file.
6303a970bbSNir Soffer
6403a970bbSNir Soffer    ovf_data = b"<xml/>"
6503a970bbSNir Soffer    ovf = tarfile.TarInfo("vm.ovf")
6603a970bbSNir Soffer    ovf.size = len(ovf_data)
6703a970bbSNir Soffer    tar.addfile(ovf, io.BytesIO(ovf_data))
6803a970bbSNir Soffer
6903a970bbSNir Soffer    # 2. Find the offset of the next member data.
7003a970bbSNir Soffer
7103a970bbSNir Soffer    offset = tar.fileobj.tell() + 512
7203a970bbSNir Soffer
7303a970bbSNir Soffer    # 3. Make room for image data, allocating for the worst case.
7403a970bbSNir Soffer
7503a970bbSNir Soffer    measure = qemu_img_measure("-O", "qcow2", src_disk)
7603a970bbSNir Soffer    tar.fileobj.truncate(offset + measure["required"])
7703a970bbSNir Soffer
7803a970bbSNir Soffer    # 4. Write compressed image data into the tar.
7903a970bbSNir Soffer
8003a970bbSNir Soffer    nbd_sock = file_path("nbd-sock", base_dir=iotests.sock_dir)
8103a970bbSNir Soffer    nbd_uri = "nbd+unix:///exp?socket=" + nbd_sock
8203a970bbSNir Soffer
8303a970bbSNir Soffer    # Use raw format to allow creating qcow2 directly into tar file.
8403a970bbSNir Soffer    with qemu_nbd_popen(
8503a970bbSNir Soffer            "--socket", nbd_sock,
8603a970bbSNir Soffer            "--export-name", "exp",
8703a970bbSNir Soffer            "--format", "raw",
8803a970bbSNir Soffer            "--offset", str(offset),
8903a970bbSNir Soffer            tar_file):
9003a970bbSNir Soffer
9103a970bbSNir Soffer        iotests.log("=== Target image info ===")
92*c30175d6SVladimir Sementsov-Ogievskiy        # Not img_info_log as it enforces imgfmt, but now we print info on raw
9303a970bbSNir Soffer        qemu_img_log("info", nbd_uri)
9403a970bbSNir Soffer
9503a970bbSNir Soffer        qemu_img(
9603a970bbSNir Soffer            "convert",
9703a970bbSNir Soffer            "-f", iotests.imgfmt,
9803a970bbSNir Soffer            "-O", "qcow2",
9903a970bbSNir Soffer            "-c",
10003a970bbSNir Soffer            src_disk,
10103a970bbSNir Soffer            nbd_uri)
10203a970bbSNir Soffer
10303a970bbSNir Soffer        iotests.log("=== Converted image info ===")
104*c30175d6SVladimir Sementsov-Ogievskiy        img_info_log(nbd_uri)
10503a970bbSNir Soffer
10603a970bbSNir Soffer        iotests.log("=== Converted image check ===")
10703a970bbSNir Soffer        qemu_img_log("check", nbd_uri)
10803a970bbSNir Soffer
10903a970bbSNir Soffer        iotests.log("=== Comparing to source disk ===")
11003a970bbSNir Soffer        qemu_img_log("compare", src_disk, nbd_uri)
11103a970bbSNir Soffer
11203a970bbSNir Soffer        actual_size = qemu_img_check(nbd_uri)["image-end-offset"]
11303a970bbSNir Soffer
11403a970bbSNir Soffer    # 5. Add a tar entry with the actual image size.
11503a970bbSNir Soffer
11603a970bbSNir Soffer    disk = tarfile.TarInfo("disk")
11703a970bbSNir Soffer    disk.size = actual_size
11803a970bbSNir Soffer    tar.addfile(disk)
11903a970bbSNir Soffer
12003a970bbSNir Soffer    # 6. Shrink the tar to the actual size, aligned to 512 bytes.
12103a970bbSNir Soffer
12203a970bbSNir Soffer    tar_size = offset + (disk.size + 511) & ~511
12303a970bbSNir Soffer    tar.fileobj.seek(tar_size)
12403a970bbSNir Soffer    tar.fileobj.truncate(tar_size)
12503a970bbSNir Soffer
12603a970bbSNir Sofferwith tarfile.open(tar_file) as tar:
12703a970bbSNir Soffer    members = [{"name": m.name, "size": m.size, "offset": m.offset_data}
12803a970bbSNir Soffer               for m in tar]
12903a970bbSNir Soffer    iotests.log("=== OVA file contents ===")
13003a970bbSNir Soffer    iotests.log(members)
131