summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/compute/api.py32
-rw-r--r--nova/tests/api/openstack/compute/test_servers.py24
-rw-r--r--nova/tests/compute/test_compute.py21
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')