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(a)redhat.com>
---
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