libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From anthonys...@apache.org
Subject [40/50] libcloud git commit: refactor the docker hub client to inherit from a registry api client, updated docs with examples and renamed the package to utils
Date Wed, 20 Jan 2016 03:44:28 GMT
refactor the docker hub client to inherit from a registry api client, updated docs with examples and renamed the package to utils


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/d29629de
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/d29629de
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/d29629de

Branch: refs/heads/trunk
Commit: d29629de79d790995d4435e1b5081bb31f3b7b82
Parents: 104cdb1
Author: anthony-shaw <anthony.p.shaw@gmail.com>
Authored: Mon Jan 11 12:59:51 2016 +1100
Committer: anthony-shaw <anthony.p.shaw@gmail.com>
Committed: Mon Jan 11 12:59:51 2016 +1100

----------------------------------------------------------------------
 docs/container/drivers/ecs.rst                  |  12 +-
 docs/container/examples.rst                     |  10 +
 docs/container/utilities.rst                    |   2 +-
 docs/examples/container/docker_hub.py           |  20 +
 libcloud/container/util/__init__.py             |   0
 libcloud/container/util/docker.py               | 137 ---
 libcloud/container/utils/__init__.py            |   0
 libcloud/container/utils/docker.py              | 164 ++++
 .../fixtures/docker/list_tags_ubuntu.json       | 354 -------
 .../v2_repositories_library_ubuntu.json         |  15 +
 .../v2_repositories_library_ubuntu_tags.json    | 975 +++++++++++++++++++
 ...repositories_library_ubuntu_tags_latest.json |  11 +
 libcloud/test/container/test_docker_utils.py    |  86 ++
 libcloud/test/container/test_ecs.py             |   2 +-
 14 files changed, 1294 insertions(+), 494 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/docs/container/drivers/ecs.rst
----------------------------------------------------------------------
diff --git a/docs/container/drivers/ecs.rst b/docs/container/drivers/ecs.rst
index 20ab400..fbde93f 100644
--- a/docs/container/drivers/ecs.rst
+++ b/docs/container/drivers/ecs.rst
@@ -23,7 +23,17 @@ Deploying a container
 
 .. literalinclude:: /examples/container/ecs/deploy_container.py
    :language: python
-   
+
+Deploying a container from Docker Hub
+-------------------------------------
+
+Docker Hub Client :class:`~libcloud.container.utils.docker.HubClient` is a shared utility class for interfacing to the public Docker Hub Service.
+
+You can use this class for fetching images to deploy to services like ECS
+
+.. literalinclude:: /examples/container/docker_hub.py
+   :language: python
+
 API Docs
 --------
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/docs/container/examples.rst
----------------------------------------------------------------------
diff --git a/docs/container/examples.rst b/docs/container/examples.rst
index a4e4316..f35662c 100644
--- a/docs/container/examples.rst
+++ b/docs/container/examples.rst
@@ -20,4 +20,14 @@ Working with cluster supported providers
 This example shows listing the clusters, find a specific named cluster and deploying a container to it.
 
 .. literalinclude:: /examples/container/working_with_clusters.py
+   :language: python
+
+Working with docker hub
+-----------------------
+
+Docker Hub Client :class:`~libcloud.container.utils.docker.HubClient` is a shared utility class for interfacing to the public Docker Hub Service.
+
+You can use this class for fetching images to deploy to services like ECS
+
+.. literalinclude:: /examples/container/docker_hub.py
    :language: python
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/docs/container/utilities.rst
----------------------------------------------------------------------
diff --git a/docs/container/utilities.rst b/docs/container/utilities.rst
index 48aafc2..c2b17e9 100644
--- a/docs/container/utilities.rst
+++ b/docs/container/utilities.rst
@@ -3,5 +3,5 @@
 Container Utility API
 =====================
 
-.. autoclass:: libcloud.container.util.HubClient
+.. autoclass:: libcloud.container.utils.docker.HubClient
     :members:

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/docs/examples/container/docker_hub.py
----------------------------------------------------------------------
diff --git a/docs/examples/container/docker_hub.py b/docs/examples/container/docker_hub.py
new file mode 100644
index 0000000..dd9d1a6
--- /dev/null
+++ b/docs/examples/container/docker_hub.py
@@ -0,0 +1,20 @@
+from libcloud.container.types import Provider
+from libcloud.container.providers import get_driver
+from libcloud.container.utils.docker import HubClient
+
+cls = get_driver(Provider.ECS)
+
+conn = cls(access_id='SDHFISJDIFJSIDFJ',
+           secret='THIS_IS)+_MY_SECRET_KEY+I6TVkv68o4H',
+           region='ap-southeast-2')
+hub = HubClient()
+
+image = hub.get_image('ubuntu', 'latest')
+
+for cluster in conn.list_clusters():
+    print(cluster.name)
+    if cluster.name == 'default':
+        container = conn.deploy_container(
+            cluster=cluster,
+            name='my-simple-app',
+            image=image)

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/libcloud/container/util/__init__.py
----------------------------------------------------------------------
diff --git a/libcloud/container/util/__init__.py b/libcloud/container/util/__init__.py
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/libcloud/container/util/docker.py
----------------------------------------------------------------------
diff --git a/libcloud/container/util/docker.py b/libcloud/container/util/docker.py
deleted file mode 100644
index 3edfec8..0000000
--- a/libcloud/container/util/docker.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import with_statement
-
-from requests.auth import HTTPBasicAuth
-import requests
-
-from libcloud.container.base import ContainerImage
-
-__all__ = [
-    'HubClient'
-]
-
-
-class HubClient(object):
-    """
-    A client for the Docker Hub API
-
-    The hub is based on the v1 registry API
-    """
-    host = 'registry.hub.docker.com'
-    base_url = 'https://%s/' % (host)
-
-    def __init__(self, username=None, password=None):
-        """
-        Construct a Docker hub client
-
-        :param username: (optional) Your Hub account username
-        :type  username: ``str``
-
-        :param password: (optional) Your hub account password
-        :type  password: ``str``
-        """
-        if username is not None:
-            self.auth = HTTPBasicAuth(username, password)
-        else:
-            self.auth = None
-
-    def list_tags(self, repository_name, namespace='library', max_count=100):
-        """
-        List the tags (versions) in a repository
-
-        :param  repository_name: The name of the repository e.g. 'ubuntu'
-        :type   repository_name: ``str``
-
-        :param  namespace: (optional) The docker namespace
-        :type   namespace: ``str``
-
-        :param  max_count: The maximum number of records to return
-        :type   max_count: ``int``
-
-        :return: A list of tags
-        :rtype: ``list`` of ``object``
-        """
-        path = 'v2/repositories/%s/%s/tags/?page=1&page_size=%s' \
-               % (namespace, repository_name, max_count)
-        response = requests.get(self.base_url + path, auth=self.auth)
-        return response.json().results
-
-    def list_image_ids(self, repository_name, namespace='library'):
-        """
-        List the image IDs (versions) in a repository
-
-        :param  repository_name: The name of the repository e.g. 'ubuntu'
-        :type   repository_name: ``str``
-
-        :param  namespace: (optional) The docker namespace
-        :type   namespace: ``str``
-
-        :return: A list of ids
-        :rtype: ``list`` of ``object``
-        """
-        path = 'v1/repositories/%s/%s/images' % (namespace, repository_name)
-        response = requests.get(self.base_url + path, auth=self.auth)
-        return response.json()
-
-    def get_repository(self, repository_name, namespace='library'):
-        """
-        Get the information about a specific repository
-
-        :param  repository_name: The name of the repository e.g. 'ubuntu'
-        :type   repository_name: ``str``
-
-        :param  namespace: (optional) The docker namespace
-        :type   namespace: ``str``
-
-        :return: The details of the repository
-        :rtype: ``object``
-        """
-        path = 'v2/repositories/%s/%s' % (namespace, repository_name)
-        response = requests.get(self.base_url + path, auth=self.auth)
-        return response.json()
-
-    def get_image(self, repository_name, tag='latest', namespace='library'):
-        """
-        Get an image from a repository with a specific tag
-
-        :param repository_name: The name of the repository, e.g. ubuntu
-        :type  repository_name: ``str``
-
-        :param  tag: (optional) The image tag (defaults to latest)
-        :type   tag: ``str``
-
-        :param  namespace: (optional) The docker namespace
-        :type   namespace: ``str``
-
-        :return: A container image
-        :rtype: :class:`libcloud.container.base.ContainerImage`
-        """
-        path = 'v2/repositories/%s/%s/tags/%s' \
-               % (namespace, repository_name, tag)
-        response = requests.get(self.base_url + path, auth=self.auth)
-        obj = response.json()
-        path = '%s/%s:%s' % (self.host, repository_name, tag)
-        return ContainerImage(
-            id=obj['id'],
-            path=path,
-            name=path,
-            version=tag,
-            extra={
-                'full_size': obj['full_size']
-            },
-            driver=None
-        )

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/libcloud/container/utils/__init__.py
----------------------------------------------------------------------
diff --git a/libcloud/container/utils/__init__.py b/libcloud/container/utils/__init__.py
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/libcloud/container/utils/docker.py
----------------------------------------------------------------------
diff --git a/libcloud/container/utils/docker.py b/libcloud/container/utils/docker.py
new file mode 100644
index 0000000..9e9703c
--- /dev/null
+++ b/libcloud/container/utils/docker.py
@@ -0,0 +1,164 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import with_statement
+
+from base64 import b64encode
+
+from libcloud.common.base import Connection, JsonResponse
+from libcloud.container.base import ContainerImage
+
+__all__ = [
+    'RegistryClient',
+    'HubClient'
+]
+
+
+class DockerHubConnection(Connection):
+    responseCls = JsonResponse
+
+    def __init__(self, host, username=None, password=None, **kwargs):
+        super(DockerHubConnection, self).__init__(host=host, **kwargs)
+        self.username = username
+        self.password = password
+
+    def add_default_headers(self, headers):
+        if self.username is not None:
+            authstr = 'Basic ' + str(
+                b64encode(
+                    ('%s:%s' % (self.username,
+                                self.password))
+                    .encode('latin1'))
+                .strip()
+            )
+            headers['Authorization'] = authstr
+        return headers
+
+
+class RegistryClient(object):
+    """
+    A client for the Docker v2 registry API
+    """
+    connectionCls = DockerHubConnection
+
+    def __init__(self, host, username=None, password=None, **kwargs):
+        """
+        Construct a Docker hub client
+
+        :param username: (optional) Your Hub account username
+        :type  username: ``str``
+
+        :param password: (optional) Your hub account password
+        :type  password: ``str``
+        """
+        self.connection = DockerHubConnection(host, username, password, **kwargs)
+
+    def list_images(self, repository_name, namespace='library', max_count=100):
+        """
+        List the tags (versions) in a repository
+
+        :param  repository_name: The name of the repository e.g. 'ubuntu'
+        :type   repository_name: ``str``
+
+        :param  namespace: (optional) The docker namespace
+        :type   namespace: ``str``
+
+        :param  max_count: The maximum number of records to return
+        :type   max_count: ``int``
+
+        :return: A list of images
+        :rtype: ``list`` of :class:`libcloud.container.base.ContainerImage`
+        """
+        path = 'v2/repositories/%s/%s/tags/?page=1&page_size=%s' \
+               % (namespace, repository_name, max_count)
+        response = self.connection.request(path)
+        images = []
+        for image in response.object['results']:
+            images.append(self._to_image(repository_name, image))
+        return images
+
+    def get_repository(self, repository_name, namespace='library'):
+        """
+        Get the information about a specific repository
+
+        :param  repository_name: The name of the repository e.g. 'ubuntu'
+        :type   repository_name: ``str``
+
+        :param  namespace: (optional) The docker namespace
+        :type   namespace: ``str``
+
+        :return: The details of the repository
+        :rtype: ``object``
+        """
+        path = 'v2/repositories/%s/%s' % (namespace, repository_name)
+        response = self.connection.request(path)
+        return response.object
+
+    def get_image(self, repository_name, tag='latest', namespace='library'):
+        """
+        Get an image from a repository with a specific tag
+
+        :param repository_name: The name of the repository, e.g. ubuntu
+        :type  repository_name: ``str``
+
+        :param  tag: (optional) The image tag (defaults to latest)
+        :type   tag: ``str``
+
+        :param  namespace: (optional) The docker namespace
+        :type   namespace: ``str``
+
+        :return: A container image
+        :rtype: :class:`libcloud.container.base.ContainerImage`
+        """
+        path = 'v2/repositories/%s/%s/tags/%s' \
+               % (namespace, repository_name, tag)
+        response = self.connection.request(path)
+        return self._to_image(repository_name, response.object)
+
+    def _to_image(self, repository_name, obj):
+        path = '%s/%s:%s' % (self.connection.host,
+                             repository_name,
+                             obj['name'])
+        return ContainerImage(
+            id=obj['id'],
+            path=path,
+            name=path,
+            version=obj['name'],
+            extra={
+                'full_size': obj['full_size']
+            },
+            driver=None
+        )
+
+
+class HubClient(RegistryClient):
+    """
+    A client for the Docker Hub API
+
+    The hub is based on the v2 registry API
+    """
+    host = 'registry.hub.docker.com'
+
+    def __init__(self, username=None, password=None, **kwargs):
+        """
+        Construct a Docker hub client
+
+        :param username: (optional) Your Hub account username
+        :type  username: ``str``
+
+        :param password: (optional) Your hub account password
+        :type  password: ``str``
+        """
+        self.connection = DockerHubConnection(self.host, username, password, **kwargs)

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/libcloud/test/container/fixtures/docker/list_tags_ubuntu.json
----------------------------------------------------------------------
diff --git a/libcloud/test/container/fixtures/docker/list_tags_ubuntu.json b/libcloud/test/container/fixtures/docker/list_tags_ubuntu.json
deleted file mode 100644
index 2786d5c..0000000
--- a/libcloud/test/container/fixtures/docker/list_tags_ubuntu.json
+++ /dev/null
@@ -1,354 +0,0 @@
-[
-  {
-    "layer": "af88597e",
-    "name": "latest"
-  },
-  {
-    "layer": "3db9c44f",
-    "name": "10.04"
-  },
-  {
-    "layer": "bad926a6",
-    "name": "12.04"
-  },
-  {
-    "layer": "bad926a6",
-    "name": "12.04.5"
-  },
-  {
-    "layer": "c5881f11",
-    "name": "12.10"
-  },
-  {
-    "layer": "463ff6be",
-    "name": "13.04"
-  },
-  {
-    "layer": "195eb90b",
-    "name": "13.10"
-  },
-  {
-    "layer": "af88597e",
-    "name": "14.04"
-  },
-  {
-    "layer": "5ba9dab4",
-    "name": "14.04.1"
-  },
-  {
-    "layer": "63e3c102",
-    "name": "14.04.2"
-  },
-  {
-    "layer": "af88597e",
-    "name": "14.04.3"
-  },
-  {
-    "layer": "dce38fb5",
-    "name": "14.10"
-  },
-  {
-    "layer": "3f0d2d4f",
-    "name": "15.04"
-  },
-  {
-    "layer": "3e0c71ad",
-    "name": "15.10"
-  },
-  {
-    "layer": "db856b41",
-    "name": "16.04"
-  },
-  {
-    "layer": "3db9c44f",
-    "name": "lucid"
-  },
-  {
-    "layer": "bad926a6",
-    "name": "precise"
-  },
-  {
-    "layer": "1f80e9ca",
-    "name": "precise-20150212"
-  },
-  {
-    "layer": "5898adab",
-    "name": "precise-20150228.11"
-  },
-  {
-    "layer": "9610cfc6",
-    "name": "precise-20150320"
-  },
-  {
-    "layer": "ac6b0eaa",
-    "name": "precise-20150427"
-  },
-  {
-    "layer": "5c97af89",
-    "name": "precise-20150528"
-  },
-  {
-    "layer": "78cef618",
-    "name": "precise-20150612"
-  },
-  {
-    "layer": "6d021018",
-    "name": "precise-20150626"
-  },
-  {
-    "layer": "d0e008c6",
-    "name": "precise-20150729"
-  },
-  {
-    "layer": "57bca513",
-    "name": "precise-20150813"
-  },
-  {
-    "layer": "61994089",
-    "name": "precise-20150924"
-  },
-  {
-    "layer": "0ac5b09d",
-    "name": "precise-20151020"
-  },
-  {
-    "layer": "04c3793b",
-    "name": "precise-20151028"
-  },
-  {
-    "layer": "bad926a6",
-    "name": "precise-20151208"
-  },
-  {
-    "layer": "c5881f11",
-    "name": "quantal"
-  },
-  {
-    "layer": "463ff6be",
-    "name": "raring"
-  },
-  {
-    "layer": "195eb90b",
-    "name": "saucy"
-  },
-  {
-    "layer": "af88597e",
-    "name": "trusty"
-  },
-  {
-    "layer": "2d24f826",
-    "name": "trusty-20150218.1"
-  },
-  {
-    "layer": "2103b00b",
-    "name": "trusty-20150228.11"
-  },
-  {
-    "layer": "b7cf8f0d",
-    "name": "trusty-20150320"
-  },
-  {
-    "layer": "07f8e8c5",
-    "name": "trusty-20150427"
-  },
-  {
-    "layer": "fa81ed08",
-    "name": "trusty-20150528"
-  },
-  {
-    "layer": "6d494699",
-    "name": "trusty-20150612"
-  },
-  {
-    "layer": "d2a0ecff",
-    "name": "trusty-20150630"
-  },
-  {
-    "layer": "63e3c102",
-    "name": "trusty-20150730"
-  },
-  {
-    "layer": "8251da35",
-    "name": "trusty-20150806"
-  },
-  {
-    "layer": "91e54dfb",
-    "name": "trusty-20150814"
-  },
-  {
-    "layer": "cdd47452",
-    "name": "trusty-20151001"
-  },
-  {
-    "layer": "a005e6b7",
-    "name": "trusty-20151009"
-  },
-  {
-    "layer": "a5a467fd",
-    "name": "trusty-20151021"
-  },
-  {
-    "layer": "ca4d7b1b",
-    "name": "trusty-20151028"
-  },
-  {
-    "layer": "d55e68e6",
-    "name": "trusty-20151208"
-  },
-  {
-    "layer": "af88597e",
-    "name": "trusty-20151218"
-  },
-  {
-    "layer": "dce38fb5",
-    "name": "utopic"
-  },
-  {
-    "layer": "78949b1e",
-    "name": "utopic-20150211"
-  },
-  {
-    "layer": "525b6e4a",
-    "name": "utopic-20150228.11"
-  },
-  {
-    "layer": "59a878f2",
-    "name": "utopic-20150319"
-  },
-  {
-    "layer": "0b79d1c2",
-    "name": "utopic-20150418"
-  },
-  {
-    "layer": "d191563a",
-    "name": "utopic-20150427"
-  },
-  {
-    "layer": "ce78e71c",
-    "name": "utopic-20150528"
-  },
-  {
-    "layer": "ab57dbaf",
-    "name": "utopic-20150612"
-  },
-  {
-    "layer": "dce38fb5",
-    "name": "utopic-20150625"
-  },
-  {
-    "layer": "3f0d2d4f",
-    "name": "vivid"
-  },
-  {
-    "layer": "2427658c",
-    "name": "vivid-20150218"
-  },
-  {
-    "layer": "19c8c047",
-    "name": "vivid-20150309"
-  },
-  {
-    "layer": "751a7482",
-    "name": "vivid-20150319.1"
-  },
-  {
-    "layer": "ef8182f3",
-    "name": "vivid-20150421"
-  },
-  {
-    "layer": "bd94ae58",
-    "name": "vivid-20150427"
-  },
-  {
-    "layer": "c6a35822",
-    "name": "vivid-20150528"
-  },
-  {
-    "layer": "6be21d1e",
-    "name": "vivid-20150611"
-  },
-  {
-    "layer": "23635bbe",
-    "name": "vivid-20150802"
-  },
-  {
-    "layer": "013f3d01",
-    "name": "vivid-20150813"
-  },
-  {
-    "layer": "82554298",
-    "name": "vivid-20150930"
-  },
-  {
-    "layer": "4e9c8310",
-    "name": "vivid-20151021"
-  },
-  {
-    "layer": "e97f8c6b",
-    "name": "vivid-20151106"
-  },
-  {
-    "layer": "db672630",
-    "name": "vivid-20151111"
-  },
-  {
-    "layer": "3f0d2d4f",
-    "name": "vivid-20151208"
-  },
-  {
-    "layer": "3e0c71ad",
-    "name": "wily"
-  },
-  {
-    "layer": "0fe5a10d",
-    "name": "wily-20150528.1"
-  },
-  {
-    "layer": "906f2d7d",
-    "name": "wily-20150611"
-  },
-  {
-    "layer": "22ba5544",
-    "name": "wily-20150708"
-  },
-  {
-    "layer": "6767f35d",
-    "name": "wily-20150731"
-  },
-  {
-    "layer": "1832625b",
-    "name": "wily-20150807"
-  },
-  {
-    "layer": "53816304",
-    "name": "wily-20150818"
-  },
-  {
-    "layer": "1884caee",
-    "name": "wily-20150829"
-  },
-  {
-    "layer": "4dc94650",
-    "name": "wily-20151006"
-  },
-  {
-    "layer": "6171b5c3",
-    "name": "wily-20151009"
-  },
-  {
-    "layer": "337d0fd7",
-    "name": "wily-20151019"
-  },
-  {
-    "layer": "3e0c71ad",
-    "name": "wily-20151208"
-  },
-  {
-    "layer": "db856b41",
-    "name": "xenial"
-  },
-  {
-    "layer": "db856b41",
-    "name": "xenial-20151218.1"
-  }
-]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu.json
----------------------------------------------------------------------
diff --git a/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu.json b/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu.json
new file mode 100644
index 0000000..d60b25d
--- /dev/null
+++ b/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu.json
@@ -0,0 +1,15 @@
+{
+  "user": "library",
+  "name": "ubuntu",
+  "namespace": "library",
+  "status": 1,
+  "description": "Ubuntu is a Debian-based Linux operating system based on free software.",
+  "is_private": false,
+  "is_automated": false,
+  "can_edit": false,
+  "star_count": 2954,
+  "pull_count": 37627788,
+  "last_updated": "2016-01-04T19:00:53.547174Z",
+  "has_starred": false,
+  "full_description": "# Supported tags and respective `Dockerfile` links\n\n-\t[`12.04.5`, `12.04`, `precise-20151208`, `precise` (*precise/Dockerfile*)](https://github.com/tianon/docker-brew-ubuntu-core/blob/d7f2045ad9b08962d9728f6d9910fa252282b85f/precise/Dockerfile)\n-\t[`14.04.3`, `14.04`, `trusty-20151218`, `trusty`, `latest` (*trusty/Dockerfile*)](https://github.com/tianon/docker-brew-ubuntu-core/blob/d7f2045ad9b08962d9728f6d9910fa252282b85f/trusty/Dockerfile)\n-\t[`15.04`, `vivid-20151208`, `vivid` (*vivid/Dockerfile*)](https://github.com/tianon/docker-brew-ubuntu-core/blob/d7f2045ad9b08962d9728f6d9910fa252282b85f/vivid/Dockerfile)\n-\t[`15.10`, `wily-20151208`, `wily` (*wily/Dockerfile*)](https://github.com/tianon/docker-brew-ubuntu-core/blob/d7f2045ad9b08962d9728f6d9910fa252282b85f/wily/Dockerfile)\n-\t[`16.04`, `xenial-20151218.1`, `xenial` (*xenial/Dockerfile*)](https://github.com/tianon/docker-brew-ubuntu-core/blob/d7f2045ad9b08962d9728f6d9910fa252282b85f/xenial/Dockerf
 ile)\n\nFor more information about this image and its history, please see [the relevant manifest file (`library/ubuntu`)](https://github.com/docker-library/official-images/blob/master/library/ubuntu). This image is updated via pull requests to [the `docker-library/official-images` GitHub repo](https://github.com/docker-library/official-images).\n\nFor detailed information about the virtual/transfer sizes and individual layers of each of the above supported tags, please see [the `ubuntu/tag-details.md` file](https://github.com/docker-library/docs/blob/master/ubuntu/tag-details.md) in [the `docker-library/docs` GitHub repo](https://github.com/docker-library/docs).\n\n# What is Ubuntu?\n\nUbuntu is a Debian-based Linux operating system, with Unity as its default desktop environment. It is based on free software and named after the Southern African philosophy of ubuntu (literally, \"human-ness\"), which often is translated as \"humanity towards others\" or \"the belief in a universal bo
 nd of sharing that connects all humanity\".\n\nDevelopment of Ubuntu is led by UK-based Canonical Ltd., a company owned by South African entrepreneur Mark Shuttleworth. Canonical generates revenue through the sale of technical support and other services related to Ubuntu. The Ubuntu project is publicly committed to the principles of open-source software development; people are encouraged to use free software, study how it works, improve upon it, and distribute it.\n\n> [wikipedia.org/wiki/Ubuntu_(operating_system)](https://en.wikipedia.org/wiki/Ubuntu_%28operating_system%29)\n\n![logo](https://raw.githubusercontent.com/docker-library/docs/01c12653951b2fe592c1f93a13b4e289ada0e3a1/ubuntu/logo.png)\n\n# What's in this image?\n\n## `/etc/apt/sources.list`\n\n### `ubuntu:14.04`\n\n```console\n$ docker run ubuntu:14.04 grep -v '^#' /etc/apt/sources.list\n\ndeb http://archive.ubuntu.com/ubuntu/ trusty main restricted\ndeb-src http://archive.ubuntu.com/ubuntu/ trusty main restricted\n\ndeb 
 http://archive.ubuntu.com/ubuntu/ trusty-updates main restricted\ndeb-src http://archive.ubuntu.com/ubuntu/ trusty-updates main restricted\n\ndeb http://archive.ubuntu.com/ubuntu/ trusty universe\ndeb-src http://archive.ubuntu.com/ubuntu/ trusty universe\ndeb http://archive.ubuntu.com/ubuntu/ trusty-updates universe\ndeb-src http://archive.ubuntu.com/ubuntu/ trusty-updates universe\n\n\ndeb http://archive.ubuntu.com/ubuntu/ trusty-security main restricted\ndeb-src http://archive.ubuntu.com/ubuntu/ trusty-security main restricted\ndeb http://archive.ubuntu.com/ubuntu/ trusty-security universe\ndeb-src http://archive.ubuntu.com/ubuntu/ trusty-security universe\n```\n\n### `ubuntu:12.04`\n\n```console\n$ docker run ubuntu:12.04 cat /etc/apt/sources.list\n\ndeb http://archive.ubuntu.com/ubuntu/ precise main restricted\ndeb-src http://archive.ubuntu.com/ubuntu/ precise main restricted\n\ndeb http://archive.ubuntu.com/ubuntu/ precise-updates main restricted\ndeb-src http://archive.ubuntu.
 com/ubuntu/ precise-updates main restricted\n\ndeb http://archive.ubuntu.com/ubuntu/ precise universe\ndeb-src http://archive.ubuntu.com/ubuntu/ precise universe\ndeb http://archive.ubuntu.com/ubuntu/ precise-updates universe\ndeb-src http://archive.ubuntu.com/ubuntu/ precise-updates universe\n\n\ndeb http://archive.ubuntu.com/ubuntu/ precise-security main restricted\ndeb-src http://archive.ubuntu.com/ubuntu/ precise-security main restricted\ndeb http://archive.ubuntu.com/ubuntu/ precise-security universe\ndeb-src http://archive.ubuntu.com/ubuntu/ precise-security universe\n```\n\n# Supported Docker versions\n\nThis image is officially supported on Docker version 1.9.1.\n\nSupport for older versions (down to 1.6) is provided on a best-effort basis.\n\nPlease see [the Docker installation documentation](https://docs.docker.com/installation/) for details on how to upgrade your Docker daemon.\n\n# User Feedback\n\n## Documentation\n\nDocumentation for this image is stored in the [`ubunt
 u/` directory](https://github.com/docker-library/docs/tree/master/ubuntu) of the [`docker-library/docs` GitHub repo](https://github.com/docker-library/docs). Be sure to familiarize yourself with the [repository's `README.md` file](https://github.com/docker-library/docs/blob/master/README.md) before attempting a pull request.\n\n## Issues\n\nIf you have any problems with or questions about this image, please contact us through a [GitHub issue](https://github.com/tianon/docker-brew-ubuntu-core/issues).\n\nYou can also reach many of the official image maintainers via the `#docker-library` IRC channel on [Freenode](https://freenode.net).\n\n## Contributing\n\nYou are invited to contribute new features, fixes, or updates, large or small; we are always thrilled to receive pull requests, and do our best to process them as fast as we can.\n\nBefore you start to code, we recommend discussing your plans through a [GitHub issue](https://github.com/tianon/docker-brew-ubuntu-core/issues), especi
 ally for more ambitious contributions. This gives other contributors a chance to point you in the right direction, give you feedback on your design, and help you find out if someone else is working on the same thing."
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu_tags.json
----------------------------------------------------------------------
diff --git a/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu_tags.json b/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu_tags.json
new file mode 100644
index 0000000..f3914c9
--- /dev/null
+++ b/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu_tags.json
@@ -0,0 +1,975 @@
+{
+  "count": 88,
+  "next": null,
+  "previous": null,
+  "results": [
+    {
+      "name": "xenial",
+      "full_size": 47439662,
+      "id": 1589976,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T19:00:51.344198Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "xenial-20151218.1",
+      "full_size": 47439662,
+      "id": 1589974,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T19:00:45.326998Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "16.04",
+      "full_size": 47439662,
+      "id": 1589970,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T19:00:39.215205Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "wily",
+      "full_size": 50294202,
+      "id": 2332,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T19:00:30.141301Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "wily-20151208",
+      "full_size": 50294202,
+      "id": 1509180,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T19:00:24.324323Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "15.10",
+      "full_size": 50294202,
+      "id": 2327,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T19:00:18.625895Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid",
+      "full_size": 49334628,
+      "id": 2329,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T19:00:12.764756Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid-20151208",
+      "full_size": 49334628,
+      "id": 1509158,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T19:00:07.282476Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "15.04",
+      "full_size": 49334628,
+      "id": 2298,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T19:00:01.659187Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "latest",
+      "full_size": 65747044,
+      "id": 2343,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T18:59:54.779484Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty",
+      "full_size": 65747044,
+      "id": 2305,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T18:59:49.102906Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20151218",
+      "full_size": 65747044,
+      "id": 1657173,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T18:59:43.103725Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "14.04",
+      "full_size": 65747044,
+      "id": 2324,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T18:59:37.496154Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "14.04.3",
+      "full_size": 65747044,
+      "id": 693829,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T18:58:46.261151Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "precise",
+      "full_size": 44194573,
+      "id": 2292,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T18:57:33.494399Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "precise-20151208",
+      "full_size": 44194573,
+      "id": 1509115,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T18:57:22.912930Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "12.04",
+      "full_size": 44194573,
+      "id": 2310,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T18:57:14.495660Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "12.04.5",
+      "full_size": 44194573,
+      "id": 2295,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": "2016-01-04T18:57:08.237857Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20151208",
+      "full_size": 65742980,
+      "id": 1509143,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2015-12-18T18:26:56.770757Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "wily-20151019",
+      "full_size": 49817335,
+      "id": 1168566,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2015-12-08T09:04:03.336941Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid-20151111",
+      "full_size": 49333876,
+      "id": 1389462,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2015-12-08T09:02:56.243906Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20151028",
+      "full_size": 65742789,
+      "id": 1313714,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2015-12-08T09:02:32.340602Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "precise-20151028",
+      "full_size": 44096878,
+      "id": 1313721,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2015-12-08T09:02:07.834932Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid-20151106",
+      "full_size": 49329280,
+      "id": 1313735,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 213249,
+      "last_updated": "2015-11-21T01:14:52.126272Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "12.10",
+      "full_size": 58078433,
+      "id": 2339,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:42:40.878495Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20150218.1",
+      "full_size": 65832655,
+      "id": 2325,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:42:29.777917Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "utopic-20150211",
+      "full_size": 68374766,
+      "id": 2307,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:41:34.805100Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "quantal",
+      "full_size": 58078433,
+      "id": 2341,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:40:29.962553Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "14.04.1",
+      "full_size": 65827193,
+      "id": 2322,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:39:42.479726Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "raring",
+      "full_size": 57667348,
+      "id": 2316,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:38:47.745980Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid-20150218",
+      "full_size": 44122689,
+      "id": 2320,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:38:37.964774Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid-20150309",
+      "full_size": 49448856,
+      "id": 2317,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:37:59.209284Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "10.04",
+      "full_size": 63533781,
+      "id": 2299,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:37:16.010344Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "saucy",
+      "full_size": 60522580,
+      "id": 2301,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:37:04.113916Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "precise-20150228.11",
+      "full_size": 43657047,
+      "id": 2331,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:36:51.552688Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "utopic-20150228.11",
+      "full_size": 68379536,
+      "id": 2318,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:36:02.986916Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "13.10",
+      "full_size": 60522580,
+      "id": 2304,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:34:52.333445Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "13.04",
+      "full_size": 57667348,
+      "id": 2294,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:33:49.391093Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "precise-20150212",
+      "full_size": 43616335,
+      "id": 2340,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:32:59.135708Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20150228.11",
+      "full_size": 65828716,
+      "id": 2323,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:32:14.798440Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "lucid",
+      "full_size": 63533781,
+      "id": 2321,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 134455,
+      "last_updated": "2015-11-14T14:31:11.758283Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid-20151021",
+      "full_size": 49328003,
+      "id": 1168551,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2015-10-28T12:21:31.210637Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20151021",
+      "full_size": 65741561,
+      "id": 1168539,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2015-10-28T12:21:07.780326Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "precise-20151020",
+      "full_size": 44096883,
+      "id": 1168524,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": "2015-10-28T12:20:39.816211Z",
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "wily-20151009",
+      "full_size": 49844614,
+      "id": 1096696,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20151009",
+      "full_size": 65861875,
+      "id": 1096682,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "wily-20151006",
+      "full_size": 49861095,
+      "id": 1081815,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid-20150930",
+      "full_size": 49345386,
+      "id": 1081804,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20151001",
+      "full_size": 65757468,
+      "id": 1081789,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "precise-20150924",
+      "full_size": 44037965,
+      "id": 1081772,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "wily-20150829",
+      "full_size": 49614664,
+      "id": 828778,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "wily-20150818",
+      "full_size": 50298307,
+      "id": 778618,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "precise-20150813",
+      "full_size": 43977816,
+      "id": 776393,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid-20150813",
+      "full_size": 49343696,
+      "id": 776144,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20150814",
+      "full_size": 65859249,
+      "id": 775535,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "wily-20150807",
+      "full_size": 50528668,
+      "id": 693839,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 213249,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20150806",
+      "full_size": 65857914,
+      "id": 693834,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 213249,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "wily-20150731",
+      "full_size": 50488452,
+      "id": 674054,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 213249,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid-20150802",
+      "full_size": 49340063,
+      "id": 674043,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 213249,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20150730",
+      "full_size": 65860360,
+      "id": 674034,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 213249,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "precise-20150729",
+      "full_size": 43967445,
+      "id": 674016,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 213249,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "wily-20150708",
+      "full_size": 50494409,
+      "id": 541269,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "utopic-20150625",
+      "full_size": 68399747,
+      "id": 541258,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20150630",
+      "full_size": 65858138,
+      "id": 541253,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "precise-20150626",
+      "full_size": 43878461,
+      "id": 541246,
+      "repository": 130,
+      "creator": 2215,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid-20150528",
+      "full_size": 131333439,
+      "id": 2338,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "utopic-20150528",
+      "full_size": 194454267,
+      "id": 2337,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "utopic",
+      "full_size": 68399747,
+      "id": 2336,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "precise-20150528",
+      "full_size": 133416464,
+      "id": 2335,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "utopic-20150319",
+      "full_size": 194424279,
+      "id": 2334,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "utopic-20150418",
+      "full_size": 194463410,
+      "id": 2333,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "precise-20150427",
+      "full_size": 132465012,
+      "id": 2330,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "trusty-20150612",
+      "full_size": 188284994,
+      "id": 2328,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "wily-20150528.1",
+      "full_size": 132392276,
+      "id": 2326,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "vivid-20150319.1",
+      "full_size": 131685773,
+      "id": 2315,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "14.04.2",
+      "full_size": 65860360,
+      "id": 2314,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 213249,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20150528",
+      "full_size": 188281989,
+      "id": 2313,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "precise-20150612",
+      "full_size": 133706040,
+      "id": 2312,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "trusty-20150320",
+      "full_size": 188300556,
+      "id": 2311,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "vivid-20150611",
+      "full_size": 49338475,
+      "id": 2309,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "trusty-20150427",
+      "full_size": 188278440,
+      "id": 2308,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "wily-20150611",
+      "full_size": 133648792,
+      "id": 2306,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "utopic-20150612",
+      "full_size": 194462706,
+      "id": 2303,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "utopic-20150427",
+      "full_size": 194461653,
+      "id": 2302,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "precise-20150320",
+      "full_size": 131886863,
+      "id": 2300,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "14.10",
+      "full_size": 68399747,
+      "id": 2297,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 2215,
+      "last_updated": null,
+      "image_id": null,
+      "v2": true
+    },
+    {
+      "name": "vivid-20150427",
+      "full_size": 131302888,
+      "id": 2296,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    },
+    {
+      "name": "vivid-20150421",
+      "full_size": 131279915,
+      "id": 2293,
+      "repository": 130,
+      "creator": 7,
+      "last_updater": 7,
+      "last_updated": null,
+      "image_id": null,
+      "v2": false
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu_tags_latest.json
----------------------------------------------------------------------
diff --git a/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu_tags_latest.json b/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu_tags_latest.json
new file mode 100644
index 0000000..c5ce942
--- /dev/null
+++ b/libcloud/test/container/fixtures/docker_utils/v2_repositories_library_ubuntu_tags_latest.json
@@ -0,0 +1,11 @@
+{
+  "name": "latest",
+  "full_size": 65747044,
+  "id": 2343,
+  "repository": 130,
+  "creator": 7,
+  "last_updater": 2215,
+  "last_updated": "2016-01-04T18:59:54.779484Z",
+  "image_id": null,
+  "v2": true
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/libcloud/test/container/test_docker_utils.py
----------------------------------------------------------------------
diff --git a/libcloud/test/container/test_docker_utils.py b/libcloud/test/container/test_docker_utils.py
new file mode 100644
index 0000000..d209447
--- /dev/null
+++ b/libcloud/test/container/test_docker_utils.py
@@ -0,0 +1,86 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+from libcloud.test import unittest
+from libcloud.container.utils.docker import HubClient
+from libcloud.utils.py3 import httplib
+from libcloud.test.file_fixtures import ContainerFileFixtures
+from libcloud.test import MockHttp
+
+
+class DockerUtilitiesTestCase(unittest.TestCase):
+
+    def setUp(self):
+        HubClient.connectionCls.conn_classes = (
+            DockerMockHttp, DockerMockHttp)
+        DockerMockHttp.type = None
+        DockerMockHttp.use_param = 'a'
+        self.driver = HubClient()
+
+    def test_list_tags(self):
+        tags = self.driver.list_images('ubuntu', max_count=100)
+        self.assertEqual(len(tags), 88)
+        self.assertEqual(tags[0].name, 'registry.hub.docker.com/ubuntu:xenial')
+
+    def test_get_repository(self):
+        repo = self.driver.get_repository('ubuntu')
+        self.assertEqual(repo['name'], 'ubuntu')
+
+    def test_get_image(self):
+        image = self.driver.get_image('ubuntu', 'latest')
+        self.assertEqual(image.id, '2343')
+        self.assertEqual(image.name, 'registry.hub.docker.com/ubuntu:latest')
+        self.assertEqual(image.path, 'registry.hub.docker.com/ubuntu:latest')
+
+
+class DockerMockHttp(MockHttp):
+    fixtures = ContainerFileFixtures('docker_utils')
+
+    def _version(
+            self, method, url, body, headers):
+        if method == 'GET':
+            body = self.fixtures.load('version.json')
+        else:
+            raise AssertionError('Unsupported method')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def v2_repositories_library_ubuntu_tags_latest(
+            self, method, url, body, headers):
+        if method == 'GET':
+            body = self.fixtures.load('v2_repositories_library_ubuntu_tags_latest.json')
+        else:
+            raise AssertionError('Unsupported method')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def v2_repositories_library_ubuntu_tags(
+            self, method, url, body, headers):
+        if method == 'GET':
+            body = self.fixtures.load('v2_repositories_library_ubuntu_tags.json')
+        else:
+            raise AssertionError('Unsupported method')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def v2_repositories_library_ubuntu(
+            self, method, url, body, headers):
+        if method == 'GET':
+            body = self.fixtures.load('v2_repositories_library_ubuntu.json')
+        else:
+            raise AssertionError('Unsupported method')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+if __name__ == '__main__':
+    sys.exit(unittest.main())

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d29629de/libcloud/test/container/test_ecs.py
----------------------------------------------------------------------
diff --git a/libcloud/test/container/test_ecs.py b/libcloud/test/container/test_ecs.py
index 2a3a2c2..518daae 100644
--- a/libcloud/test/container/test_ecs.py
+++ b/libcloud/test/container/test_ecs.py
@@ -35,7 +35,7 @@ class ElasticContainerDriverTestCase(unittest.TestCase):
         ECSMockHttp.use_param = 'a'
         ElasticContainerDriver.ecrConnectionClass.conn_classes = (
             ECSMockHttp, ECSMockHttp)
-        
+
         self.driver = ElasticContainerDriver(*CONTAINER_PARAMS_ECS)
 
     def test_list_clusters(self):


Mime
View raw message