Skip to content

Commit d892905

Browse files
committed
Protect against a deleted node id file
If we are starting up for the first time, we expect to generate and write a node_uuid file if one does not exist. If we are upgrading, we expect to do the same. However, if we are starting up not after an upgrade and not for the first time, a missing compute_id file is an error, and we should abort. Because of the additional check that this adds, which is called from a variety of places that don't have the stable compute node singleton stubbed to make it happy, this mocks the check for any test that does not specifically aim to exercise it. Related to blueprint stable-compute-uuid Change-Id: If83ce14b96e7d84ae38eba9d798754557d5abdfd
1 parent 72370a1 commit d892905

File tree

4 files changed

+42
-8
lines changed

4 files changed

+42
-8
lines changed

nova/compute/manager.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,15 +1509,21 @@ def _ensure_existing_node_identity(self, service_ref):
15091509
to write our node identity uuid (if not already done) based on
15101510
nodes assigned to us in the database.
15111511
"""
1512-
if service_ref.version >= service_obj.NODE_IDENTITY_VERSION:
1513-
# Already new enough, nothing to do here
1514-
return
1515-
15161512
if 'ironic' in CONF.compute_driver.lower():
15171513
# We do not persist a single local node identity for
15181514
# ironic
15191515
return
15201516

1517+
if service_ref.version >= service_obj.NODE_IDENTITY_VERSION:
1518+
# Already new enough, nothing to do here, but make sure that we
1519+
# have a UUID file already, as this is not our first time starting.
1520+
if nova.virt.node.read_local_node_uuid() is None:
1521+
raise exception.InvalidConfiguration(
1522+
('No local node identity found, but this is not our '
1523+
'first startup on this host. Refusing to start after '
1524+
'potentially having lost that state!'))
1525+
return
1526+
15211527
if nova.virt.node.read_local_node_uuid():
15221528
# We already have a local node identity, no migration needed
15231529
return

nova/test.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,12 @@ class TestCase(base.BaseTestCase):
171171
# base class when USES_DB is True.
172172
NUMBER_OF_CELLS = 1
173173

174+
# The stable compute id stuff is intentionally singleton-ish, which makes
175+
# it a nightmare for testing multiple host/node combinations in tests like
176+
# we do. So, mock it out by default, unless the test is specifically
177+
# designed to handle it.
178+
STUB_COMPUTE_ID = True
179+
174180
def setUp(self):
175181
"""Run before each test method to initialize test environment."""
176182
# Ensure BaseTestCase's ConfigureLogging fixture is disabled since
@@ -301,7 +307,8 @@ def setUp(self):
301307

302308
# Reset our local node uuid cache (and avoid writing to the
303309
# local filesystem when we generate a new one).
304-
self.useFixture(nova_fixtures.ComputeNodeIdFixture())
310+
if self.STUB_COMPUTE_ID:
311+
self.useFixture(nova_fixtures.ComputeNodeIdFixture())
305312

306313
def _setup_cells(self):
307314
"""Setup a normal cellsv2 environment.

nova/tests/fixtures/nova.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,3 +1863,7 @@ def setUp(self):
18631863
self.useFixture(fixtures.MockPatch(
18641864
'nova.virt.node.write_local_node_uuid',
18651865
lambda uuid: None))
1866+
self.useFixture(fixtures.MockPatch(
1867+
'nova.compute.manager.ComputeManager.'
1868+
'_ensure_existing_node_identity',
1869+
mock.DEFAULT))

nova/tests/unit/compute/test_compute_mgr.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
9191
# os-brick>=5.1 now uses external file system locks instead of internal
9292
# locks so we need to set up locking
9393
REQUIRES_LOCKING = True
94+
STUB_COMPUTE_ID = False
9495

9596
def setUp(self):
9697
super(ComputeManagerUnitTestCase, self).setUp()
@@ -6361,13 +6362,15 @@ def test_cache_images_multi(self):
63616362
'two-image': 'existing'}, r)
63626363

63636364
@mock.patch.object(virt_node, 'write_local_node_uuid')
6364-
def test_ensure_node_uuid_not_needed_version(self, mock_node):
6365+
@mock.patch.object(virt_node, 'read_local_node_uuid')
6366+
def test_ensure_node_uuid_not_needed_version(self, mock_read, mock_write):
63656367
# Make sure an up-to-date service bypasses the persistence
63666368
service_ref = service_obj.Service()
63676369
self.assertEqual(service_obj.SERVICE_VERSION, service_ref.version)
6368-
mock_node.assert_not_called()
6370+
mock_read.return_value = 'not none'
6371+
mock_write.assert_not_called()
63696372
self.compute._ensure_existing_node_identity(service_ref)
6370-
mock_node.assert_not_called()
6373+
mock_write.assert_not_called()
63716374

63726375
@mock.patch.object(virt_node, 'write_local_node_uuid')
63736376
def test_ensure_node_uuid_not_needed_ironic(self, mock_node):
@@ -6452,6 +6455,20 @@ def test_ensure_node_uuid_upgrade_writes_node_uuid(self, mock_get_cn,
64526455
mock_get_cn.assert_called_once_with(mock.ANY, self.compute.host)
64536456
mock_write_node.assert_called_once_with(str(uuids.compute))
64546457

6458+
@mock.patch.object(virt_node, 'read_local_node_uuid')
6459+
def test_ensure_node_uuid_missing_file_ironic(self, mock_read):
6460+
mock_service = mock.MagicMock(
6461+
version=service_obj.NODE_IDENTITY_VERSION)
6462+
mock_read.return_value = None
6463+
self.assertRaises(exception.InvalidConfiguration,
6464+
self.compute._ensure_existing_node_identity,
6465+
mock_service)
6466+
mock_read.assert_called_once_with()
6467+
6468+
# Now make sure that ironic causes this exact configuration to pass
6469+
self.flags(compute_driver='ironic')
6470+
self.compute._ensure_existing_node_identity(mock_service)
6471+
64556472
def test_ensure_node_uuid_called_by_init_host(self):
64566473
# test_init_host() above ensures that we do not call
64576474
# _ensure_existing_node_identity() in the service_ref=None case.

0 commit comments

Comments
 (0)