[libvirt] [sandbox v2 0/5] virt-builder source for virt-sandbox-image

Hi all, Here is the new version of the virt-builder source with the download command removed and the format parameter too. Cédric Bosdonnat (5): virt-sandbox-image: remove the download command virt-image-sandbox: tarball extracting function to be reusable virt-sandbox-image: remove the format parameter virt-sandbox-image: automatically call create if needed virt-sandbox-image: add a virt-builder source libvirt-sandbox.spec.in | 1 + libvirt-sandbox/image/cli.py | 29 +++----- libvirt-sandbox/image/sources/DockerSource.py | 61 ++++++++-------- libvirt-sandbox/image/sources/Makefile.am | 1 + libvirt-sandbox/image/sources/Source.py | 29 ++++++-- libvirt-sandbox/image/sources/VirtBuilderSource.py | 84 ++++++++++++++++++++++ libvirt-sandbox/image/template.py | 2 + 7 files changed, 149 insertions(+), 58 deletions(-) create mode 100644 libvirt-sandbox/image/sources/VirtBuilderSource.py -- 2.1.4

The download command is now merged with the create one. There is no real reason to keep those two separate. --- libvirt-sandbox/image/cli.py | 14 -------------- libvirt-sandbox/image/sources/DockerSource.py | 3 +++ libvirt-sandbox/image/sources/Source.py | 11 ----------- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/libvirt-sandbox/image/cli.py b/libvirt-sandbox/image/cli.py index a43da62..4500713 100755 --- a/libvirt-sandbox/image/cli.py +++ b/libvirt-sandbox/image/cli.py @@ -64,12 +64,6 @@ def debug(msg): def info(msg): sys.stdout.write(msg) -def download(args): - tmpl = template.Template.from_uri(args.template) - source = tmpl.get_source_impl() - source.download_template(template=tmpl, - templatedir=args.template_dir) - def delete(args): tmpl = template.Template.from_uri(args.template) source = tmpl.get_source_impl() @@ -178,13 +172,6 @@ Example supported URI formats: """) return parser -def gen_download_args(subparser): - parser = gen_command_parser(subparser, "download", - _("Download template data")) - requires_template(parser) - requires_template_dir(parser) - parser.set_defaults(func=download) - def gen_delete_args(subparser): parser = gen_command_parser(subparser, "delete", _("Delete template data")) @@ -225,7 +212,6 @@ def main(): parser = argparse.ArgumentParser(description="Sandbox Container Image Tool") subparser = parser.add_subparsers(help=_("commands")) - gen_download_args(subparser) gen_delete_args(subparser) gen_create_args(subparser) gen_run_args(subparser) diff --git a/libvirt-sandbox/image/sources/DockerSource.py b/libvirt-sandbox/image/sources/DockerSource.py index 41df7a7..93d7f17 100644 --- a/libvirt-sandbox/image/sources/DockerSource.py +++ b/libvirt-sandbox/image/sources/DockerSource.py @@ -245,6 +245,9 @@ class DockerSource(Source): if format is None: format = "qcow2" self._check_disk_format(format) + + self.download_template(template, templatedir) + imagelist = self._get_image_list(template, templatedir) imagelist.reverse() diff --git a/libvirt-sandbox/image/sources/Source.py b/libvirt-sandbox/image/sources/Source.py index 444baa3..708f2aa 100644 --- a/libvirt-sandbox/image/sources/Source.py +++ b/libvirt-sandbox/image/sources/Source.py @@ -35,17 +35,6 @@ class Source(): pass @abstractmethod - def download_template(self, template, templatedir): - """ - :param template: libvirt_sandbox.template.Template object - :param templatedir: local directory path in which to store the template - - Download a template from the registry, storing it in the local - filesystem - """ - pass - - @abstractmethod def create_template(self, template, templatedir, connect=None, format=None): """ -- 2.1.4

On Mon, Oct 05, 2015 at 04:37:55PM +0200, Cédric Bosdonnat wrote:
The download command is now merged with the create one. There is no real reason to keep those two separate. --- libvirt-sandbox/image/cli.py | 14 -------------- libvirt-sandbox/image/sources/DockerSource.py | 3 +++ libvirt-sandbox/image/sources/Source.py | 11 ----------- 3 files changed, 3 insertions(+), 25 deletions(-)
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

The virt-builder source will need this function too, let's move it to the Source abstraction for reusability. Note that the function now checks for tarball filename to end with ".gz" to add the proper tar option. --- libvirt-sandbox/image/sources/DockerSource.py | 25 +++++-------------------- libvirt-sandbox/image/sources/Source.py | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/libvirt-sandbox/image/sources/DockerSource.py b/libvirt-sandbox/image/sources/DockerSource.py index 93d7f17..0d76717 100644 --- a/libvirt-sandbox/image/sources/DockerSource.py +++ b/libvirt-sandbox/image/sources/DockerSource.py @@ -266,7 +266,11 @@ class DockerSource(Source): if parentImage is None: self.format_disk(templateImage,format,connect) - self._extract_tarballs(templatedir + "/" + imagetagid + "/template.",format,connect) + path = templatedir + "/" + imagetagid + "/template." + self.extract_tarball(path + "qcow2", + format, + path + "tar.gz", + connect) parentImage = templateImage @@ -302,25 +306,6 @@ class DockerSource(Source): imagetagid = parent return imagelist - def _extract_tarballs(self,directory,format,connect): - tarfile = directory + "tar.gz" - diskfile = directory + "qcow2" - 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', - 'zxf', - '%s' %tarfile, - '-C', - '/mnt'] - cmd = cmd + params - subprocess.call(cmd) - def delete_template(self, template, templatedir): imageusage = {} imageparent = {} diff --git a/libvirt-sandbox/image/sources/Source.py b/libvirt-sandbox/image/sources/Source.py index 708f2aa..15737c1 100644 --- a/libvirt-sandbox/image/sources/Source.py +++ b/libvirt-sandbox/image/sources/Source.py @@ -119,3 +119,23 @@ class Source(): '/dev/disk/by-tag/disk_image'] cmd = cmd + params subprocess.call(cmd) + + 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") + compression = "" + if tarfile.endswith(".gz"): + compression = "z" + params = ['-m', + 'host-image:/mnt=%s,format=%s' % (diskfile, format), + '--', + '/bin/tar', + 'xf%s' % compression, + '%s' % tarfile, + '-C', + '/mnt'] + cmd = cmd + params + subprocess.call(cmd) -- 2.1.4

On Mon, Oct 05, 2015 at 04:37:56PM +0200, Cédric Bosdonnat wrote:
The virt-builder source will need this function too, let's move it to the Source abstraction for reusability. Note that the function now checks for tarball filename to end with ".gz" to add the proper tar option. --- libvirt-sandbox/image/sources/DockerSource.py | 25 +++++-------------------- libvirt-sandbox/image/sources/Source.py | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 20 deletions(-)
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

The format parameter isn't used so far and would only be misleading users. Removing it for the while, but may be reintroduced later when adding storage backend support. --- libvirt-sandbox/image/cli.py | 9 ++------- libvirt-sandbox/image/sources/DockerSource.py | 18 ++++-------------- libvirt-sandbox/image/sources/Source.py | 3 +-- 3 files changed, 7 insertions(+), 23 deletions(-) diff --git a/libvirt-sandbox/image/cli.py b/libvirt-sandbox/image/cli.py index 4500713..f067347 100755 --- a/libvirt-sandbox/image/cli.py +++ b/libvirt-sandbox/image/cli.py @@ -75,8 +75,7 @@ def create(args): source = tmpl.get_source_impl() source.create_template(template=tmpl, templatedir=args.template_dir, - connect=args.connect, - format=args.format) + connect=args.connect) def run(args): if args.connect is not None: @@ -95,7 +94,6 @@ def run(args): imagedir=args.image_dir, sandboxname=name) - format = "qcow2" commandToRun = source.get_command(tmpl, args.template_dir, args.args) if len(commandToRun) == 0: commandToRun = ["/bin/sh"] @@ -103,7 +101,7 @@ def run(args): if args.connect is not None: cmd.append("-c") cmd.append(args.connect) - params = ['-m','host-image:/=%s,format=%s' %(diskfile,format)] + params = ['-m','host-image:/=%s,format=qcow2' % diskfile] networkArgs = args.network if networkArgs is not None: @@ -185,9 +183,6 @@ def gen_create_args(subparser): requires_template(parser) requires_connect(parser) requires_template_dir(parser) - parser.add_argument("-f","--format", - default="qcow2", - help=_("format format for image")) parser.set_defaults(func=create) def gen_run_args(subparser): diff --git a/libvirt-sandbox/image/sources/DockerSource.py b/libvirt-sandbox/image/sources/DockerSource.py index 0d76717..1f6f94f 100644 --- a/libvirt-sandbox/image/sources/DockerSource.py +++ b/libvirt-sandbox/image/sources/DockerSource.py @@ -241,11 +241,7 @@ class DockerSource(Source): debug("FAIL %s\n" % str(e)) raise - def create_template(self, template, templatedir, connect=None, format=None): - if format is None: - format = "qcow2" - self._check_disk_format(format) - + def create_template(self, template, templatedir, connect=None): self.download_template(template, templatedir) imagelist = self._get_image_list(template, templatedir) @@ -253,7 +249,7 @@ class DockerSource(Source): parentImage = None for imagetagid in imagelist: - templateImage = templatedir + "/" + imagetagid + "/template." + format + templateImage = templatedir + "/" + imagetagid + "/template.qcow2" cmd = ["qemu-img","create","-f","qcow2"] if parentImage is not None: cmd.append("-o") @@ -264,21 +260,15 @@ class DockerSource(Source): subprocess.call(cmd) if parentImage is None: - self.format_disk(templateImage,format,connect) + self.format_disk(templateImage, "qcow2", connect) path = templatedir + "/" + imagetagid + "/template." self.extract_tarball(path + "qcow2", - format, + "qcow2", path + "tar.gz", connect) parentImage = templateImage - - def _check_disk_format(self,format): - supportedFormats = ['qcow2'] - if not format in supportedFormats: - raise ValueError(["Unsupported image format %s" % format]) - def _get_image_list(self, template, destdir): imageparent = {} imagenames = {} diff --git a/libvirt-sandbox/image/sources/Source.py b/libvirt-sandbox/image/sources/Source.py index 15737c1..a31bab8 100644 --- a/libvirt-sandbox/image/sources/Source.py +++ b/libvirt-sandbox/image/sources/Source.py @@ -36,12 +36,11 @@ class Source(): @abstractmethod def create_template(self, template, templatedir, - connect=None, format=None): + connect=None): """ :param template: libvirt_sandbox.template.Template object :param templatedir: local directory path in which to store the template :param connect: libvirt connection URI - :param format: disk image format Create a set of local disk images populated with the content of a template. The images creation process will be isolated -- 2.1.4

On Mon, Oct 05, 2015 at 04:37:57PM +0200, Cédric Bosdonnat wrote:
The format parameter isn't used so far and would only be misleading users. Removing it for the while, but may be reintroduced later when adding storage backend support. --- libvirt-sandbox/image/cli.py | 9 ++------- libvirt-sandbox/image/sources/DockerSource.py | 18 ++++-------------- libvirt-sandbox/image/sources/Source.py | 3 +-- 3 files changed, 7 insertions(+), 23 deletions(-)
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

To provide a smooth user experience, run automatically calls create if needed. --- libvirt-sandbox/image/cli.py | 5 +++++ libvirt-sandbox/image/sources/DockerSource.py | 19 +++++++++++++++++++ libvirt-sandbox/image/sources/Source.py | 11 +++++++++++ 3 files changed, 35 insertions(+) diff --git a/libvirt-sandbox/image/cli.py b/libvirt-sandbox/image/cli.py index f067347..05d593a 100755 --- a/libvirt-sandbox/image/cli.py +++ b/libvirt-sandbox/image/cli.py @@ -42,6 +42,7 @@ if os.geteuid() == 0: else: default_template_dir = os.environ['HOME'] + "/.local/share/libvirt/templates" default_image_dir = os.environ['HOME'] + "/.local/share/libvirt/images" +default_format = "qcow2" debug = False verbose = False @@ -84,6 +85,10 @@ def run(args): tmpl = template.Template.from_uri(args.template) source = tmpl.get_source_impl() + # Create the template image if needed + if not source.has_template(tmpl, args.template_dir): + create(args) + name = args.name if name is None: randomid = ''.join(random.choice(string.lowercase) for i in range(10)) diff --git a/libvirt-sandbox/image/sources/DockerSource.py b/libvirt-sandbox/image/sources/DockerSource.py index 1f6f94f..fb21bda 100644 --- a/libvirt-sandbox/image/sources/DockerSource.py +++ b/libvirt-sandbox/image/sources/DockerSource.py @@ -59,6 +59,22 @@ class DockerSource(Source): if (major == 2 and sys.hexversion < py2_7_9_hexversion) or (major == 3 and sys.hexversion < py3_4_3_hexversion): sys.stderr.write(SSL_WARNING) + def _was_downloaded(self, template, templatedir): + try: + self._get_image_list(template, templatedir) + return True + except Exception: + return False + + + def has_template(self, template, templatedir): + try: + configfile, diskfile = self._get_template_data(template, templatedir) + return os.path.exists(diskfile) + except Exception: + return False + + def download_template(self, template, templatedir): self._check_cert_validate() @@ -244,6 +260,9 @@ class DockerSource(Source): def create_template(self, template, templatedir, connect=None): self.download_template(template, templatedir) + if not self._was_downloaded(template, templatedir): + self.download_template(template, templatedir) + imagelist = self._get_image_list(template, templatedir) imagelist.reverse() diff --git a/libvirt-sandbox/image/sources/Source.py b/libvirt-sandbox/image/sources/Source.py index a31bab8..8f6ccba 100644 --- a/libvirt-sandbox/image/sources/Source.py +++ b/libvirt-sandbox/image/sources/Source.py @@ -34,6 +34,17 @@ class Source(): def __init__(self): pass + + @abstractmethod + def has_template(self, template, templatedir): + """ + :param template: libvirt_sandbox.template.Template object + :param templatedir: local directory path in which to store the template + + Check if a template has already been created. + """ + pass + @abstractmethod def create_template(self, template, templatedir, connect=None): -- 2.1.4

On Mon, Oct 05, 2015 at 04:37:58PM +0200, Cédric Bosdonnat wrote:
To provide a smooth user experience, run automatically calls create if needed. --- libvirt-sandbox/image/cli.py | 5 +++++ libvirt-sandbox/image/sources/DockerSource.py | 19 +++++++++++++++++++ libvirt-sandbox/image/sources/Source.py | 11 +++++++++++ 3 files changed, 35 insertions(+)
diff --git a/libvirt-sandbox/image/cli.py b/libvirt-sandbox/image/cli.py index f067347..05d593a 100755 --- a/libvirt-sandbox/image/cli.py +++ b/libvirt-sandbox/image/cli.py @@ -42,6 +42,7 @@ if os.geteuid() == 0: else: default_template_dir = os.environ['HOME'] + "/.local/share/libvirt/templates" default_image_dir = os.environ['HOME'] + "/.local/share/libvirt/images" +default_format = "qcow2"
Left over from a previous version I presume. ACK with that removed. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

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 | 84 ++++++++++++++++++++++ libvirt-sandbox/image/template.py | 2 + 5 files changed, 89 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 05d593a..f7fa8ee 100755 --- a/libvirt-sandbox/image/cli.py +++ b/libvirt-sandbox/image/cli.py @@ -172,6 +172,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..3ce1867 --- /dev/null +++ b/libvirt-sandbox/image/sources/VirtBuilderSource.py @@ -0,0 +1,84 @@ +#!/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@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 has_template(self, template, templatedir): + imagepath = "%s/%s.qcow2" % (templatedir, template.path) + return os.path.exists(imagepath) + + def create_template(self, template, templatedir, connect=None): + 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.qcow2" % (templatedir, templatename) + 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", "qcow2", imagepath, "10G"] + subprocess.call(cmd) + + self.format_disk(imagepath, "qcow2", connect) + self.extract_tarball(imagepath, "qcow2", tarfile, connect) + os.unlink(tarfile) + + + def delete_template(self, template, templatedir): + os.unlink("%s/%s.qcow2" % (templatedir, self._get_template_name(template))) + + 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) + return tempfile + + def get_env(self,template, templatedir): + return [] diff --git a/libvirt-sandbox/image/template.py b/libvirt-sandbox/image/template.py index 52d366c..58904a2 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

On Mon, Oct 05, 2015 at 04:37:59PM +0200, Cédric Bosdonnat wrote:
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 | 84 ++++++++++++++++++++++ libvirt-sandbox/image/template.py | 2 + 5 files changed, 89 insertions(+) create mode 100644 libvirt-sandbox/image/sources/VirtBuilderSource.py
+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 has_template(self, template, templatedir): + imagepath = "%s/%s.qcow2" % (templatedir, template.path) + return os.path.exists(imagepath) + + def create_template(self, template, templatedir, connect=None): + 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.qcow2" % (templatedir, templatename) + 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", "qcow2", imagepath, "10G"] + subprocess.call(cmd) + + self.format_disk(imagepath, "qcow2", connect) + self.extract_tarball(imagepath, "qcow2", tarfile, connect) + os.unlink(tarfile)
We should probably wrap the method in a try/finally block, and put the two os.unlink() calls in the finally block so we can guarantee we clean up the intermediate files if an exception is raised. Aside from that it looks fine. It is a shame virt-builder cannot produce a partitionless image straight away for us :-( Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Mon, 2015-10-05 at 16:49 +0100, Daniel P. Berrange wrote:
On Mon, Oct 05, 2015 at 04:37:59PM +0200, Cédric Bosdonnat wrote:
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 | 84 ++++++++++++++++++++++ libvirt-sandbox/image/template.py | 2 + 5 files changed, 89 insertions(+) create mode 100644 libvirt-sandbox/image/sources/VirtBuilderSource.py
+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 has_template(self, template, templatedir): + imagepath = "%s/%s.qcow2" % (templatedir, template.path) + return os.path.exists(imagepath) + + def create_template(self, template, templatedir, connect=None): + 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.qcow2" % (templatedir, templatename) + 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", "qcow2", imagepath, "10G"] + subprocess.call(cmd) + + self.format_disk(imagepath, "qcow2", connect) + self.extract_tarball(imagepath, "qcow2", tarfile, connect) + os.unlink(tarfile)
We should probably wrap the method in a try/finally block, and put the two os.unlink() calls in the finally block so we can guarantee we clean up the intermediate files if an exception is raised.
Aside from that it looks fine. It is a shame virt-builder cannot produce a partitionless image straight away for us :-(
This and the others have been pushed with the changes. -- Cedric
Regards, Daniel
participants (3)
-
Cedric Bosdonnat
-
Cédric Bosdonnat
-
Daniel P. Berrange