summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Fried <openstack@fried.cc>2019-09-16 16:00:39 -0500
committerLee Yarwood <lyarwood@redhat.com>2021-02-04 17:06:53 +0000
commitbc30d78a5d22720b8bd739b1e6667332f2484d40 (patch)
treec85c2885b4f72d8e23ffe2704d7b80754518a24f
parente9e0998978f931e318690723ec4a4aed823e2943 (diff)
downloadnova-bc30d78a5d22720b8bd739b1e6667332f2484d40.tar.gz
Only allow one scheduler service in tests
There have been two recent issues [1][2] caused by starting multiple instances of the same service in tests. This can cause races when the services' (shared) state conflicts. With this patch, the nexus of nova service starting, nova.test.TestCase.start_service, is instrumented to keep track of how many of each service we are running. If we try to run the scheduler service more than once, we fail. We could probably do the same thing for conductor, though that's less important (for now) because conductor is stateless (for now). [1] https://bugs.launchpad.net/nova/+bug/1844174 [2] https://review.opendev.org/#/c/681059/ (not a nova service, but same class of problem) Change-Id: I56d3cb17260dad8b88f03c0a7b9688efb3258d6f (cherry picked from commit fe05d004b51dc9801749b0f5572e1a2392004830)
-rw-r--r--nova/test.py21
1 files changed, 21 insertions, 0 deletions
diff --git a/nova/test.py b/nova/test.py
index 96c7829741..a10f18043d 100644
--- a/nova/test.py
+++ b/nova/test.py
@@ -24,6 +24,7 @@ inline callbacks.
import nova.monkey_patch # noqa
import abc
+import collections
import copy
import datetime
import inspect
@@ -213,6 +214,9 @@ class TestCase(testtools.TestCase):
os.environ.get('OS_TEST_TIMEOUT', 0),
self.TIMEOUT_SCALING_FACTOR))
+ # How many of which service we've started. {$service-name: $count}
+ self._service_fixture_count = collections.defaultdict(int)
+
self.useFixture(nova_fixtures.OpenStackSDKFixture())
self.useFixture(fixtures.NestedTempfile())
@@ -426,6 +430,10 @@ class TestCase(testtools.TestCase):
CONF.set_override(k, v, group)
def start_service(self, name, host=None, **kwargs):
+ # Disallow starting multiple scheduler services
+ if name == 'scheduler' and self._service_fixture_count[name]:
+ raise TestingException("Duplicate start_service(%s)!" % name)
+
cell = None
# if the host is None then the CONF.host remains defaulted to
# 'fake-mini' (originally done in ConfFixture)
@@ -451,6 +459,19 @@ class TestCase(testtools.TestCase):
svc = self.useFixture(
nova_fixtures.ServiceFixture(name, host, cell=cell, **kwargs))
+ # Keep track of how many instances of this service are running.
+ self._service_fixture_count[name] += 1
+ real_stop = svc.service.stop
+
+ # Make sure stopping the service decrements the active count, so that
+ # start,stop,start doesn't trigger the "Duplicate start_service"
+ # exception.
+ def patch_stop(*a, **k):
+ self._service_fixture_count[name] -= 1
+ return real_stop(*a, **k)
+ self.useFixture(fixtures.MockPatchObject(
+ svc.service, 'stop', patch_stop))
+
return svc.service
def restart_compute_service(self, compute, keep_hypervisor_state=True):