summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Macdonald-Wallace <matthew.macdonald-wallace@hp.com>2013-06-07 15:20:00 +0100
committerStanislaw Pitucha <stanislaw.pitucha@hp.com>2013-06-07 17:33:27 +0100
commite67641da51610a419ec8cf6562583d14a2b0fbd7 (patch)
treeaf322ab0b0d290cfa93b6d9b467094925f1fdc99
parent7a475d3cd606e68090075c1a8944e3aeb7898b87 (diff)
downloadnova-e67641da51610a419ec8cf6562583d14a2b0fbd7.tar.gz
nova-e67641da51610a419ec8cf6562583d14a2b0fbd7.tar.xz
nova-e67641da51610a419ec8cf6562583d14a2b0fbd7.zip
Export volume metadata to new instances.
Instances that are booted from volume currently miss out on glance metadata that instances booted from images receive. By extracting that data and passing it on in the create request we make it available to both sorts of instance boot, fixing bug 1175571. Change-Id: I8c01ba3065a909ca8e1805db9a10a423b10fe289
-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')