Merge "Move compute API is_volume_backed to BDM objects"

This commit is contained in:
Jenkins
2014-01-30 20:58:46 +00:00
committed by Gerrit Code Review
9 changed files with 173 additions and 159 deletions

View File

@@ -31,6 +31,7 @@ from nova import compute
from nova.compute import flavors
from nova import exception
from nova.image import glance
from nova.objects import block_device as block_device_obj
from nova.objects import instance as instance_obj
from nova.openstack.common.gettextutils import _
from nova.openstack.common import log as logging
@@ -904,21 +905,18 @@ class ServersController(wsgi.Controller):
instance = self._get_server(context, req, id)
bdms = self.compute_api.get_instance_bdms(context, instance,
legacy=False)
bdms = block_device_obj.BlockDeviceMappingList.get_by_instance_uuid(
context, instance.uuid)
try:
if self.compute_api.is_volume_backed_instance(context, instance,
bdms):
img = instance['image_ref']
if not img:
# NOTE(Vincent Hou) The private method
# _get_bdm_image_metadata only works, when boot
# device is set to 'vda'. It needs to be fixed later,
# but tentatively we use it here.
image_meta = {'properties': self.compute_api.
_get_bdm_image_metadata(context, bdms,
legacy_bdm=False)}
props = bdms.root_metadata(
context, self.compute_api.image_service,
self.compute_api.volume_api)
image_meta = {'properties': props}
else:
src_image = self.compute_api.\
image_service.show(context, img)

View File

@@ -32,6 +32,7 @@ from nova import block_device
from nova import compute
from nova.compute import flavors
from nova import exception
from nova.objects import block_device as block_device_obj
from nova.openstack.common.gettextutils import _
from nova.openstack.common import log as logging
from nova.openstack.common.rpc import common as rpc_common
@@ -1421,21 +1422,18 @@ class Controller(wsgi.Controller):
instance = self._get_server(context, req, id)
bdms = self.compute_api.get_instance_bdms(context, instance,
legacy=False)
bdms = block_device_obj.BlockDeviceMappingList.get_by_instance_uuid(
context, instance.uuid)
try:
if self.compute_api.is_volume_backed_instance(context, instance,
bdms):
img = instance['image_ref']
if not img:
# NOTE(Vincent Hou) The private method
# _get_bdm_image_metadata only works, when boot
# device is set to 'vda'. It needs to be fixed later,
# but tentatively we use it here.
image_meta = {'properties': self.compute_api.
_get_bdm_image_metadata(context, bdms,
legacy_bdm=False)}
props = bdms.root_metadata(
context, self.compute_api.image_service,
self.compute_api.volume_api)
image_meta = {'properties': props}
else:
src_image = self.compute_api.image_service.\
show(context, img)

View File

@@ -54,6 +54,7 @@ from nova import notifications
from nova import notifier
from nova.objects import aggregate as aggregate_obj
from nova.objects import base as obj_base
from nova.objects import block_device as block_device_obj
from nova.objects import flavor as flavor_obj
from nova.objects import instance as instance_obj
from nova.objects import instance_action
@@ -2519,14 +2520,12 @@ class API(base.Base):
def rescue(self, context, instance, rescue_password=None):
"""Rescue the given instance."""
bdms = self.get_instance_bdms(context, instance, legacy=False)
bdms = block_device_obj.BlockDeviceMappingList.get_by_instance_uuid(
context, instance['uuid'])
for bdm in bdms:
if bdm['volume_id']:
volume = self.volume_api.get(context, bdm['volume_id'])
self.volume_api.check_attached(context, volume)
# TODO(ndipanov): This check can be generalized as a decorator to
# check for valid combinations of src and dests - for now check
# if it's booted from volume only
if bdm.volume_id:
vol = self.volume_api.get(context, bdm.volume_id)
self.volume_api.check_attached(context, vol)
if self.is_volume_backed_instance(context, instance, bdms):
reason = _("Cannot rescue a volume-backed instance")
raise exception.InstanceNotRescuable(instance_id=instance['uuid'],
@@ -2925,12 +2924,13 @@ class API(base.Base):
return True
if bdms is None:
bdms = self.get_instance_bdms(context, instance, legacy=False)
bdms = block_device_obj.BlockDeviceMappingList.\
get_by_instance_uuid(context, instance['uuid'])
root_bdm = block_device.get_root_bdm(bdms)
if root_bdm and root_bdm.get('destination_type') == 'volume':
return True
root_bdm = bdms.root_bdm()
if not root_bdm:
return False
return root_bdm.is_volume
@check_instance_cell
@check_instance_state(vm_state=[vm_states.ACTIVE])

View File

@@ -4137,14 +4137,8 @@ class ComputeManager(manager.Manager):
:param dest_check_data: result of check_can_live_migrate_destination
:returns: a dict containing migration info
"""
capi = self.conductor_api
instance_p = obj_base.obj_to_primitive(instance)
bdms = capi.block_device_mapping_get_all_by_instance(ctxt, instance_p,
legacy=False)
is_volume_backed = self.compute_api.is_volume_backed_instance(ctxt,
instance,
bdms)
instance)
dest_check_data['is_volume_backed'] = is_volume_backed
return self.driver.check_can_live_migrate_source(ctxt, instance,
dest_check_data)

View File

@@ -56,6 +56,7 @@ from nova import test
from nova.tests.api.openstack.compute.contrib import (
test_neutron_security_groups as test_neutron)
from nova.tests import cast_as_call
from nova.tests import fake_block_device
from nova.tests import fake_network
from nova.tests import fake_utils
from nova.tests.image import fake
@@ -2283,18 +2284,17 @@ class CloudTestCase(test.TestCase):
self.stubs.Set(fake._FakeImageService, 'show', fake_show)
def fake_block_device_mapping_get_all_by_instance(context, inst_id):
return [dict(id=1,
source_type='snapshot',
destination_type='volume',
instance_uuid=inst_id,
snapshot_id=snapshots[0],
volume_id=volumes[0],
volume_size=1,
device_name='sda1',
delete_on_termination=False,
no_device=None,
boot_index=0,
connection_info='{"foo":"bar"}')]
return [fake_block_device.FakeDbBlockDeviceDict(
{'volume_id': volumes[0],
'snapshot_id': snapshots[0],
'source_type': 'snapshot',
'destination_type': 'volume',
'volume_size': 1,
'device_name': 'sda1',
'boot_index': 0,
'delete_on_termination': False,
'connection_info': '{"foo":"bar"}',
'no_device': None})]
self.stubs.Set(db, 'block_device_mapping_get_all_by_instance',
fake_block_device_mapping_get_all_by_instance)
@@ -2359,14 +2359,15 @@ class CloudTestCase(test.TestCase):
ec2_instance_id = self._run_instance(**kwargs)
def fake_block_device_mapping_get_all_by_instance(context, inst_id):
return [dict(snapshot_id=snapshots[0],
volume_id=volumes[0],
source_type='snapshot',
destination_type='volume',
volume_size=1,
device_name='vda',
delete_on_termination=False,
no_device=None)]
return [fake_block_device.FakeDbBlockDeviceDict(
{'volume_id': volumes[0],
'snapshot_id': snapshots[0],
'source_type': 'snapshot',
'destination_type': 'volume',
'volume_size': 1,
'device_name': 'vda',
'delete_on_termination': False,
'no_device': None})]
self.stubs.Set(db, 'block_device_mapping_get_all_by_instance',
fake_block_device_mapping_get_all_by_instance)

View File

@@ -34,6 +34,7 @@ from nova.openstack.common import jsonutils
from nova.openstack.common import uuidutils
from nova import test
from nova.tests.api.openstack import fakes
from nova.tests import fake_block_device
from nova.tests import fake_instance
from nova.tests.image import fake
@@ -855,15 +856,16 @@ class ServerActionsControllerTest(test.TestCase):
image_service.create(None, original_image)
def fake_block_device_mapping_get_all_by_instance(context, inst_id):
return [dict(volume_id=_fake_id('a'),
source_type='snapshot',
destination_type='volume',
volume_size=1,
device_name='vda',
snapshot_id=1,
boot_index=0,
delete_on_termination=False,
no_device=None)]
return [fake_block_device.FakeDbBlockDeviceDict(
{'volume_id': _fake_id('a'),
'source_type': 'snapshot',
'destination_type': 'volume',
'volume_size': 1,
'device_name': 'vda',
'snapshot_id': 1,
'boot_index': 0,
'delete_on_termination': False,
'no_device': None})]
self.stubs.Set(db, 'block_device_mapping_get_all_by_instance',
fake_block_device_mapping_get_all_by_instance)
@@ -922,15 +924,16 @@ class ServerActionsControllerTest(test.TestCase):
image_service = glance.get_default_image_service()
def fake_block_device_mapping_get_all_by_instance(context, inst_id):
return [dict(volume_id=_fake_id('a'),
source_type='snapshot',
destination_type='volume',
volume_size=1,
device_name='vda',
snapshot_id=1,
boot_index=0,
delete_on_termination=False,
no_device=None)]
return [fake_block_device.FakeDbBlockDeviceDict(
{'volume_id': _fake_id('a'),
'source_type': 'snapshot',
'destination_type': 'volume',
'volume_size': 1,
'device_name': 'vda',
'snapshot_id': 1,
'boot_index': 0,
'delete_on_termination': False,
'no_device': None})]
self.stubs.Set(db, 'block_device_mapping_get_all_by_instance',
fake_block_device_mapping_get_all_by_instance)
@@ -940,23 +943,22 @@ class ServerActionsControllerTest(test.TestCase):
root_device_name='/dev/vda')
self.stubs.Set(db, 'instance_get_by_uuid', instance)
fake_metadata = {'test_key1': 'test_value1',
'test_key2': 'test_value2'}
volume = dict(id=_fake_id('a'),
size=1,
host='fake',
display_description='fake')
display_description='fake',
volume_image_metadata=fake_metadata)
snapshot = dict(id=_fake_id('d'))
self.mox.StubOutWithMock(self.controller.compute_api, 'volume_api')
volume_api = self.controller.compute_api.volume_api
volume_api.get(mox.IgnoreArg(), volume['id']).AndReturn(volume)
volume_api.get(mox.IgnoreArg(), volume['id']).AndReturn(volume)
volume_api.create_snapshot_force(mox.IgnoreArg(), volume['id'],
mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(snapshot)
def fake_bdm_image_metadata(fd, context, bdms, legacy_bdm):
return {'test_key1': 'test_value1',
'test_key2': 'test_value2'}
req = fakes.HTTPRequestV3.blank(self.url)
self.stubs.Set(compute_api.API, '_get_bdm_image_metadata',
fake_bdm_image_metadata)
self.mox.ReplayAll()
response = self.controller._action_create_image(req, FAKE_UUID, body)

View File

@@ -34,6 +34,7 @@ from nova.openstack.common import jsonutils
from nova.openstack.common import uuidutils
from nova import test
from nova.tests.api.openstack import fakes
from nova.tests import fake_block_device
from nova.tests import fake_instance
from nova.tests.image import fake
from nova.tests import matchers
@@ -1021,15 +1022,16 @@ class ServerActionsControllerTest(test.TestCase):
image_service.create(None, original_image)
def fake_block_device_mapping_get_all_by_instance(context, inst_id):
return [dict(volume_id=_fake_id('a'),
source_type='snapshot',
destination_type='volume',
volume_size=1,
device_name='vda',
snapshot_id=1,
boot_index=0,
delete_on_termination=False,
no_device=None)]
return [fake_block_device.FakeDbBlockDeviceDict(
{'volume_id': _fake_id('a'),
'source_type': 'snapshot',
'destination_type': 'volume',
'volume_size': 1,
'device_name': 'vda',
'snapshot_id': 1,
'boot_index': 0,
'delete_on_termination': False,
'no_device': None})]
self.stubs.Set(db, 'block_device_mapping_get_all_by_instance',
fake_block_device_mapping_get_all_by_instance)
@@ -1088,15 +1090,16 @@ class ServerActionsControllerTest(test.TestCase):
image_service = glance.get_default_image_service()
def fake_block_device_mapping_get_all_by_instance(context, inst_id):
return [dict(volume_id=_fake_id('a'),
source_type='snapshot',
destination_type='volume',
volume_size=1,
device_name='vda',
snapshot_id=1,
boot_index=0,
delete_on_termination=False,
no_device=None)]
return [fake_block_device.FakeDbBlockDeviceDict(
{'volume_id': _fake_id('a'),
'source_type': 'snapshot',
'destination_type': 'volume',
'volume_size': 1,
'device_name': 'vda',
'snapshot_id': 1,
'boot_index': 0,
'delete_on_termination': False,
'no_device': None})]
self.stubs.Set(db, 'block_device_mapping_get_all_by_instance',
fake_block_device_mapping_get_all_by_instance)
@@ -1106,23 +1109,22 @@ class ServerActionsControllerTest(test.TestCase):
root_device_name='/dev/vda')
self.stubs.Set(db, 'instance_get_by_uuid', instance)
fake_metadata = {'test_key1': 'test_value1',
'test_key2': 'test_value2'}
volume = dict(id=_fake_id('a'),
size=1,
host='fake',
display_description='fake')
display_description='fake',
volume_image_metadata=fake_metadata)
snapshot = dict(id=_fake_id('d'))
self.mox.StubOutWithMock(self.controller.compute_api, 'volume_api')
volume_api = self.controller.compute_api.volume_api
volume_api.get(mox.IgnoreArg(), volume['id']).AndReturn(volume)
volume_api.get(mox.IgnoreArg(), volume['id']).AndReturn(volume)
volume_api.create_snapshot_force(mox.IgnoreArg(), volume['id'],
mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(snapshot)
def fake_bdm_image_metadata(fd, context, bdms, legacy_bdm):
return {'test_key1': 'test_value1',
'test_key2': 'test_value2'}
req = fakes.HTTPRequest.blank(self.url)
self.stubs.Set(compute_api.API, '_get_bdm_image_metadata',
fake_bdm_image_metadata)
self.mox.ReplayAll()
response = self.controller._action_create_image(req, FAKE_UUID, body)

View File

@@ -56,6 +56,7 @@ from nova.network import api as network_api
from nova.network import model as network_model
from nova.network.security_group import openstack_driver
from nova.objects import base as obj_base
from nova.objects import block_device as block_device_obj
from nova.objects import instance as instance_obj
from nova.objects import migration as migration_obj
from nova.objects import quotas as quotas_obj
@@ -72,6 +73,7 @@ from nova import quota
from nova import test
from nova.tests.compute import fake_resource_tracker
from nova.tests.db import fakes as db_fakes
from nova.tests import fake_block_device
from nova.tests import fake_instance
from nova.tests import fake_instance_actions
from nova.tests import fake_network
@@ -6869,11 +6871,47 @@ class ComputeAPITestCase(BaseTestCase):
self.compute.terminate_instance(self.context,
self._objectify(instance), [], [])
def test_rescue_volume_backed(self):
def _fake_rescue_block_devices(self, instance, status="in-use"):
fake_bdms = block_device_obj.block_device_make_list(self.context,
[fake_block_device.FakeDbBlockDeviceDict(
{'device_name': '/dev/vda',
'source_type': 'volume',
'boot_index': 0,
'destination_type': 'volume',
'volume_id': 'bf0b6b00-a20c-11e2-9e96-0800200c9a66'})])
volume = {'id': 'bf0b6b00-a20c-11e2-9e96-0800200c9a66',
'state': 'active', 'instance_uuid': instance['uuid']}
self.mox.StubOutWithMock(block_device_obj.BlockDeviceMappingList,
'get_by_instance_uuid')
self.mox.StubOutWithMock(cinder.API, 'get')
block_device_obj.BlockDeviceMappingList.get_by_instance_uuid(
self.context, instance['uuid']).AndReturn(fake_bdms)
cinder.API.get(self.context, volume['id']).AndReturn(
{'id': volume['id'], 'status': status})
def test_rescue_volume_backed_no_image(self):
# Instance started without an image
volume_backed_inst_1 = jsonutils.to_primitive(
self._create_fake_instance({'image_ref': ''}))
self._fake_rescue_block_devices(volume_backed_inst_1)
self.mox.ReplayAll()
self.compute.run_instance(self.context,
volume_backed_inst_1, {}, {}, None, None,
None, True, None, False)
self.assertRaises(exception.InstanceNotRescuable,
self.compute_api.rescue, self.context,
volume_backed_inst_1)
self.compute.terminate_instance(self.context,
self._objectify(volume_backed_inst_1), [], [])
def test_rescue_volume_backed_placeholder_image(self):
# Instance started with a placeholder image (for metadata)
volume_backed_inst_2 = jsonutils.to_primitive(
self._create_fake_instance(
@@ -6881,37 +6919,17 @@ class ComputeAPITestCase(BaseTestCase):
'root_device_name': '/dev/vda'})
)
def fake_get_instance_bdms(*args, **kwargs):
return [{'device_name': '/dev/vda',
'source_type': 'volume',
'boot_index': 0,
'destination_type': 'volume',
'volume_id': 'bf0b6b00-a20c-11e2-9e96-0800200c9a66'}]
self._fake_rescue_block_devices(volume_backed_inst_2)
self.mox.ReplayAll()
self.stubs.Set(self.compute_api, 'get_instance_bdms',
fake_get_instance_bdms)
def fake_volume_get(self, context, volume_id):
return {'id': volume_id, 'status': 'in-use'}
self.stubs.Set(cinder.API, 'get', fake_volume_get)
self.compute.run_instance(self.context,
volume_backed_inst_1, {}, {}, None, None,
None, True, None, False)
self.compute.run_instance(self.context,
volume_backed_inst_2, {}, {}, None, None,
None, True, None, False)
self.assertRaises(exception.InstanceNotRescuable,
self.compute_api.rescue, self.context,
volume_backed_inst_1)
self.assertRaises(exception.InstanceNotRescuable,
self.compute_api.rescue, self.context,
volume_backed_inst_2)
self.compute.terminate_instance(self.context,
self._objectify(volume_backed_inst_1), [], [])
self.compute.terminate_instance(self.context,
self._objectify(volume_backed_inst_2), [], [])
@@ -7611,33 +7629,46 @@ class ComputeAPITestCase(BaseTestCase):
instance = self._create_fake_instance({'root_device_name': 'vda'})
self.assertFalse(
self.compute_api.is_volume_backed_instance(ctxt, instance, []))
self.compute_api.is_volume_backed_instance(
ctxt, instance,
block_device_obj.block_device_make_list(ctxt, [])))
bdms = [{'device_name': '/dev/vda',
bdms = block_device_obj.block_device_make_list(ctxt,
[fake_block_device.FakeDbBlockDeviceDict(
{'source_type': 'volume',
'device_name': '/dev/vda',
'volume_id': 'fake_volume_id',
'boot_index': 0,
'destination_type': 'volume'}]
'destination_type': 'volume'})])
self.assertTrue(
self.compute_api.is_volume_backed_instance(ctxt, instance, bdms))
bdms = [{'device_name': '/dev/vda',
bdms = block_device_obj.block_device_make_list(ctxt,
[fake_block_device.FakeDbBlockDeviceDict(
{'source_type': 'volume',
'device_name': '/dev/vda',
'volume_id': 'fake_volume_id',
'destination_type': 'local',
'boot_index': 0,
'snapshot_id': None},
{'device_name': '/dev/vdb',
'snapshot_id': None}),
fake_block_device.FakeDbBlockDeviceDict(
{'source_type': 'volume',
'device_name': '/dev/vdb',
'boot_index': 1,
'destination_type': 'volume',
'volume_id': 'c2ec2156-d75e-11e2-985b-5254009297d6',
'snapshot_id': None}]
'snapshot_id': None})])
self.assertFalse(
self.compute_api.is_volume_backed_instance(ctxt, instance, bdms))
bdms = [{'device_name': '/dev/vda',
bdms = block_device_obj.block_device_make_list(ctxt,
[fake_block_device.FakeDbBlockDeviceDict(
{'source_type': 'volume',
'device_name': '/dev/vda',
'snapshot_id': 'de8836ac-d75e-11e2-8271-5254009297d6',
'destination_type': 'volume',
'boot_index': 0,
'volume_id': None}]
'volume_id': None})])
self.assertTrue(
self.compute_api.is_volume_backed_instance(ctxt, instance, bdms))
@@ -7645,9 +7676,11 @@ class ComputeAPITestCase(BaseTestCase):
ctxt = self.context
instance = self._create_fake_instance()
self.mox.StubOutWithMock(self.compute_api, 'get_instance_bdms')
self.compute_api.get_instance_bdms(ctxt, instance,
legacy=False).AndReturn([])
self.mox.StubOutWithMock(block_device_obj.BlockDeviceMappingList,
'get_by_instance_uuid')
block_device_obj.BlockDeviceMappingList.get_by_instance_uuid(
ctxt, instance['uuid']).AndReturn(
block_device_obj.block_device_make_list(ctxt, []))
self.mox.ReplayAll()
self.compute_api.is_volume_backed_instance(ctxt, instance, None)
@@ -7805,19 +7838,9 @@ class ComputeAPITestCase(BaseTestCase):
# Make sure a VM cannot be rescued while volume is being attached
instance = self._create_fake_instance()
def fake_get_instance_bdms(*args, **kwargs):
return [{'device_name': '/dev/vda',
'source_type': 'volume',
'destination_type': 'volume',
'volume_id': 'bf0b6b00-a20c-11e2-9e96-0800200c9a66'}]
self._fake_rescue_block_devices(instance, status="attaching")
self.mox.ReplayAll()
self.stubs.Set(self.compute_api, 'get_instance_bdms',
fake_get_instance_bdms)
def fake_volume_get(self, context, volume_id):
return {'id': volume_id, 'status': 'attaching'}
self.stubs.Set(cinder.API, 'get', fake_volume_get)
self.assertRaises(exception.InvalidVolume,
self.compute_api.rescue, self.context, instance)

View File

@@ -736,18 +736,14 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
expected_dest_check_data = dict(dest_check_data,
is_volume_backed=is_volume_backed)
self.mox.StubOutWithMock(self.compute.conductor_api,
'block_device_mapping_get_all_by_instance')
self.mox.StubOutWithMock(self.compute.compute_api,
'is_volume_backed_instance')
self.mox.StubOutWithMock(self.compute.driver,
'check_can_live_migrate_source')
instance_p = obj_base.obj_to_primitive(instance)
self.compute.conductor_api.block_device_mapping_get_all_by_instance(
self.context, instance_p, legacy=False).AndReturn(bdms)
self.compute.compute_api.is_volume_backed_instance(
self.context, instance, bdms).AndReturn(is_volume_backed)
self.context, instance).AndReturn(is_volume_backed)
self.compute.driver.check_can_live_migrate_source(
self.context, instance, expected_dest_check_data)