diff --git a/nova/test.py b/nova/test.py index 3e89e1a8f2ac..03f98233d056 100644 --- a/nova/test.py +++ b/nova/test.py @@ -432,20 +432,29 @@ class TestCase(testtools.TestCase): ctxt = context.get_context() cell_name = kwargs.pop('cell', CELL1_NAME) or CELL1_NAME cell = self.cell_mappings[cell_name] - hm = objects.HostMapping(context=ctxt, - host=host or name, - cell_mapping=cell) - hm.create() - self.host_mappings[hm.host] = hm + if (host or name) not in self.host_mappings: + # NOTE(gibi): If the HostMapping does not exists then this is + # the first start of the service so we create the mapping. + hm = objects.HostMapping(context=ctxt, + host=host or name, + cell_mapping=cell) + hm.create() + self.host_mappings[hm.host] = hm svc = self.useFixture( nova_fixtures.ServiceFixture(name, host, cell=cell, **kwargs)) return svc.service - def restart_compute_service(self, compute): - """Restart a compute service in a realistic way. + def restart_compute_service(self, compute, keep_hypervisor_state=True): + """Stops the service and starts a new one to have realistic restart :param:compute: the nova-compute service to be restarted + :param:keep_hypervisor_state: If true then already defined instances + will survive the compute service restart. + If false then the new service will see + an empty hypervisor + :returns: a new compute service instance serving the same host and + and node """ # NOTE(gibi): The service interface cannot be used to simulate a real @@ -455,12 +464,36 @@ class TestCase(testtools.TestCase): # a stop start. The service.kill() call cannot help as it deletes # the service from the DB which is unrealistic and causes that some # operation that refers to the killed host (e.g. evacuate) fails. - # So this helper method tries to simulate a better compute service - # restart by cleaning up some of the internal state of the compute - # manager. + # So this helper method will stop the original service and then starts + # a brand new compute service for the same host and node. This way + # a new ComputeManager instance will be created and initialized during + # the service startup. compute.stop() - compute.manager._resource_tracker = None - compute.start() + + # this service was running previously so we have to make sure that + # we restart it in the same cell + cell_name = self.host_mappings[compute.host].cell_mapping.name + + if keep_hypervisor_state: + # NOTE(gibi): FakeDriver does not provide a meaningful way to + # define some servers that exists already on the hypervisor when + # the driver is (re)created during the service startup. This means + # that we cannot simulate that the definition of a server + # survives a nova-compute service restart on the hypervisor. + # Instead here we save the FakeDriver instance that knows about + # the defined servers and inject that driver into the new Manager + # class during the startup of the compute service. + old_driver = compute.manager.driver + with mock.patch( + 'nova.virt.driver.load_compute_driver') as load_driver: + load_driver.return_value = old_driver + new_compute = self.start_service( + 'compute', host=compute.host, cell=cell_name) + else: + new_compute = self.start_service( + 'compute', host=compute.host, cell=cell_name) + + return new_compute def assertJsonEqual(self, expected, observed, message=''): """Asserts that 2 complex data structures are json equivalent. diff --git a/nova/tests/functional/regressions/test_bug_1794996.py b/nova/tests/functional/regressions/test_bug_1794996.py index 2287fef61516..299759c4b19b 100644 --- a/nova/tests/functional/regressions/test_bug_1794996.py +++ b/nova/tests/functional/regressions/test_bug_1794996.py @@ -176,4 +176,4 @@ class TestEvacuateDeleteServerRestartOriginalCompute( self._delete_and_check_allocations(server) # restart the source compute - self.restart_compute_service(self.compute1) + self.compute1 = self.restart_compute_service(self.compute1) diff --git a/nova/tests/functional/test_servers.py b/nova/tests/functional/test_servers.py index 9d860a440fce..4ef536cbbbfe 100644 --- a/nova/tests/functional/test_servers.py +++ b/nova/tests/functional/test_servers.py @@ -2310,7 +2310,7 @@ class ServerMovingTests(integrated_helpers.ProviderUsageBaseTestCase): self.assertFlavorMatchesAllocation(self.flavor1, dest_allocation) # restart the source compute - self.restart_compute_service(self.compute1) + self.compute1 = self.restart_compute_service(self.compute1) self.admin_api.put_service( source_compute_id, {'forced_down': 'false'}) @@ -2387,7 +2387,7 @@ class ServerMovingTests(integrated_helpers.ProviderUsageBaseTestCase): self.assertFlavorMatchesAllocation(self.flavor1, dest_allocation) # restart the source compute - self.restart_compute_service(self.compute1) + self.compute1 = self.restart_compute_service(self.compute1) self.admin_api.put_service( source_compute_id, {'forced_down': 'false'}) @@ -2473,7 +2473,7 @@ class ServerMovingTests(integrated_helpers.ProviderUsageBaseTestCase): self.assertFlavorMatchesAllocation(self.flavor1, source_allocation) # restart the source compute - self.restart_compute_service(self.compute1) + self.compute1 = self.restart_compute_service(self.compute1) self.admin_api.put_service( source_compute_id, {'forced_down': 'false'}) @@ -2546,7 +2546,7 @@ class ServerMovingTests(integrated_helpers.ProviderUsageBaseTestCase): self.assertFlavorMatchesAllocation(self.flavor1, source_allocation) # restart the source compute - self.restart_compute_service(self.compute1) + self.compute1 = self.restart_compute_service(self.compute1) self.admin_api.put_service( source_compute_id, {'forced_down': 'false'})