From 040d9309c52a517c4236b3750fdde7a69c4be5e7 Mon Sep 17 00:00:00 2001 From: Mike Perez Date: Sun, 18 Nov 2012 21:27:39 -0800 Subject: [PATCH] Add volume bootable information to api response If there is any glance metadata associated with a volume, we'll consider the volume bootable. This will return the information for both /volumes and /detail calls. blueprint list-bootable-volumes Change-Id: Id9dbe5cb648be62fb19bb8bd6a97d8eab05ec25a --- cinder/api/openstack/volume/volumes.py | 5 +++ cinder/db/sqlalchemy/models.py | 5 +++ cinder/tests/api/openstack/fakes.py | 1 + .../api/openstack/volume/test_volumes.py | 35 +++++++++++++++++++ 4 files changed, 46 insertions(+) diff --git a/cinder/api/openstack/volume/volumes.py b/cinder/api/openstack/volume/volumes.py index 20208a16e..53abd8b54 100644 --- a/cinder/api/openstack/volume/volumes.py +++ b/cinder/api/openstack/volume/volumes.py @@ -113,6 +113,11 @@ def _translate_volume_summary_view(context, vol, image_id=None): else: d['metadata'] = {} + if vol.get('volume_glance_metadata'): + d['bootable'] = 'true' + else: + d['bootable'] = 'false' + return d diff --git a/cinder/db/sqlalchemy/models.py b/cinder/db/sqlalchemy/models.py index 664230dfa..aae7af6a7 100644 --- a/cinder/db/sqlalchemy/models.py +++ b/cinder/db/sqlalchemy/models.py @@ -213,6 +213,11 @@ class VolumeGlanceMetadata(BASE, CinderBase): snapshot_id = Column(String(36), ForeignKey('snapshots.id')) key = Column(String(255)) value = Column(Text) + volume = relationship(Volume, backref="volume_glance_metadata", + foreign_keys=volume_id, + primaryjoin='and_(' + 'VolumeGlanceMetadata.volume_id == Volume.id,' + 'VolumeGlanceMetadata.deleted == False)') class Quota(BASE, CinderBase): diff --git a/cinder/tests/api/openstack/fakes.py b/cinder/tests/api/openstack/fakes.py index 695322f08..97a5b95f5 100644 --- a/cinder/tests/api/openstack/fakes.py +++ b/cinder/tests/api/openstack/fakes.py @@ -188,6 +188,7 @@ def stub_volume(id, **kwargs): 'mountpoint': '/', 'status': 'fakestatus', 'attach_status': 'attached', + 'bootable': 'false', 'name': 'vol name', 'display_name': 'displayname', 'display_description': 'displaydesc', diff --git a/cinder/tests/api/openstack/volume/test_volumes.py b/cinder/tests/api/openstack/volume/test_volumes.py index 851e599bd..f717fc80e 100644 --- a/cinder/tests/api/openstack/volume/test_volumes.py +++ b/cinder/tests/api/openstack/volume/test_volumes.py @@ -83,6 +83,7 @@ class VolumeApiTest(test.TestCase): 'server_id': 'fakeuuid', 'id': '1', 'volume_id': '1'}], + 'bootable': 'false', 'volume_type': 'vol_type_name', 'snapshot_id': None, 'metadata': {}, @@ -140,6 +141,7 @@ class VolumeApiTest(test.TestCase): 'server_id': 'fakeuuid', 'id': '1', 'volume_id': '1'}], + 'bootable': 'false', 'volume_type': 'vol_type_name', 'image_id': 'c905cedb-7281-47e4-8a62-f26bc5fc4c77', 'snapshot_id': None, @@ -219,6 +221,7 @@ class VolumeApiTest(test.TestCase): 'server_id': 'fakeuuid', 'device': '/', }], + 'bootable': 'false', 'volume_type': 'vol_type_name', 'snapshot_id': None, 'metadata': {}, @@ -247,6 +250,7 @@ class VolumeApiTest(test.TestCase): 'server_id': 'fakeuuid', 'device': '/', }], + 'bootable': 'false', 'volume_type': 'vol_type_name', 'snapshot_id': None, 'metadata': {"qos_max_iops": 2000}, @@ -295,6 +299,7 @@ class VolumeApiTest(test.TestCase): 'server_id': 'fakeuuid', 'id': '1', 'volume_id': '1'}], + 'bootable': 'false', 'volume_type': 'vol_type_name', 'snapshot_id': None, 'metadata': {}, @@ -317,6 +322,7 @@ class VolumeApiTest(test.TestCase): 'server_id': 'fakeuuid', 'id': '1', 'volume_id': '1'}], + 'bootable': 'false', 'volume_type': 'vol_type_name', 'snapshot_id': None, 'metadata': {}, @@ -398,6 +404,7 @@ class VolumeApiTest(test.TestCase): 'server_id': 'fakeuuid', 'id': '1', 'volume_id': '1'}], + 'bootable': 'false', 'volume_type': 'vol_type_name', 'snapshot_id': None, 'metadata': {}, @@ -420,6 +427,34 @@ class VolumeApiTest(test.TestCase): 'availability_zone': 'fakeaz', 'display_name': 'displayname', 'attachments': [], + 'bootable': 'false', + 'volume_type': 'vol_type_name', + 'snapshot_id': None, + 'metadata': {}, + 'id': '1', + 'created_at': datetime.datetime(1, 1, 1, + 1, 1, 1), + 'size': 1}} + self.assertEqual(res_dict, expected) + + def test_volume_show_bootable(self): + def stub_volume_get(self, context, volume_id): + return (fakes.stub_volume(volume_id, + volume_glance_metadata=dict(foo='bar'))) + + self.stubs.Set(volume_api.API, 'get', stub_volume_get) + + req = fakes.HTTPRequest.blank('/v1/volumes/1') + res_dict = self.controller.show(req, '1') + expected = {'volume': {'status': 'fakestatus', + 'display_description': 'displaydesc', + 'availability_zone': 'fakeaz', + 'display_name': 'displayname', + 'attachments': [{'device': '/', + 'server_id': 'fakeuuid', + 'id': '1', + 'volume_id': '1'}], + 'bootable': 'true', 'volume_type': 'vol_type_name', 'snapshot_id': None, 'metadata': {}, -- 2.45.2