diff options
| -rw-r--r-- | nova/compute/api.py | 31 | ||||
| -rw-r--r-- | nova/compute/manager.py | 20 | ||||
| -rw-r--r-- | nova/compute/rpcapi.py | 12 | ||||
| -rw-r--r-- | nova/tests/compute/test_compute.py | 57 | ||||
| -rw-r--r-- | nova/tests/compute/test_rpcapi.py | 7 |
5 files changed, 113 insertions, 14 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py index e98f8a654..29f52c4e5 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1358,6 +1358,27 @@ class API(base.Base): return min_ram, min_disk + def _get_block_device_info(self, context, instance_uuid): + bdms = self.db.block_device_mapping_get_all_by_instance(context, + instance_uuid) + block_device_mapping = [] + for bdm in bdms: + if not bdm['volume_id']: + continue + try: + cinfo = jsonutils.loads(bdm['connection_info']) + if cinfo and 'serial' not in cinfo: + cinfo['serial'] = bdm['volume_id'] + bdmap = {'connection_info': cinfo, + 'mount_device': bdm['volume_id'], + 'delete_on_termination': bdm['delete_on_termination']} + block_device_mapping.append(bdmap) + except TypeError: + # if the block_device_mapping has no value in connection_info + # (returned as None), don't include in the mapping + pass + return {'block_device_mapping': block_device_mapping} + @wrap_check_policy @check_instance_lock @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED, @@ -1377,8 +1398,16 @@ class API(base.Base): task_state=state, expected_task_state=[None, task_states.REBOOTING]) + elevated = context.elevated() + block_info = self._get_block_device_info(elevated, + instance['uuid']) + network_info = self.network_api.get_instance_nw_info(elevated, + instance) + self.compute_rpcapi.reboot_instance(context, instance=instance, - reboot_type=reboot_type) + block_device_info=block_info, + network_info=network_info, + reboot_type=reboot_type) def _get_image(self, context, image_href): """Throws an ImageNotFound exception if image_href does not exist.""" diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 46760e772..8057ae4e1 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -210,7 +210,7 @@ def _get_image_meta(context, image_ref): class ComputeManager(manager.SchedulerDependentManager): """Manages the running instances from creation to destruction.""" - RPC_API_VERSION = '2.4' + RPC_API_VERSION = '2.5' def __init__(self, compute_driver=None, *args, **kwargs): """Load configuration options and connect to the hypervisor.""" @@ -1093,11 +1093,22 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @reverts_task_state @wrap_instance_fault - def reboot_instance(self, context, instance, reboot_type="SOFT"): + def reboot_instance(self, context, instance, + block_device_info=None, + network_info=None, + reboot_type="SOFT"): """Reboot an instance on this host.""" context = context.elevated() LOG.audit(_("Rebooting instance"), context=context, instance=instance) + # NOTE(danms): remove these when RPC API < 2.5 compatibility + # is no longer needed + if block_device_info is None: + block_device_info = self._get_instance_volume_block_device_info( + context, instance['uuid']) + if network_info is None: + network_info = self._get_instance_nw_info(context, instance) + self._notify_about_instance_usage(context, instance, "reboot.start") current_power_state = self._get_power_state(context, instance) @@ -1113,11 +1124,6 @@ class ComputeManager(manager.SchedulerDependentManager): 'expected: %(running)s)') % locals(), context=context, instance=instance) - network_info = self._get_instance_nw_info(context, instance) - - block_device_info = self._get_instance_volume_block_device_info( - context, instance['uuid']) - try: self.driver.reboot(instance, self._legacy_nw_info(network_info), reboot_type, block_device_info) diff --git a/nova/compute/rpcapi.py b/nova/compute/rpcapi.py index e0c4bae3b..6a47bb096 100644 --- a/nova/compute/rpcapi.py +++ b/nova/compute/rpcapi.py @@ -132,6 +132,7 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy): remove_aggregate_host() 2.3 - Adds volume_id to reserve_block_device_name() 2.4 - Add bdms to terminate_instance + 2.5 - Add block device and network info to reboot_instance ''' # @@ -342,11 +343,16 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy): image=image, reservations=reservations), _compute_topic(self.topic, ctxt, host, None)) - def reboot_instance(self, ctxt, instance, reboot_type): + def reboot_instance(self, ctxt, instance, + block_device_info, network_info, reboot_type): instance_p = jsonutils.to_primitive(instance) self.cast(ctxt, self.make_msg('reboot_instance', - instance=instance_p, reboot_type=reboot_type), - topic=_compute_topic(self.topic, ctxt, None, instance)) + instance=instance_p, + block_device_info=block_device_info, + network_info=network_info, + reboot_type=reboot_type), + topic=_compute_topic(self.topic, ctxt, None, instance), + version='2.5') def rebuild_instance(self, ctxt, instance, new_pass, injected_files, image_ref, orig_image_ref, orig_sys_metadata): diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index 979dc9a5d..2479bc946 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -870,6 +870,15 @@ class ComputeTestCase(BaseTestCase): self.compute.terminate_instance(self.context, instance=jsonutils.to_primitive(instance)) + def _stub_out_reboot(self, fake_net_info, fake_block_dev_info): + def fake_reboot(driver, inst, net_info, reboot_type, block_dev_info): + self.assertEqual(block_dev_info, fake_block_dev_info) + self.assertEqual(net_info, fake_net_info) + + self.stubs.Set(nova.virt.fake.FakeDriver, 'legacy_nwinfo', + lambda x: False) + self.stubs.Set(nova.virt.fake.FakeDriver, 'reboot', fake_reboot) + def test_reboot_soft(self): """Ensure instance can be soft rebooted""" instance = jsonutils.to_primitive(self._create_fake_instance()) @@ -878,8 +887,12 @@ class ComputeTestCase(BaseTestCase): {'task_state': task_states.REBOOTING}) reboot_type = "SOFT" - self.compute.reboot_instance(self.context, - instance=instance, + fake_net_info = {'bar': 'baz'} + fake_block_dev_info = {'foo': 'bar'} + self._stub_out_reboot(fake_net_info, fake_block_dev_info) + self.compute.reboot_instance(self.context, instance=instance, + network_info=fake_net_info, + block_device_info=fake_block_dev_info, reboot_type=reboot_type) inst_ref = db.instance_get_by_uuid(self.context, instance['uuid']) @@ -897,7 +910,12 @@ class ComputeTestCase(BaseTestCase): {'task_state': task_states.REBOOTING_HARD}) reboot_type = "HARD" + fake_net_info = {'bar': 'baz'} + fake_block_dev_info = {'foo': 'bar'} + self._stub_out_reboot(fake_net_info, fake_block_dev_info) self.compute.reboot_instance(self.context, instance=instance, + network_info=fake_net_info, + block_device_info=fake_block_dev_info, reboot_type=reboot_type) inst_ref = db.instance_get_by_uuid(self.context, instance['uuid']) @@ -3268,15 +3286,40 @@ class ComputeAPITestCase(BaseTestCase): 'preserved': 'preserve this!'}) db.instance_destroy(self.context, instance['uuid']) + def _stub_out_reboot(self, volume_id): + def fake_reboot_instance(rpcapi, context, instance, + block_device_info, + network_info, + reboot_type): + self.assertEqual( + block_device_info['block_device_mapping'][0]['mount_device'], + volume_id) + self.assertEqual(network_info[0]['network']['bridge'], 'fake_br1') + self.stubs.Set(nova.compute.rpcapi.ComputeAPI, 'reboot_instance', + fake_reboot_instance) + + self.stubs.Set(nova.virt.fake.FakeDriver, 'legacy_nwinfo', + lambda x: False) + def test_reboot_soft(self): """Ensure instance can be soft rebooted""" instance = jsonutils.to_primitive(self._create_fake_instance()) self.compute.run_instance(self.context, instance=instance) + volume_id = db.volume_create(context.get_admin_context(), + {'size': 1})['id'] + volume = {'instance_uuid': instance['uuid'], + 'device_name': '/dev/vdc', + 'delete_on_termination': False, + 'connection_info': '{"foo": "bar"}', + 'volume_id': volume_id} + db.block_device_mapping_create(self.context, volume) + inst_ref = db.instance_get_by_uuid(self.context, instance['uuid']) self.assertEqual(inst_ref['task_state'], None) reboot_type = "SOFT" + self._stub_out_reboot(volume_id) self.compute_api.reboot(self.context, inst_ref, reboot_type) inst_ref = db.instance_get_by_uuid(self.context, inst_ref['uuid']) @@ -3289,10 +3332,20 @@ class ComputeAPITestCase(BaseTestCase): instance = jsonutils.to_primitive(self._create_fake_instance()) self.compute.run_instance(self.context, instance=instance) + volume_id = db.volume_create(context.get_admin_context(), + {'size': 1})['id'] + volume = {'instance_uuid': instance['uuid'], + 'device_name': '/dev/vdc', + 'delete_on_termination': False, + 'connection_info': '{"foo": "bar"}', + 'volume_id': volume_id} + db.block_device_mapping_create(self.context, volume) + inst_ref = db.instance_get_by_uuid(self.context, instance['uuid']) self.assertEqual(inst_ref['task_state'], None) reboot_type = "HARD" + self._stub_out_reboot(volume_id) self.compute_api.reboot(self.context, inst_ref, reboot_type) inst_ref = db.instance_get_by_uuid(self.context, inst_ref['uuid']) diff --git a/nova/tests/compute/test_rpcapi.py b/nova/tests/compute/test_rpcapi.py index 304f9adb3..2fa6bf9ee 100644 --- a/nova/tests/compute/test_rpcapi.py +++ b/nova/tests/compute/test_rpcapi.py @@ -216,8 +216,13 @@ class ComputeRpcAPITestCase(test.TestCase): reservations=list('fake_res')) def test_reboot_instance(self): + self.maxDiff = None self._test_compute_api('reboot_instance', 'cast', - instance=self.fake_instance, reboot_type='type') + instance=self.fake_instance, + block_device_info={}, + network_info={}, + reboot_type='type', + version='2.5') def test_rebuild_instance(self): self._test_compute_api('rebuild_instance', 'cast', |
