Allow virt-sandbox-image to pull templates from virt-builder and run
sandboxes on top of them.
---
libvirt-sandbox.spec.in | 1 +
libvirt-sandbox/image/cli.py | 1 +
libvirt-sandbox/image/sources/Makefile.am | 1 +
libvirt-sandbox/image/sources/VirtBuilderSource.py | 136 +++++++++++++++++++++
libvirt-sandbox/image/template.py | 2 +
5 files changed, 141 insertions(+)
create mode 100644 libvirt-sandbox/image/sources/VirtBuilderSource.py
diff --git a/libvirt-sandbox.spec.in b/libvirt-sandbox.spec.in
index 54fde55..f84eabc 100644
--- a/libvirt-sandbox.spec.in
+++ b/libvirt-sandbox.spec.in
@@ -36,6 +36,7 @@ Requires: systemd >= 198
Requires: pygobject3-base
Requires: libselinux-python
Requires: %{name}-libs = %{version}-%{release}
+Requires: %{_bindir}/virt-builder
%package libs
Group: Development/Libraries
diff --git a/libvirt-sandbox/image/cli.py b/libvirt-sandbox/image/cli.py
index e991e2d..fb1104a 100755
--- a/libvirt-sandbox/image/cli.py
+++ b/libvirt-sandbox/image/cli.py
@@ -188,6 +188,7 @@ Example supported URI formats:
docker:///ubuntu?tag=15.04
docker://username:password@index.docker.io/private/image
docker://registry.access.redhat.com/rhel6
+ virt-builder:///fedora-20
""")
return parser
diff --git a/libvirt-sandbox/image/sources/Makefile.am
b/libvirt-sandbox/image/sources/Makefile.am
index 069557d..52e9a7e 100644
--- a/libvirt-sandbox/image/sources/Makefile.am
+++ b/libvirt-sandbox/image/sources/Makefile.am
@@ -4,6 +4,7 @@ pythonimage_DATA = \
__init__.py \
Source.py \
DockerSource.py \
+ VirtBuilderSource.py \
$(NULL)
EXTRA_DIST = $(pythonimage_DATA)
diff --git a/libvirt-sandbox/image/sources/VirtBuilderSource.py
b/libvirt-sandbox/image/sources/VirtBuilderSource.py
new file mode 100644
index 0000000..4a7e383
--- /dev/null
+++ b/libvirt-sandbox/image/sources/VirtBuilderSource.py
@@ -0,0 +1,136 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2015 SUSE LLC
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Author: Cedric Bosdonnat <cbosdonnat(a)suse.com>
+#
+
+from Source import Source
+import os
+import os.path
+import subprocess
+
+class VirtBuilderSource(Source):
+
+ def _get_template_name(self, template):
+ # We shouldn't have '/' in the names, but let's make sure
+ # nobody can try to alter the folders structure later.
+ return template.path[1:].replace('/', '_')
+
+ def download_template(self, template, templatedir):
+ # We don't do anything here: virt-builder will do it for us in
+ # the create action
+ pass
+
+ def _check_disk_format(self,format):
+ supportedFormats = ['qcow2', 'raw']
+ if not format in supportedFormats:
+ raise ValueError(["Unsupported image format %s" % format])
+
+ def create_template(self, template, templatedir,
+ connect=None, format=None):
+ # FIXME Force qcow2 format: do we really want people to mess with that?
+ if not os.path.exists(templatedir):
+ os.makedirs(templatedir)
+
+ # Get the image using virt-builder
+ templatename = self._get_template_name(template)
+ imagepath_original = "%s/%s-original.qcow2" % (templatedir,
templatename)
+ imagepath = "%s/%s.%s" % (templatedir, templatename, format)
+ cmd = ["virt-builder", templatename,
+ "-o", imagepath_original, "--format",
"qcow2"]
+ subprocess.call(cmd)
+
+ # We need to convert this image into a single partition one.
+ tarfile = "%s/%s.tar" % (templatedir, templatename)
+ cmd = ["virt-tar-out", "-a", imagepath_original,
"/", tarfile]
+ subprocess.call(cmd)
+
+ os.unlink(imagepath_original)
+
+ cmd = ["qemu-img", "create", "-q", "-f",
format, imagepath, "10G"]
+ subprocess.call(cmd)
+
+ self.format_disk(imagepath, format, connect)
+ self._extract_tarball(imagepath, format, tarfile, connect)
+ os.unlink(tarfile)
+
+
+ def delete_template(self, template, templatedir):
+ # Check for running sandboxes using this template before killing it
+ images = self._get_template_uses(template, templatedir)
+ if len(images) != 0:
+ imagesStr = ", ".join(images)
+ raise ValueError(["Images still using the template: %s" %
imagesStr])
+
+ os.unlink("%s/%s.qcow2" % (templatedir,
self._get_template_name(template)))
+ os.unlink("%s/%s.uses" % (templatedir,
self._get_template_name(template)))
+
+ def _get_template_uses(self, template, templatedir):
+ uses = open("%s/%s.uses" % (templatedir,
self._get_template_name(template)), "r")
+ lines = uses.read()
+ uses.close()
+ return [l for l in lines.split("\n") if l != ""]
+
+ def post_run(self, template, templatedir, imagename):
+ images = self._get_template_uses(template, templatedir)
+ images.remove(imagename)
+
+ uses = open("%s/%s.uses" % (templatedir,
self._get_template_name(template)), "w")
+ uses.write("\n".join(images))
+ uses.close()
+
+ def get_command(self, template, templatedir, userargs):
+ return userargs
+
+ def get_disk(self,template, templatedir, imagedir, sandboxname):
+ diskfile = "%s/%s.qcow2" % (templatedir,
self._get_template_name(template))
+ tempfile = imagedir + "/" + sandboxname + ".qcow2"
+ if not os.path.exists(imagedir):
+ os.makedirs(imagedir)
+ cmd = ["qemu-img", "create", "-q",
+ "-f", "qcow2",
+ "-o", "backing_fmt=qcow2,backing_file=%s" % diskfile,
+ tempfile]
+ subprocess.call(cmd)
+
+ # Add the image to the uses files
+ uses = open("%s/%s.uses" % (templatedir,
+ self._get_template_name(template)), "a")
+ uses.write("%s\n" % sandboxname)
+ uses.close()
+ return tempfile
+
+ def get_env(self,template, templatedir):
+ return []
+
+ def _extract_tarball(self, diskfile, format, tarfile, connect):
+ cmd = ['virt-sandbox']
+ if connect is not None:
+ cmd.append("-c")
+ cmd.append(connect)
+ cmd.append("-p")
+ params = ['-m',
+ 'host-image:/mnt=%s,format=%s' % (diskfile, format),
+ '--',
+ '/bin/tar',
+ 'xf',
+ '%s' % tarfile,
+ '-C',
+ '/mnt']
+ cmd = cmd + params
+ subprocess.call(cmd)
diff --git a/libvirt-sandbox/image/template.py b/libvirt-sandbox/image/template.py
index 4713b0a..efdd845 100644
--- a/libvirt-sandbox/image/template.py
+++ b/libvirt-sandbox/image/template.py
@@ -43,6 +43,8 @@ class Template(object):
docker:///ubuntu
docker+https://index.docker.io/ubuntu?tag=latest
+
+ virt-builder:///fedora-20
"""
self.source = source
--
2.1.4