diff options
| -rw-r--r-- | nova/compute/api.py | 32 | ||||
| -rw-r--r-- | nova/tests/api/openstack/compute/test_servers.py | 24 | ||||
| -rw-r--r-- | nova/tests/compute/test_compute.py | 21 |
3 files changed, 74 insertions, 3 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py index f676c9797..e268cf2d9 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -539,7 +539,9 @@ class API(base.Base): files_to_inject): self._check_metadata_properties_quota(context, metadata) self._check_injected_file_quota(context, files_to_inject) - self._check_requested_image(context, image_id, image, instance_type) + if image_id is not None: + self._check_requested_image(context, image_id, + image, instance_type) def _validate_and_build_base_options(self, context, instance_type, image, image_href, image_id, @@ -686,6 +688,26 @@ class API(base.Base): QUOTAS.commit(context, quota_reservations) return instances + def _get_volume(self, context, block_device_mapping): + """If we are booting from a volume, we need to get the + volume details from Cinder and make sure we pass the + metadata back accordingly. + """ + if not block_device_mapping: + return {} + + for bdm in block_device_mapping: + if bdm.get('device_name') == "vda": + volume_id = bdm.get('volume_id') + if volume_id is not None: + try: + volume = self.volume_api.get(context, + volume_id) + return volume + except Exception: + raise exception.InvalidBDMVolume(volume_id) + return None + def _create_instance(self, context, instance_type, image_href, kernel_id, ramdisk_id, min_count, max_count, @@ -710,7 +732,13 @@ class API(base.Base): block_device_mapping = block_device_mapping or [] if not instance_type: instance_type = flavors.get_default_instance_type() - image_id, image = self._get_image(context, image_href) + + if image_href: + image_id, image = self._get_image(context, image_href) + else: + image_id = None + image = self._get_volume(context, + block_device_mapping) handle_az = self._handle_availability_zone availability_zone, forced_host, forced_node = handle_az( diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py index 6cdad1294..e11023308 100644 --- a/nova/tests/api/openstack/compute/test_servers.py +++ b/nova/tests/api/openstack/compute/test_servers.py @@ -24,6 +24,7 @@ import uuid import iso8601 from lxml import etree +import mox from oslo.config import cfg import webob @@ -1781,6 +1782,8 @@ class ServersControllerCreateTest(test.TestCase): self.ext_mgr.extensions = {} self.controller = servers.Controller(self.ext_mgr) + self.volume_id = 'fake' + def instance_create(context, inst): inst_type = flavors.get_instance_type_by_flavor_id(3) image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6' @@ -2441,7 +2444,25 @@ class ServersControllerCreateTest(test.TestCase): os-volumes extension is enabled and bdms are supplied """ self.ext_mgr.extensions = {'os-volumes': 'fake'} - bdm = [{'device_name': 'foo'}] + self.mox.StubOutWithMock(compute_api.API, '_validate_bdm') + self.mox.StubOutWithMock(compute_api.API, '_get_volume') + bdm = [{ + 'id': 1, + 'no_device': None, + 'virtual_name': None, + 'snapshot_id': None, + 'volume_id': self.volume_id, + 'status': 'active', + 'device_name': 'vda', + 'delete_on_termination': False, + 'volume_image_metadata': + {'test_key': 'test_value'} + }] + volume = bdm[0] + compute_api.API._validate_bdm(mox.IgnoreArg(), + mox.IgnoreArg()).AndReturn(True) + compute_api.API._get_volume(mox.IgnoreArg(), + bdm).AndReturn(volume) params = {'block_device_mapping': bdm} old_create = compute_api.API.create @@ -2451,6 +2472,7 @@ class ServersControllerCreateTest(test.TestCase): return old_create(*args, **kwargs) self.stubs.Set(compute_api.API, 'create', create) + self.mox.ReplayAll() self._test_create_extra(params, no_image=True) def test_create_instance_with_volumes_disabled(self): diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index fc3e0126b..7e31c7886 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -378,6 +378,27 @@ class ComputeVolumeTestCase(BaseTestCase): block_device_mapping) self.assertEqual(self.cinfo.get('serial'), self.volume_id) + def test_boot_volume_metadata(self): + self.mox.StubOutWithMock(self.compute_api.volume_api, 'get') + block_device_mapping = [{ + 'id': 1, + 'no_device': None, + 'virtual_name': None, + 'snapshot_id': None, + 'volume_id': self.volume_id, + 'status': 'active', + 'device_name': 'vda', + 'delete_on_termination': False, + 'volume_image_metadata': + {'test_key': 'test_value'} + }] + sentinel = object() + self.compute_api.volume_api.get(self.context, + self.volume_id).AndReturn(sentinel) + self.mox.ReplayAll() + vol = self.compute_api._get_volume(self.context, block_device_mapping) + self.assertIs(vol, sentinel) + def test_poll_volume_usage_disabled(self): ctxt = 'MockContext' self.mox.StubOutWithMock(self.compute, '_get_host_volume_bdms') |
