From f92973d7f876fbbcf18eb6f6827042da530618dd Mon Sep 17 00:00:00 2001 From: Brian Curtin Date: Sun, 22 Feb 2015 23:58:11 -0600 Subject: [PATCH] Add ImageDetail for extra information The current Image can only receive the basics returned by a GET /images, which is just name, id, and links. A call to /images/detail gives a number of added details, some of which were already in the Image resource but not set. This change follows with how a few other basic/detail requests were done, and exposes it through the proxy with details coming by default (since they're likely expected, and most useful). Change-Id: Iadc98cd0f679777b1c6e14711ad00787142221e2 --- .../users/resources/compute/v2/image.rst | 9 +++ openstack/compute/v2/_proxy.py | 18 +++-- openstack/compute/v2/image.py | 20 +++-- openstack/tests/compute/v2/test_image.py | 74 +++++++++++++------ openstack/tests/compute/v2/test_proxy.py | 18 ++--- 5 files changed, 93 insertions(+), 46 deletions(-) diff --git a/doc/source/users/resources/compute/v2/image.rst b/doc/source/users/resources/compute/v2/image.rst index 1b25e522e..d39006536 100644 --- a/doc/source/users/resources/compute/v2/image.rst +++ b/doc/source/users/resources/compute/v2/image.rst @@ -10,3 +10,12 @@ The ``Image`` class inherits from :class:`~openstack.resource.Resource`. .. autoclass:: openstack.compute.v2.image.Image :members: + +The ImageDetail Class +--------------------- + +The ``ImageDetail`` class inherits from +:class:`~openstack.compute.v2.image.Image`. + +.. autoclass:: openstack.compute.v2.image.ImageDetail + :members: diff --git a/openstack/compute/v2/_proxy.py b/openstack/compute/v2/_proxy.py index dd158faec..dc7538475 100644 --- a/openstack/compute/v2/_proxy.py +++ b/openstack/compute/v2/_proxy.py @@ -59,9 +59,6 @@ class Proxy(object): def update_flavor(self, **data): return flavor.Flavor(data).update(self.session) - def create_image(self, **data): - return image.Image(data).create(self.session) - def delete_image(self, **data): image.Image(data).delete(self.session) @@ -71,11 +68,18 @@ class Proxy(object): def get_image(self, **data): return image.Image(data).get(self.session) - def list_images(self): - return image.Image.list(self.session) + def list_images(self, details=True): + """Return a generator of images - def update_image(self, **data): - return image.Image(data).update(self.session) + :param bool details: When ``True``, returns + :class:`~openstack.compute.v2.image.ImageDetail` objects, + otherwise :class:`~openstack.compute.v2.image.Image`. + *Default: ``True``* + + :returns: A generator of image objects + """ + img = image.ImageDetail if details else image.Image + return img.list(self.session, paginate=False) def create_keypair(self, **data): return keypair.Keypair(data).create(self.session) diff --git a/openstack/compute/v2/image.py b/openstack/compute/v2/image.py index 16e42eaca..2eec3f924 100644 --- a/openstack/compute/v2/image.py +++ b/openstack/compute/v2/image.py @@ -21,26 +21,24 @@ class Image(resource.Resource): service = compute_service.ComputeService() # capabilities - allow_create = True allow_retrieve = True - allow_update = True allow_delete = True allow_list = True # Properties - #: Timestamp when the image was created. - created = resource.prop('created') #: Links pertaining to this image. This is a list of dictionaries, #: each including keys ``href`` and ``rel``, and optionally ``type``. links = resource.prop('links') + #: The name of this image. + name = resource.prop('name') + #: Timestamp when the image was created. + created = resource.prop('created') #: Metadata pertaining to this image. *Type: dict* metadata = resource.prop('metadata', type=dict) #: The mimimum disk size. *Type: int* min_disk = resource.prop('minDisk', type=int) #: The minimum RAM size. *Type: int* min_ram = resource.prop('minRam', type=int) - #: The name of this image. - name = resource.prop('name') #: If this image is still building, its progress is represented here. #: Once an image is created, progres will be 100. *Type: int* progress = resource.prop('progress', type=int) @@ -48,3 +46,13 @@ class Image(resource.Resource): status = resource.prop('status') #: Timestamp when the image was updated. updated = resource.prop('updated') + #: Size of the image in bytes. *Type: int* + size = resource.prop('OS-EXT-IMG-SIZE:size', type=int) + + +class ImageDetail(Image): + base_path = '/images/detail' + + allow_retrieve = False + allow_delete = False + allow_list = True diff --git a/openstack/tests/compute/v2/test_image.py b/openstack/tests/compute/v2/test_image.py index 083cb946d..c815d2482 100644 --- a/openstack/tests/compute/v2/test_image.py +++ b/openstack/tests/compute/v2/test_image.py @@ -15,19 +15,26 @@ import testtools from openstack.compute.v2 import image IDENTIFIER = 'IDENTIFIER' -EXAMPLE = { - 'created': '1', +BASIC_EXAMPLE = { 'id': IDENTIFIER, - 'links': '3', - 'metadata': {'key': '4'}, - 'minDisk': 5, - 'minRam': 6, - 'name': '7', - 'progress': 8, - 'status': '9', - 'updated': '10', + 'links': '2', + 'name': '3', } +DETAILS = { + 'created': '1', + 'metadata': {'key': '2'}, + 'minDisk': 3, + 'minRam': 4, + 'progress': 5, + 'status': '6', + 'updated': '7', + 'OS-EXT-IMG-SIZE:size': 8 +} + +DETAIL_EXAMPLE = BASIC_EXAMPLE.copy() +DETAIL_EXAMPLE.update(DETAILS) + class TestImage(testtools.TestCase): @@ -37,21 +44,40 @@ class TestImage(testtools.TestCase): self.assertEqual('images', sot.resources_key) self.assertEqual('/images', sot.base_path) self.assertEqual('compute', sot.service.service_type) - self.assertTrue(sot.allow_create) + self.assertFalse(sot.allow_create) self.assertTrue(sot.allow_retrieve) - self.assertTrue(sot.allow_update) + self.assertFalse(sot.allow_update) self.assertTrue(sot.allow_delete) self.assertTrue(sot.allow_list) - def test_make_it(self): - sot = image.Image(EXAMPLE) - self.assertEqual(EXAMPLE['created'], sot.created) - self.assertEqual(EXAMPLE['id'], sot.id) - self.assertEqual(EXAMPLE['links'], sot.links) - self.assertEqual(EXAMPLE['metadata'], sot.metadata) - self.assertEqual(EXAMPLE['minDisk'], sot.min_disk) - self.assertEqual(EXAMPLE['minRam'], sot.min_ram) - self.assertEqual(EXAMPLE['name'], sot.name) - self.assertEqual(EXAMPLE['progress'], sot.progress) - self.assertEqual(EXAMPLE['status'], sot.status) - self.assertEqual(EXAMPLE['updated'], sot.updated) + def test_make_basic(self): + sot = image.Image(BASIC_EXAMPLE) + self.assertEqual(BASIC_EXAMPLE['id'], sot.id) + self.assertEqual(BASIC_EXAMPLE['links'], sot.links) + self.assertEqual(BASIC_EXAMPLE['name'], sot.name) + + def test_detail(self): + sot = image.ImageDetail() + self.assertEqual('image', sot.resource_key) + self.assertEqual('images', sot.resources_key) + self.assertEqual('/images/detail', sot.base_path) + self.assertEqual('compute', sot.service.service_type) + self.assertFalse(sot.allow_create) + self.assertFalse(sot.allow_retrieve) + self.assertFalse(sot.allow_update) + self.assertFalse(sot.allow_delete) + self.assertTrue(sot.allow_list) + + def test_make_detail(self): + sot = image.ImageDetail(DETAIL_EXAMPLE) + self.assertEqual(DETAIL_EXAMPLE['created'], sot.created) + self.assertEqual(DETAIL_EXAMPLE['id'], sot.id) + self.assertEqual(DETAIL_EXAMPLE['links'], sot.links) + self.assertEqual(DETAIL_EXAMPLE['metadata'], sot.metadata) + self.assertEqual(DETAIL_EXAMPLE['minDisk'], sot.min_disk) + self.assertEqual(DETAIL_EXAMPLE['minRam'], sot.min_ram) + self.assertEqual(DETAIL_EXAMPLE['name'], sot.name) + self.assertEqual(DETAIL_EXAMPLE['progress'], sot.progress) + self.assertEqual(DETAIL_EXAMPLE['status'], sot.status) + self.assertEqual(DETAIL_EXAMPLE['updated'], sot.updated) + self.assertEqual(DETAIL_EXAMPLE['OS-EXT-IMG-SIZE:size'], sot.size) diff --git a/openstack/tests/compute/v2/test_proxy.py b/openstack/tests/compute/v2/test_proxy.py index cfd367002..aad46eddd 100644 --- a/openstack/tests/compute/v2/test_proxy.py +++ b/openstack/tests/compute/v2/test_proxy.py @@ -59,10 +59,6 @@ class TestComputeProxy(test_proxy_base.TestProxyBase): self.verify_update('openstack.compute.v2.flavor.Flavor.update', self.proxy.update_flavor) - def test_image_create(self): - self.verify_create('openstack.compute.v2.image.Image.create', - self.proxy.create_image) - def test_image_delete(self): self.verify_delete('openstack.compute.v2.image.Image.delete', self.proxy.delete_image) @@ -75,13 +71,17 @@ class TestComputeProxy(test_proxy_base.TestProxyBase): self.verify_get('openstack.compute.v2.image.Image.get', self.proxy.get_image) - def test_image_list(self): + def test_image_list_basic(self): self.verify_list('openstack.compute.v2.image.Image.list', - self.proxy.list_images) + self.proxy.list_images, + method_kwargs={"details": False}, + expected_kwargs={"paginate": False}) - def test_image_update(self): - self.verify_update('openstack.compute.v2.image.Image.update', - self.proxy.update_image) + def test_image_list_detail(self): + self.verify_list('openstack.compute.v2.image.ImageDetail.list', + self.proxy.list_images, + method_kwargs={"details": True}, + expected_kwargs={"paginate": False}) def test_keypair_create(self): self.verify_create('openstack.compute.v2.keypair.Keypair.create',