summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--glanceclient/v1/images.py59
-rwxr-xr-xrun_tests.sh2
-rw-r--r--tests/__init__.py0
-rw-r--r--tests/test_test.py5
-rw-r--r--tests/v1/__init__.py0
-rw-r--r--tests/v1/test_images.py59
-rw-r--r--tests/v1/utils.py70
7 files changed, 174 insertions, 21 deletions
diff --git a/glanceclient/v1/images.py b/glanceclient/v1/images.py
index 442b23e..97e2ce4 100644
--- a/glanceclient/v1/images.py
+++ b/glanceclient/v1/images.py
@@ -29,21 +29,34 @@ class Image(base.Resource):
class ImageManager(base.Manager):
resource_class = Image
- def get(self, image):
- """Get the metadata for a specific image.
-
- :param image: image object or id to look up
- :rtype: :class:`Image`
- """
- resp, body = self.api.head("/images/%s" % base.getid(image))
+ def _image_meta_from_headers(self, headers):
meta = {'properties': {}}
- for key, value in resp.iteritems():
+ for key, value in headers.iteritems():
if key.startswith('x-image-meta-property-'):
_key = key[22:]
meta['properties'][_key] = value
elif key.startswith('x-image-meta-'):
_key = key[13:]
meta[_key] = value
+ return meta
+
+ def _image_meta_to_headers(self, fields):
+ headers = {}
+ for key, value in fields.iteritems():
+ if key == 'properties':
+ headers['x-image-meta-property-%s' % key] = value
+ else:
+ headers['x-image-meta-%s' % key] = value
+ return headers
+
+ def get(self, image):
+ """Get the metadata for a specific image.
+
+ :param image: image object or id to look up
+ :rtype: :class:`Image`
+ """
+ resp, body = self.api.head('/v1/images/%s' % base.getid(image))
+ meta = self._image_meta_from_headers(resp)
return Image(self, meta)
def list(self, limit=None, marker=None):
@@ -58,13 +71,29 @@ class ImageManager(base.Manager):
params['limit'] = int(limit)
if marker:
params['marker'] = int(marker)
-
- query = ""
- if params:
- query = "?" + urllib.urlencode(params)
-
- return self._list("/images/detail%s" % query, "images")
+ query = '?%s' % urllib.urlencode(params) if params else ''
+ return self._list('/v1/images/detail%s' % query, "images")
def delete(self, image):
"""Delete an image."""
- self._delete("/images/%s" % base.getid(image))
+ self._delete("/v1/images/%s" % base.getid(image))
+
+ def create(self, **kwargs):
+ """Create an image"""
+ fields = {}
+ if 'name' in kwargs:
+ fields['name'] = kwargs['name']
+ resp, body = self.api.post('/v1/images', body={'image': fields})
+ meta = self._image_meta_from_headers(resp)
+ return Image(self, meta)
+
+ def update(self, image, **kwargs):
+ """Update an image"""
+ fields = {}
+ if 'name' in kwargs:
+ fields['name'] = kwargs['name']
+ send_meta = self._image_meta_to_headers(fields)
+ url = '/v1/images/%s' % base.getid(image)
+ resp, body = self.api.put(url, headers=send_meta)
+ recv_meta = self._image_meta_from_headers(resp)
+ return Image(self, recv_meta)
diff --git a/run_tests.sh b/run_tests.sh
index d0d3645..2ecbc4a 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -50,7 +50,7 @@ function run_tests {
function run_pep8 {
echo "Running pep8..."
PEP8_OPTIONS="--exclude=$PEP8_EXCLUDE --repeat"
- PEP8_INCLUDE="glanceclient/* setup.py run_tests.py tools/install_venv.py"
+ PEP8_INCLUDE="glanceclient/*.py setup.py run_tests.py tools/install_venv.py"
${wrapper} pep8 $PEP8_OPTIONS $PEP8_INCLUDE
}
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/__init__.py
diff --git a/tests/test_test.py b/tests/test_test.py
deleted file mode 100644
index ec6a6e5..0000000
--- a/tests/test_test.py
+++ /dev/null
@@ -1,5 +0,0 @@
-import unittest
-
-class TestCase(unittest.TestCase):
- def test_one(self):
- self.assertTrue(True)
diff --git a/tests/v1/__init__.py b/tests/v1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/v1/__init__.py
diff --git a/tests/v1/test_images.py b/tests/v1/test_images.py
new file mode 100644
index 0000000..f8d904f
--- /dev/null
+++ b/tests/v1/test_images.py
@@ -0,0 +1,59 @@
+
+import unittest
+
+from tests.v1 import utils
+
+import glanceclient.v1.images
+
+
+class ImageManagerTest(unittest.TestCase):
+
+ def setUp(self):
+ self.api = utils.FakeAPI()
+ self.mgr = glanceclient.v1.images.ImageManager(self.api)
+
+ def test_list(self):
+ images = self.mgr.list()
+ expect = [('GET', '/v1/images/detail', {}, None)]
+ self.assertEqual(self.api.calls, expect)
+ self.assertEqual(len(images), 1)
+ self.assertEqual(images[0].id, '1')
+ self.assertEqual(images[0].name, 'image-1')
+ self.assertEqual(images[0].properties, {'arch': 'x86_64'})
+
+ def test_list_with_limit(self):
+ self.mgr.list(limit=10)
+ expect = [('GET', '/v1/images/detail?limit=10', {}, None)]
+ self.assertEqual(self.api.calls, expect)
+
+ def test_list_with_marker(self):
+ self.mgr.list(marker=20)
+ expect = [('GET', '/v1/images/detail?marker=20', {}, None)]
+ self.assertEqual(self.api.calls, expect)
+
+ def test_get(self):
+ image = self.mgr.get('1')
+ expect = [('HEAD', '/v1/images/1', {}, None)]
+ self.assertEqual(self.api.calls, expect)
+ self.assertEqual(image.id, '1')
+ self.assertEqual(image.name, 'image-1')
+
+ def test_delete(self):
+ self.mgr.delete('1')
+ expect = [('DELETE', '/v1/images/1', {}, None)]
+ self.assertEqual(self.api.calls, expect)
+
+ def test_create(self):
+ image = self.mgr.create(name='image-1')
+ expect = [('POST', '/v1/images', {}, {'image': {'name': 'image-1'}})]
+ self.assertEqual(self.api.calls, expect)
+ self.assertEqual(image.id, '1')
+ self.assertEqual(image.name, 'image-1')
+
+ def test_update(self):
+ image = self.mgr.update('1', name='image-2')
+ expect_hdrs = {'x-image-meta-name': 'image-2'}
+ expect = [('PUT', '/v1/images/1', expect_hdrs, None)]
+ self.assertEqual(self.api.calls, expect)
+ self.assertEqual(image.id, '1')
+ self.assertEqual(image.name, 'image-2')
diff --git a/tests/v1/utils.py b/tests/v1/utils.py
new file mode 100644
index 0000000..42acd27
--- /dev/null
+++ b/tests/v1/utils.py
@@ -0,0 +1,70 @@
+
+
+fixtures = {
+ '/v1/images': {
+ 'POST': (
+ {
+ 'location': '/v1/images/1',
+ 'x-image-meta-id': '1',
+ 'x-image-meta-name': 'image-1',
+ 'x-image-meta-property-arch': 'x86_64',
+ },
+ None),
+ },
+ '/v1/images/detail': {
+ 'GET': (
+ {},
+ {'images': [
+ {
+ 'id': '1',
+ 'name': 'image-1',
+ 'properties': {'arch': 'x86_64'},
+ },
+ ]},
+ ),
+ },
+ '/v1/images/1': {
+ 'HEAD': (
+ {
+ 'x-image-meta-id': '1',
+ 'x-image-meta-name': 'image-1',
+ 'x-image-meta-property-arch': 'x86_64',
+ },
+ None),
+ 'PUT': (
+ {
+ 'x-image-meta-id': '1',
+ 'x-image-meta-name': 'image-2',
+ 'x-image-meta-property-arch': 'x86_64',
+ },
+ None),
+ 'DELETE': ({}, None),
+ }
+}
+
+class FakeAPI(object):
+
+ def __init__(self):
+ self.calls = []
+
+ def _request(self, method, url, headers=None, body=None):
+ call = (method, url, headers or {}, body)
+ self.calls.append(call)
+ # drop any query params
+ url = url.split('?', 1)[0]
+ return fixtures[url][method]
+
+ def get(self, url):
+ return self._request('GET', url)
+
+ def head(self, url):
+ return self._request('HEAD', url)
+
+ def post(self, url, headers=None, body=None):
+ return self._request('POST', url, headers, body)
+
+ def put(self, url, headers=None, body=None):
+ return self._request('PUT', url, headers, body)
+
+ def delete(self, url):
+ return self._request('DELETE', url)