[libvirt] [PATCH sandbox 23/24] docker: add support for v2 registry server

Daniel P. Berrange berrange at redhat.com
Fri Jul 15 13:08:15 UTC 2016


Many images are no longer available to download the via
v1 registry server. Implement the v2 registry server
protocol, in combination with the v2.1 metadata file
format.

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 libvirt-sandbox/image/sources/docker.py | 61 +++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/libvirt-sandbox/image/sources/docker.py b/libvirt-sandbox/image/sources/docker.py
index cc8d05b..291a305 100644
--- a/libvirt-sandbox/image/sources/docker.py
+++ b/libvirt-sandbox/image/sources/docker.py
@@ -217,6 +217,17 @@ class DockerRegistry():
     def set_auth_handler(self, auth_handler):
         self.auth_handler = auth_handler
 
+    def supports_v2(self):
+        try:
+            (data, res) = self.get_json("/v2/")
+            ver = res.info().getheader("Docker-Distribution-Api-Version")
+        except urllib2.HTTPError as e:
+            ver = e.headers.get("Docker-Distribution-Api-Version", None)
+
+        if ver is None:
+            return False
+        return ver.startswith("registry/2")
+
     def set_server(self, server):
         self.uri_base[1] = server
 
@@ -381,6 +392,13 @@ class DockerSource(base.Source):
         self._check_cert_validate()
 
         registry = DockerRegistry.from_template(template)
+        registry.set_auth_handler(DockerAuthBearer())
+        if registry.supports_v2():
+            self._download_template_impl_v2(registry, image, template, templatedir, createdFiles, createdDirs)
+        else:
+            self._download_template_impl_v1(registry, image, template, templatedir, createdFiles, createdDirs)
+
+    def _download_template_impl_v1(self, registry, image, template, templatedir, createdFiles, createdDirs):
         basicauth = DockerAuthBasic(template.username, template.password)
         registry.set_auth_handler(basicauth)
         try:
@@ -440,6 +458,49 @@ class DockerSource(base.Source):
         with open(indexfile, "w") as f:
             f.write(json.dumps(index))
 
+
+    def _download_template_impl_v2(self, registry, image, template, templatedir, createdFiles, createdDirs):
+        (manifest, res) = registry.get_json( "/v2/%s/%s/manifests/%s" % (
+            image.repo, image.name, image.tag))
+
+        layerChecksums = [
+            layer["blobSum"] for layer in manifest["fsLayers"]
+        ]
+        layers = [
+            json.loads(entry["v1Compatibility"]) for entry in manifest["history"]
+        ]
+
+        for i in range(len(layerChecksums)):
+            layerChecksum = layerChecksums[i]
+            config = layers[i]
+
+            layerdir = templatedir + "/" + config["id"]
+            if not os.path.exists(layerdir):
+                os.makedirs(layerdir)
+                createdDirs.append(layerdir)
+
+            jsonfile = layerdir + "/template.json"
+            datafile = layerdir + "/template.tar.gz"
+
+            with open(jsonfile, "w") as fh:
+                fh.write(json.dumps(config))
+
+            registry.save_data("/v2/%s/%s/blobs/%s" % (
+                                   image.repo, image.name, layerChecksum),
+                               datafile, checksum=layerChecksum)
+
+
+        index = {
+            "repo": image.repo,
+            "name": image.name,
+            "tag": image.tag,
+        }
+
+        indexfile = templatedir + "/" + layers[0]["id"] + "/index.json"
+        with open(indexfile, "w") as f:
+            f.write(json.dumps(index))
+
+
     def create_template(self, template, templatedir, connect=None):
         image = DockerImage.from_template(template)
 
-- 
2.7.4




More information about the libvir-list mailing list