Sync with trunk.
This commit is contained in:
commit
c54e7bf264
@ -63,6 +63,57 @@ Using Glance's Client, we can do this using the following code
|
||||
|
||||
print c.get_images_detailed()
|
||||
|
||||
Filtering Images Returned via ``get_images()`` and ``get_images_detailed()``
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Both the ``get_images()`` and ``get_images_detailed()`` methods take query
|
||||
parameters that serve to filter the returned list of images.
|
||||
|
||||
When calling, simply pass an optional dictionary to the method containing
|
||||
the filters by which you wish to limit results, with the filter keys being one
|
||||
or more of the below:
|
||||
|
||||
* ``name: NAME``
|
||||
|
||||
Filters images having a ``name`` attribute matching ``NAME``.
|
||||
|
||||
* ``container_format: FORMAT``
|
||||
|
||||
Filters images having a ``container_format`` attribute matching ``FORMAT``
|
||||
|
||||
For more information, see :doc:`About Disk and Container Formats <formats>`
|
||||
|
||||
* ``disk_format: FORMAT``
|
||||
|
||||
Filters images having a ``disk_format`` attribute matching ``FORMAT``
|
||||
|
||||
For more information, see :doc:`About Disk and Container Formats <formats>`
|
||||
|
||||
* ``status: STATUS``
|
||||
|
||||
Filters images having a ``status`` attribute matching ``STATUS``
|
||||
|
||||
For more information, see :doc:`About Image Statuses <statuses>`
|
||||
|
||||
* ``size_min: BYTES``
|
||||
|
||||
Filters images having a ``size`` attribute greater than or equal to ``BYTES``
|
||||
|
||||
* ``size_max: BYTES``
|
||||
|
||||
Filters images having a ``size`` attribute less than or equal to ``BYTES``
|
||||
|
||||
Here's a quick example that will return all images less than or equal to 5G
|
||||
in size and in the `saving` status.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from glance.client import Client
|
||||
|
||||
c = Client("glance.example.com", 9292)
|
||||
|
||||
filters = {'status': 'saving', 'size_max': (5 * 1024 * 1024 * 1024)}
|
||||
print c.get_images_detailed(filters)
|
||||
|
||||
Requesting Detailed Metadata on a Specific Image
|
||||
------------------------------------------------
|
||||
@ -86,7 +137,6 @@ first public image returned, we can use the following code
|
||||
|
||||
print c.get_image_meta("http://glance.example.com/images/1")
|
||||
|
||||
|
||||
Retrieving a Virtual Machine Image
|
||||
----------------------------------
|
||||
|
||||
|
@ -92,6 +92,42 @@ JSON-encoded mapping in the following format::
|
||||
|
||||
The `checksum` field is an MD5 checksum of the image file data
|
||||
|
||||
Filtering Images Returned via ``GET /images`` and ``GET /images/detail``
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Both the ``GET /images`` and ``GET /images/detail`` requests take query
|
||||
parameters that serve to filter the returned list of images. The following
|
||||
list details these query parameters.
|
||||
|
||||
* ``name=NAME``
|
||||
|
||||
Filters images having a ``name`` attribute matching ``NAME``.
|
||||
|
||||
* ``container_format=FORMAT``
|
||||
|
||||
Filters images having a ``container_format`` attribute matching ``FORMAT``
|
||||
|
||||
For more information, see :doc:`About Disk and Container Formats <formats>`
|
||||
|
||||
* ``disk_format=FORMAT``
|
||||
|
||||
Filters images having a ``disk_format`` attribute matching ``FORMAT``
|
||||
|
||||
For more information, see :doc:`About Disk and Container Formats <formats>`
|
||||
|
||||
* ``status=STATUS``
|
||||
|
||||
Filters images having a ``status`` attribute matching ``STATUS``
|
||||
|
||||
For more information, see :doc:`About Image Statuses <statuses>`
|
||||
|
||||
* ``size_min=BYTES``
|
||||
|
||||
Filters images having a ``size`` attribute greater than or equal to ``BYTES``
|
||||
|
||||
* ``size_max=BYTES``
|
||||
|
||||
Filters images having a ``size`` attribute less than or equal to ``BYTES``
|
||||
|
||||
Requesting Detailed Metadata on a Specific Image
|
||||
------------------------------------------------
|
||||
|
@ -46,6 +46,43 @@ The following is a brief description of the Glance API::
|
||||
PUT /images/<ID> Update metadata about an existing image
|
||||
DELETE /images/<ID> Remove an image's metadata from the registry
|
||||
|
||||
Filtering Images Returned via ``GET /images`` and ``GET /images/detail``
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Both the ``GET /images`` and ``GET /images/detail`` requests take query
|
||||
parameters that serve to filter the returned list of images. The following
|
||||
list details these query parameters.
|
||||
|
||||
* ``name=NAME``
|
||||
|
||||
Filters images having a ``name`` attribute matching ``NAME``.
|
||||
|
||||
* ``container_format=FORMAT``
|
||||
|
||||
Filters images having a ``container_format`` attribute matching ``FORMAT``
|
||||
|
||||
For more information, see :doc:`About Disk and Container Formats <formats>`
|
||||
|
||||
* ``disk_format=FORMAT``
|
||||
|
||||
Filters images having a ``disk_format`` attribute matching ``FORMAT``
|
||||
|
||||
For more information, see :doc:`About Disk and Container Formats <formats>`
|
||||
|
||||
* ``status=STATUS``
|
||||
|
||||
Filters images having a ``status`` attribute matching ``STATUS``
|
||||
|
||||
For more information, see :doc:`About Image Statuses <statuses>`
|
||||
|
||||
* ``size_min=BYTES``
|
||||
|
||||
Filters images having a ``size`` attribute greater than or equal to ``BYTES``
|
||||
|
||||
* ``size_max=BYTES``
|
||||
|
||||
Filters images having a ``size`` attribute less than or equal to ``BYTES``
|
||||
|
||||
``POST /images``
|
||||
----------------
|
||||
|
||||
|
@ -25,6 +25,7 @@ import logging
|
||||
import urlparse
|
||||
import socket
|
||||
import sys
|
||||
import urllib
|
||||
|
||||
from glance import utils
|
||||
from glance.common import exception
|
||||
@ -94,7 +95,8 @@ class BaseClient(object):
|
||||
else:
|
||||
return httplib.HTTPConnection
|
||||
|
||||
def do_request(self, method, action, body=None, headers=None):
|
||||
def do_request(self, method, action, body=None, headers=None,
|
||||
params=None):
|
||||
"""
|
||||
Connects to the server and issues a request. Handles converting
|
||||
any returned HTTP error status codes to OpenStack/Glance exceptions
|
||||
@ -105,6 +107,8 @@ class BaseClient(object):
|
||||
:param action: part of URL after root netloc
|
||||
:param body: string of data to send, or None (default)
|
||||
:param headers: mapping of key/value pairs to add as headers
|
||||
:param params: dictionary of key/value pairs to add to append
|
||||
to action
|
||||
|
||||
:note
|
||||
|
||||
@ -115,6 +119,9 @@ class BaseClient(object):
|
||||
objects to be transferred efficiently without buffering the entire
|
||||
body in memory.
|
||||
"""
|
||||
if type(params) is dict:
|
||||
action += '?' + urllib.urlencode(params)
|
||||
|
||||
try:
|
||||
connection_type = self.get_connection_type()
|
||||
headers = headers or {}
|
||||
@ -197,24 +204,24 @@ class V1Client(BaseClient):
|
||||
self.doc_root = doc_root
|
||||
super(Client, self).__init__(host, port, use_ssl)
|
||||
|
||||
def do_request(self, method, action, body=None, headers=None):
|
||||
def do_request(self, method, action, body=None, headers=None, params=None):
|
||||
action = "%s/%s" % (self.doc_root, action.lstrip("/"))
|
||||
return super(V1Client, self).do_request(method, action,
|
||||
body, headers)
|
||||
return super(V1Client, self).do_request(method, action, body,
|
||||
headers, params)
|
||||
|
||||
def get_images(self):
|
||||
def get_images(self, filters=None):
|
||||
"""
|
||||
Returns a list of image id/name mappings from Registry
|
||||
"""
|
||||
res = self.do_request("GET", "/images")
|
||||
res = self.do_request("GET", "/images", params=filters)
|
||||
data = json.loads(res.read())['images']
|
||||
return data
|
||||
|
||||
def get_images_detailed(self):
|
||||
def get_images_detailed(self, filters=None):
|
||||
"""
|
||||
Returns a list of detailed image data mappings from Registry
|
||||
"""
|
||||
res = self.do_request("GET", "/images/detail")
|
||||
res = self.do_request("GET", "/images/detail", params=filters)
|
||||
data = json.loads(res.read())['images']
|
||||
return data
|
||||
|
||||
|
@ -48,12 +48,7 @@ class RegistryClient(BaseClient):
|
||||
"""
|
||||
Returns a list of image id/name mappings from Registry
|
||||
"""
|
||||
if filters != None:
|
||||
action = "/images?%s" % urllib.urlencode(filters)
|
||||
else:
|
||||
action = "/images"
|
||||
|
||||
res = self.do_request("GET", action)
|
||||
res = self.do_request("GET", "/images", params=filters)
|
||||
data = json.loads(res.read())['images']
|
||||
return data
|
||||
|
||||
@ -61,12 +56,7 @@ class RegistryClient(BaseClient):
|
||||
"""
|
||||
Returns a list of detailed image data mappings from Registry
|
||||
"""
|
||||
if filters != None:
|
||||
action = "/images/detail?%s" % urllib.urlencode(filters)
|
||||
else:
|
||||
action = "/images/detail"
|
||||
|
||||
res = self.do_request("GET", action)
|
||||
res = self.do_request("GET", "/images/detail", params=filters)
|
||||
data = json.loads(res.read())['images']
|
||||
return data
|
||||
|
||||
|
@ -457,6 +457,43 @@ class TestClient(unittest.TestCase):
|
||||
for k, v in fixture.items():
|
||||
self.assertEquals(v, images[0][k])
|
||||
|
||||
def test_get_image_index_by_base_attribute(self):
|
||||
"""Tests that an index call can be filtered by a base attribute"""
|
||||
extra_fixture = {'id': 3,
|
||||
'status': 'active',
|
||||
'is_public': True,
|
||||
'disk_format': 'vhd',
|
||||
'container_format': 'ovf',
|
||||
'name': 'new name! #123',
|
||||
'size': 19,
|
||||
'checksum': None}
|
||||
|
||||
glance.registry.db.api.image_create(None, extra_fixture)
|
||||
|
||||
images = self.client.get_images({'name': 'new name! #123'})
|
||||
|
||||
self.assertEquals(len(images), 1)
|
||||
self.assertEquals('new name! #123', images[0]['name'])
|
||||
|
||||
def test_get_image_index_by_property(self):
|
||||
"""Tests that an index call can be filtered by a property"""
|
||||
extra_fixture = {'id': 3,
|
||||
'status': 'saving',
|
||||
'is_public': True,
|
||||
'disk_format': 'vhd',
|
||||
'container_format': 'ovf',
|
||||
'name': 'new name! #123',
|
||||
'size': 19,
|
||||
'checksum': None,
|
||||
'properties': {'p a': 'v a'}}
|
||||
|
||||
glance.registry.db.api.image_create(None, extra_fixture)
|
||||
|
||||
images = self.client.get_images({'property-p a': 'v a'})
|
||||
|
||||
self.assertEquals(len(images), 1)
|
||||
self.assertEquals(3, images[0]['id'])
|
||||
|
||||
def test_get_image_details(self):
|
||||
"""Tests that the detailed info about public images returned"""
|
||||
fixture = {'id': 2,
|
||||
@ -485,6 +522,45 @@ class TestClient(unittest.TestCase):
|
||||
for k, v in expected.items():
|
||||
self.assertEquals(v, images[0][k])
|
||||
|
||||
def test_get_image_details_by_base_attribute(self):
|
||||
"""Tests that a detailed call can be filtered by a base attribute"""
|
||||
extra_fixture = {'id': 3,
|
||||
'status': 'active',
|
||||
'is_public': True,
|
||||
'disk_format': 'vhd',
|
||||
'container_format': 'ovf',
|
||||
'name': 'new name! #123',
|
||||
'size': 19,
|
||||
'checksum': None}
|
||||
|
||||
glance.registry.db.api.image_create(None, extra_fixture)
|
||||
|
||||
images = self.client.get_images_detailed({'name': 'new name! #123'})
|
||||
self.assertEquals(len(images), 1)
|
||||
|
||||
for image in images:
|
||||
self.assertEquals('new name! #123', image['name'])
|
||||
|
||||
def test_get_image_details_by_property(self):
|
||||
"""Tests that a detailed call can be filtered by a property"""
|
||||
extra_fixture = {'id': 3,
|
||||
'status': 'saving',
|
||||
'is_public': True,
|
||||
'disk_format': 'vhd',
|
||||
'container_format': 'ovf',
|
||||
'name': 'new name! #123',
|
||||
'size': 19,
|
||||
'checksum': None,
|
||||
'properties': {'p a': 'v a'}}
|
||||
|
||||
glance.registry.db.api.image_create(None, extra_fixture)
|
||||
|
||||
images = self.client.get_images_detailed({'property-p a': 'v a'})
|
||||
self.assertEquals(len(images), 1)
|
||||
|
||||
for image in images:
|
||||
self.assertEquals('v a', image['properties']['p a'])
|
||||
|
||||
def test_get_image_meta(self):
|
||||
"""Tests that the detailed info about an image returned"""
|
||||
fixture = {'id': 2,
|
||||
|
Loading…
Reference in New Issue
Block a user