On Fri, 2016-07-15 at 14:08 +0100, Daniel P. Berrange wrote: > Introduce a command able to list locally stored image > templates: > > $ virt-sandbox-image list > docker:library/ubuntu?tag=14.04.1 > docker:library/ubuntu?tag=14.04.2 > virt-builder:/fedora-23 > > or restrict to a single source type > > $ virt-sandbox-image list --source docker > docker:library/ubuntu?tag=14.04.1 > docker:library/ubuntu?tag=14.04.2 > > Signed-off-by: Daniel P. Berrange <berrange@xxxxxxxxxx> > --- > libvirt-sandbox/image/cli.py | 24 ++++++++++++++++++++++ > libvirt-sandbox/image/sources/base.py | 10 ++++++++++ > libvirt-sandbox/image/sources/docker.py | 22 ++++++++++++++++++++ > libvirt-sandbox/image/sources/virtbuilder.py | 18 +++++++++++++++++ > libvirt-sandbox/image/template.py | 30 +++++++++++++++++++--------- > 5 files changed, 95 insertions(+), 9 deletions(-) > > diff --git a/libvirt-sandbox/image/cli.py b/libvirt-sandbox/image/cli.py > index b0d864f..66854e4 100644 > --- a/libvirt-sandbox/image/cli.py > +++ b/libvirt-sandbox/image/cli.py > @@ -135,6 +135,18 @@ def run(args): > os.unlink(diskfile) > source.post_run(tmpl, template_dir, name) > > +def list_cached(args): > + tmpls = [] > + if args.source is not None: > + tmpls.extend(template.Template.get_all(args.source, > + "%s/%s" % (args.template_dir, args.source))) > + else: > + for source in ["docker", "virt-builder"]: > + tmpls.extend(template.Template.get_all(source, > + "%s/%s" % (args.template_dir, source))) > + for tmpl in tmpls: > + print tmpl > + > def requires_template(parser): > parser.add_argument("template", > help=_("URI of the template")) > @@ -221,6 +233,17 @@ def gen_run_args(subparser): > > parser.set_defaults(func=run) > > +def gen_list_args(subparser): > + parser = gen_command_parser(subparser, "list", > + _("List locally cached images")) > + requires_debug(parser) > + requires_template_dir(parser) > + > + parser.add_argument("-s","--source", > + help=_("Name of the template source")) > + > + parser.set_defaults(func=list_cached) > + > def main(): > parser = argparse.ArgumentParser(description="Sandbox Container Image Tool") > > @@ -228,6 +251,7 @@ def main(): > gen_delete_args(subparser) > gen_create_args(subparser) > gen_run_args(subparser) > + gen_list_args(subparser) > > args = parser.parse_args() > if args.debug: > diff --git a/libvirt-sandbox/image/sources/base.py b/libvirt-sandbox/image/sources/base.py > index f70551d..e4e4e41 100644 > --- a/libvirt-sandbox/image/sources/base.py > +++ b/libvirt-sandbox/image/sources/base.py > @@ -34,6 +34,16 @@ class Source(): > def __init__(self): > pass > > + @abstractmethod > + def list_templates(self, templatedir): > + """ > + :param templatedir: local directory path in which to store the template > + > + Get a list of all templates that are locally cached > + > + :returns: a list of libvirt_sandbox.template.Template objects > + """ > + pass > > @abstractmethod > def has_template(self, template, templatedir): > diff --git a/libvirt-sandbox/image/sources/docker.py b/libvirt-sandbox/image/sources/docker.py > index 291a305..dd72db7 100644 > --- a/libvirt-sandbox/image/sources/docker.py > +++ b/libvirt-sandbox/image/sources/docker.py > @@ -32,6 +32,7 @@ import urlparse > import hashlib > from abc import ABCMeta, abstractmethod > import copy > +from libvirt_sandbox.image.template import Template > > from . import base > > @@ -360,6 +361,27 @@ class DockerSource(base.Source): > except Exception: > return False > > + def list_templates(self, templatedir): > + indexes = [] > + imagedirs = os.listdir(templatedir) > + for imagetagid in imagedirs: > + indexfile = templatedir + "/" + imagetagid + "/index.json" > + if os.path.exists(indexfile): > + with open(indexfile,"r") as f: > + index = json.load(f) > + indexes.append(index) > + > + return [ > + Template(source="docker", > + protocol=None, > + hostname=None, > + port=None, > + username=None, > + password=None, > + path="/%s/%s" % (index.get("repo", "library"), index["name"]), > + params={ > + "tag": index.get("tag", "latest"), > + }) for index in indexes] > > def has_template(self, template, templatedir): > try: > diff --git a/libvirt-sandbox/image/sources/virtbuilder.py b/libvirt-sandbox/image/sources/virtbuilder.py > index 6e71b36..fefe0dd 100644 > --- a/libvirt-sandbox/image/sources/virtbuilder.py > +++ b/libvirt-sandbox/image/sources/virtbuilder.py > @@ -24,6 +24,7 @@ import os.path > import subprocess > > from . import base > +from libvirt_sandbox.image.template import Template > > > class VirtBuilderSource(base.Source): > @@ -65,6 +66,23 @@ class VirtBuilderSource(base.Source): > os.unlink(imagepath_original) > os.unlink(tarfile) > > + def list_templates(self, templatedir): > + files = [] > + imagefiles = os.listdir(templatedir) > + for filename in imagefiles: > + if not filename.endswith(".qcow2"): > + continue > + files.append(filename[0:-6]) > + > + return [ > + Template(source="virt-builder", > + protocol=None, > + hostname=None, > + port=None, > + username=None, > + password=None, > + path="/%s" % filename, > + params={}) for filename in files] > > def delete_template(self, template, templatedir): > os.unlink("%s/%s.qcow2" % (templatedir, self._get_template_name(template))) > diff --git a/libvirt-sandbox/image/template.py b/libvirt-sandbox/image/template.py > index 751cd4b..79dc33d 100644 > --- a/libvirt-sandbox/image/template.py > +++ b/libvirt-sandbox/image/template.py > @@ -58,22 +58,27 @@ class Template(object): > if self.params is None: > self.params = {} > > - def get_source_impl(self): > - if self.source == "": > - raise Exception("Missing scheme in image URI") > - > + @classmethod > + def _get_source_impl(klass, source): > try: > p = re.compile("\W") > - sourcemod = "".join(p.split(self.source)) > - sourcename = "".join([i.capitalize() for i in p.split(self.source)]) > + sourcemod = "".join(p.split(source)) > + sourcename = "".join([i.capitalize() for i in p.split(source)]) > > mod = importlib.import_module( > "libvirt_sandbox.image.sources." + sourcemod) > classname = sourcename + "Source" > classimpl = getattr(mod, classname) > return classimpl() > - except Exception: > - raise Exception("Invalid source: '%s'" % self.source) > + except Exception as e: > + print e > + raise Exception("Invalid source: '%s'" % source) > + > + def get_source_impl(self): > + if self.source == "": > + raise Exception("Missing scheme in image URI") > + > + return self._get_source_impl(self.source) > > def __repr__(self): > if self.protocol is not None: > @@ -96,7 +101,8 @@ class Template(object): > netloc = None > > query = "&".join([key + "=" + self.params[key] for key in self.params.keys()]) > - return urlparse.urlunparse((scheme, netloc, self.path, None, query, None)) > + ret = urlparse.urlunparse((scheme, netloc, self.path, None, query, None)) > + return ret > > @classmethod > def from_uri(klass, uri): > @@ -119,3 +125,9 @@ class Template(object): > o.hostname, o.port, > o.username, o.password, > o.path, query) > + > + @classmethod > + def get_all(klass, source, templatedir): > + impl = klass._get_source_impl(source) > + > + return impl.list_templates(templatedir) The whole series looks good to me. ACK. -- Cedric -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list