[virt-tools-list] [virt-bootstrap] [PATCH v4 11/26] Create qcow2 images with python-guestfs
Radostin Stoyanov
rstoyanov1 at gmail.com
Thu Aug 3 13:13:09 UTC 2017
---
src/virtBootstrap/utils.py | 96 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
diff --git a/src/virtBootstrap/utils.py b/src/virtBootstrap/utils.py
index e05a83f..19aaa17 100644
--- a/src/virtBootstrap/utils.py
+++ b/src/virtBootstrap/utils.py
@@ -33,6 +33,7 @@ import tempfile
import logging
import re
+import guestfs
import passlib.hosts
# pylint: disable=invalid-name
@@ -42,6 +43,8 @@ logger = logging.getLogger(__name__)
DEFAULT_OUTPUT_FORMAT = 'dir'
# Default virtual size of qcow2 image
DEF_QCOW2_SIZE = '5G'
+DEF_BASE_IMAGE_SIZE = 5 * 1024 * 1024 * 1024
+
if os.geteuid() == 0:
LIBVIRT_CONN = "lxc:///"
DEFAULT_IMG_DIR = "/var/lib/virt-bootstrap/docker_images"
@@ -51,6 +54,99 @@ else:
DEFAULT_IMG_DIR += "/.local/share/virt-bootstrap/docker_images"
+class Build_QCOW2_Image(object):
+ """
+ Create qcow2 image with backing chains from list of tar files.
+ """
+ def __init__(self, **kwargs):
+ """
+ Initialize guestfs
+
+ @param tar_files: List of paths to tar files from which to the rootfs
+ @param dest: Destination directory where qcow2 images will be stored
+ @param progress: Instance of the progress module
+ """
+ self.tar_files = kwargs['tar_files']
+ if not isinstance(self.tar_files, list):
+ raise ValueError(
+ 'tar_files must be list not %s' % type(self.tar_files)
+ )
+ self.progress = kwargs['progress']
+ self.fmt = 'qcow2'
+ self.qcow2_files = [os.path.join(kwargs['dest'], 'layer-%s.qcow2' % i)
+ for i in range(len(self.tar_files))]
+
+ self.g = guestfs.GuestFS(python_return_dict=True)
+ self.create_base_qcow2_layer(self.tar_files[0], self.qcow2_files[0])
+ if len(self.tar_files) > 1:
+ self.create_backing_chains()
+ self.g.shutdown()
+
+ def create_disk(self, qcow2_file, backingfile=None, readonly=False):
+ """
+ Create and add qcow2 disk image.
+ """
+ if backingfile is not None:
+ size = -1
+ backingformat = self.fmt
+ else:
+ size = DEF_BASE_IMAGE_SIZE
+ backingformat = None
+
+ self.g.disk_create(qcow2_file, self.fmt, size, backingfile,
+ backingformat)
+ self.g.add_drive_opts(qcow2_file, readonly, self.fmt)
+
+ def tar_in(self, tar_file, dev):
+ """
+ Extract tar file in disk device.
+ """
+ self.g.mount(dev, '/')
+ # Restore extended attributes, SELinux contexts and POSIX ACLs
+ # from tar file.
+ self.g.tar_in(tar_file, '/', get_compression_type(tar_file),
+ xattrs=True, selinux=True, acls=True)
+ # Shutdown guestfs instance to avoid hot-plugging of devices.
+ self.g.umount('/')
+
+ def create_base_qcow2_layer(self, tar_file, qcow2_file):
+ """
+ Create and format base qcow2 layer.
+
+ Do this separatelly when extracting multiple layers to avoid
+ hot-plugging of devices.
+ """
+ self.progress("Creating base layer", logger=logger)
+ self.create_disk(qcow2_file)
+ self.g.launch()
+ dev = self.g.list_devices()[0]
+ self.progress("Formating disk image", logger=logger)
+ self.g.mkfs("ext3", dev)
+ self.tar_in(tar_file, dev)
+ self.progress("Extracting content of base layer", logger=logger)
+ self.g.shutdown()
+
+ def create_backing_chains(self):
+ """
+ Create backing chains for all layers after following the first
+ and tar-in the content.
+ """
+ for i in range(1, len(self.tar_files)):
+ self.progress("Creating layer %d" % i, logger=logger)
+ self.create_disk(
+ self.qcow2_files[i],
+ backingfile=self.qcow2_files[i - 1]
+ )
+
+ self.g.launch()
+ devices = self.g.list_devices()
+ # Iterate trough tar files of layers and skip the base layer
+ for i, tar_file in enumerate(self.tar_files[1:]):
+ self.progress("Extracting content of layer %d" % (i + 1),
+ logger=logger)
+ self.tar_in(tar_file, devices[i])
+
+
def get_compression_type(tar_file):
"""
Get compression type of tar file.
--
2.13.3
More information about the virt-tools-list
mailing list