[virt-tools-list] [virt-bootstrap] [PATCH v2 14/14] sources: Add support for virt-builder

Radostin Stoyanov rstoyanov1 at gmail.com
Tue Aug 1 11:28:55 UTC 2017


Add implementation for virt-builder source. The aim is to create a
container root file system from VM image build with virt-builder.
---
 src/virtBootstrap/sources/__init__.py            |   1 +
 src/virtBootstrap/sources/virt_builder_source.py | 134 +++++++++++++++++++++++
 src/virtBootstrap/utils.py                       |   9 ++
 src/virtBootstrap/virt_bootstrap.py              |   2 +-
 4 files changed, 145 insertions(+), 1 deletion(-)
 create mode 100644 src/virtBootstrap/sources/virt_builder_source.py

diff --git a/src/virtBootstrap/sources/__init__.py b/src/virtBootstrap/sources/__init__.py
index e891e9b..be6b25c 100644
--- a/src/virtBootstrap/sources/__init__.py
+++ b/src/virtBootstrap/sources/__init__.py
@@ -24,3 +24,4 @@ sources - Class definitions which process container image or
 
 from virtBootstrap.sources.file_source import FileSource
 from virtBootstrap.sources.docker_source import DockerSource
+from virtBootstrap.sources.virt_builder_source import VirtBuilderSource
diff --git a/src/virtBootstrap/sources/virt_builder_source.py b/src/virtBootstrap/sources/virt_builder_source.py
new file mode 100644
index 0000000..f55668e
--- /dev/null
+++ b/src/virtBootstrap/sources/virt_builder_source.py
@@ -0,0 +1,134 @@
+# Authors: Radostin Stoyanov <rstoyanov1 at gmail.com>
+#
+# Copyright (C) 2017 Radostin Stoyanov
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+VirtBuilderSource aim is to extract the root file system from VM image
+build with virt-builder from template.
+"""
+
+import os
+import logging
+import subprocess
+import shutil
+
+from virtBootstrap import utils
+
+
+# pylint: disable=invalid-name
+# Create logger
+logger = logging.getLogger(__name__)
+
+
+class VirtBuilderSource(object):
+    """
+    Extract root file system from image build with virt-builder.
+    """
+    def __init__(self, **kwargs):
+        """
+        Create container rootfs by building VM from virt-builder template
+        and extract the rootfs.
+
+        @param uri: Template name
+        @param fmt: Format used to store the output [dir, qcow2]
+        @param progress: Instance of the progress module
+        """
+        # Parsed URIs:
+        # - "virt-builder:///<template>"
+        # - "virt-builder://<template>"
+        # - "virt-builder:/<template>"
+        self.template = kwargs['uri'].netloc or kwargs['uri'].path[1:]
+        self.output_format = kwargs.get('fmt', utils.DEFAULT_OUTPUT_FORMAT)
+        self.root_password = kwargs.get('root_password', None)
+        self.progress = kwargs['progress'].update_progress
+
+    def build_image(self, output_file):
+        """
+        Build VM from virt-builder template
+        """
+        cmd = ['virt-builder', self.template,
+               '-o', output_file,
+               '--no-network',
+               '--delete', '/dev/*',
+               '--delete', '/boot/*',
+               # Comment out every line in fstab
+               '--edit', '/etc/fstab:s/^/#/']
+        if self.root_password is not None:
+            cmd += ['--root-password', "password:%s" % self.root_password]
+        subprocess.check_call(cmd)
+
+    def unpack(self, dest):
+        """
+        Build image and extract root file system
+
+        @param dest: Directory path where output files will be stored.
+        """
+
+        tmp_dir = utils.get_image_dir(no_cache=True)
+        tmp_image_file = os.path.join(tmp_dir, self.template + '.img')
+
+        try:
+            if self.output_format == 'dir':
+
+                self.progress("Building image", value=0, logger=logger)
+                self.build_image(tmp_image_file)
+
+                self.progress("Extracting file system",
+                              value=50, logger=logger)
+                utils.execute(['virt-copy-out',
+                               '-a', tmp_image_file, '/', dest])
+
+                self.progress("Extraction completed successfully!",
+                              value=100, logger=logger)
+                logger.info("Files are stored in: %s", dest)
+
+            elif self.output_format == 'qcow2':
+                # Use templete name as name for the output image
+                image_file = os.path.join(dest, self.template + '.qcow2')
+                utils.show_error_if_file_exits(image_file)
+
+                # Create temporary directory to extract file system
+                tmp_tar_file = os.path.join(tmp_dir, 'filesystem.tar')
+
+                self.progress("Building image", value=0, logger=logger)
+                self.build_image(tmp_image_file)
+
+                self.progress("Extracting file system", value=33,
+                              logger=logger)
+                utils.execute(['virt-tar-out',
+                               '-a', tmp_image_file, '/', tmp_tar_file])
+
+                self.progress("Creating qcow2 image with single partition",
+                              value=66, logger=logger)
+                utils.execute(['virt-make-fs',
+                               '--type=ext3',
+                               '--format=qcow2',
+                               '--size=+200M',
+                               tmp_tar_file, image_file])
+
+                self.progress("Extraction completed successfully!", value=100,
+                              logger=logger)
+                logger.info("Image is stored in: %s", image_file)
+
+            else:
+                raise Exception("Unknown format:" + self.output_format)
+
+        except Exception:
+            raise
+
+        finally:
+            # Clean up
+            shutil.rmtree(tmp_dir)
diff --git a/src/virtBootstrap/utils.py b/src/virtBootstrap/utils.py
index 3b7758f..3f8c606 100644
--- a/src/virtBootstrap/utils.py
+++ b/src/virtBootstrap/utils.py
@@ -538,6 +538,15 @@ def write_progress(prog):
     sys.stdout.flush()
 
 
+def show_error_if_file_exits(path):
+    """
+    Show error message if path exist and exit
+    """
+    if os.path.exists(path):
+        logger.error("File already exist '%s'", path)
+        sys.exit(1)
+
+
 # The implementation for remapping ownership of all files inside a
 # container's rootfs is inspired by the tool uidmapshift:
 #
diff --git a/src/virtBootstrap/virt_bootstrap.py b/src/virtBootstrap/virt_bootstrap.py
index e465fb2..8c19f29 100755
--- a/src/virtBootstrap/virt_bootstrap.py
+++ b/src/virtBootstrap/virt_bootstrap.py
@@ -62,7 +62,7 @@ def get_source(source_type):
     Get object which match the source type
     """
     try:
-        class_name = "%sSource" % source_type.capitalize()
+        class_name = "%sSource" % source_type.title().replace('-', '')
         clazz = getattr(sources, class_name)
         return clazz
     except Exception:
-- 
2.13.3




More information about the virt-tools-list mailing list