From a9a2bca070b992bcf02628c1d0d394989f0a0d03 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Mon, 5 Dec 2016 12:21:51 -0800 Subject: [PATCH] Make servers api view load instance fault from proper cell Right now with CellsV2 the servers api will fail to load the fault for an instance because it does not target it to a particular cell. This makes us look up the instance mapping and use it to target loading of the fault. Change-Id: Ic2df2c3cfa66a91bd20437f534287e770b85f51d --- nova/api/openstack/compute/views/servers.py | 24 +++++++++++++++++-- .../api/openstack/compute/test_serversV21.py | 23 ++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) 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(