diff --git a/nova/api/openstack/compute/views/servers.py b/nova/api/openstack/compute/views/servers.py index f7f8c71def..3fe8757035 100644 --- a/nova/api/openstack/compute/views/servers.py +++ b/nova/api/openstack/compute/views/servers.py @@ -23,7 +23,10 @@ from nova.api.openstack import common from nova.api.openstack.compute.views import addresses as views_addresses from nova.api.openstack.compute.views import flavors as views_flavors from nova.api.openstack.compute.views import images as views_images +from nova import context as nova_context +from nova import exception from nova.i18n import _LW +from nova import objects from nova.objects import base as obj_base from nova import utils @@ -260,9 +263,26 @@ class ViewBuilder(common.ViewBuilder): }], } + def _load_fault(self, request, instance): + try: + mapping = objects.InstanceMapping.get_by_instance_uuid( + request.environ['nova.context'], instance.uuid) + if mapping.cell_mapping is not None: + with nova_context.target_cell(instance._context, + mapping.cell_mapping): + return instance.fault + except exception.InstanceMappingNotFound: + pass + + # NOTE(danms): No instance mapping at all, or a mapping with no cell, + # which means a legacy environment or instance. + return instance.fault + def _get_fault(self, request, instance): - # This can result in a lazy load of the fault information - fault = instance.fault + if 'fault' in instance: + fault = instance.fault + else: + fault = self._load_fault(request, instance) if not fault: return None diff --git a/nova/tests/unit/api/openstack/compute/test_serversV21.py b/nova/tests/unit/api/openstack/compute/test_serversV21.py index 3a886a1bf7..3bcae4787b 100644 --- a/nova/tests/unit/api/openstack/compute/test_serversV21.py +++ b/nova/tests/unit/api/openstack/compute/test_serversV21.py @@ -4049,6 +4049,29 @@ class ServersViewBuilderTest(test.TestCase): self.assertThat(output['server']['fault'], matchers.DictMatches(expected_fault)) + @mock.patch('nova.objects.InstanceMapping.get_by_instance_uuid') + def test_build_server_detail_with_fault_no_instance_mapping(self, + mock_im): + self.instance['vm_state'] = vm_states.ERROR + + mock_im.side_effect = exception.InstanceMappingNotFound(uuid='foo') + + self.request.context = context.RequestContext('fake', 'fake') + self.view_builder.show(self.request, self.instance) + mock_im.assert_called_once_with(mock.ANY, self.uuid) + + @mock.patch('nova.objects.InstanceMapping.get_by_instance_uuid') + def test_build_server_detail_with_fault_loaded(self, mock_im): + self.instance['vm_state'] = vm_states.ERROR + fault = fake_instance.fake_fault_obj(self.request.context, + self.uuid, code=500, + message="No valid host was found") + self.instance['fault'] = fault + + self.request.context = context.RequestContext('fake', 'fake') + self.view_builder.show(self.request, self.instance) + self.assertFalse(mock_im.called) + def test_build_server_detail_with_fault_no_details_not_admin(self): self.instance['vm_state'] = vm_states.ERROR self.instance['fault'] = fake_instance.fake_fault_obj(