[OVN] Cleanup old Hash Ring node entries

This patch introduces a maintenance task that runs once a day and is
responsible for cleaning up Hash Ring nodes that haven't been updated in
5 days or more.

Change-Id: Ibed9e0d77500570c3d0f9f39bfe40cb9239d0d7a
Closes-Bug: #2033281
Signed-off-by: Lucas Alvares Gomes <lucasagomes@gmail.com>
This commit is contained in:
Lucas Alvares Gomes 2023-08-29 11:37:52 +01:00
parent 03e07ade2e
commit 7f777c223e
4 changed files with 55 additions and 0 deletions

View File

@ -60,6 +60,15 @@ def remove_node_by_uuid(context, node_uuid):
LOG.info('Node "%s" removed from the Hash Ring', node_uuid) LOG.info('Node "%s" removed from the Hash Ring', node_uuid)
@db_api.retry_if_session_inactive()
def cleanup_old_nodes(context, days):
age = timeutils.utcnow() - datetime.timedelta(days=days)
with db_api.CONTEXT_WRITER.using(context):
context.session.query(ovn_models.OVNHashRing).filter(
ovn_models.OVNHashRing.updated_at < age).delete()
LOG.info('Cleaned up Hash Ring nodes older than %d days', days)
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def _touch(context, updated_at=None, **filter_args): def _touch(context, updated_at=None, **filter_args):
if updated_at is None: if updated_at is None:

View File

@ -1103,6 +1103,20 @@ class DBInconsistenciesPeriodics(SchemaAwarePeriodicsBase):
for table in ('Chassis_Private', 'Chassis'): for table in ('Chassis_Private', 'Chassis'):
txn.add(self._sb_idl.db_destroy(table, ch.name)) txn.add(self._sb_idl.db_destroy(table, ch.name))
@periodics.periodic(spacing=86400, run_immediately=True)
def cleanup_old_hash_ring_nodes(self):
"""Daily task to cleanup old stable Hash Ring node entries.
Runs once a day and clean up Hash Ring entries that haven't
been updated in more than 5 days. See LP #2033281 for more
information.
"""
if not self.has_lock:
return
context = n_context.get_admin_context()
hash_ring_db.cleanup_old_nodes(context, days=5)
class HashRingHealthCheckPeriodics(object): class HashRingHealthCheckPeriodics(object):

View File

@ -285,3 +285,29 @@ class TestHashRing(testlib_api.SqlTestCaseLight):
self.admin_ctx, interval=60, group_name=HASH_RING_TEST_GROUP) self.admin_ctx, interval=60, group_name=HASH_RING_TEST_GROUP)
self.assertEqual(2, len(active_nodes)) self.assertEqual(2, len(active_nodes))
self.assertNotIn(node_to_remove, [n.node_uuid for n in active_nodes]) self.assertNotIn(node_to_remove, [n.node_uuid for n in active_nodes])
def test_cleanup_old_nodes(self):
# Add 2 new nodes
self._add_nodes_and_assert_exists(count=2)
# Subtract 5 days from utcnow() and touch the nodes to make
# them to appear stale
fake_utcnow = timeutils.utcnow() - datetime.timedelta(days=5)
with mock.patch.object(timeutils, 'utcnow') as mock_utcnow:
mock_utcnow.return_value = fake_utcnow
ovn_hash_ring_db.touch_nodes_from_host(self.admin_ctx,
HASH_RING_TEST_GROUP)
# Add 3 new nodes
self._add_nodes_and_assert_exists(count=3)
# Assert we have 5 nodes in the hash ring
self.assertEqual(5, ovn_hash_ring_db.count_nodes_from_host(
self.admin_ctx, HASH_RING_TEST_GROUP))
# Clean up the 2 stale nodes
ovn_hash_ring_db.cleanup_old_nodes(self.admin_ctx, days=5)
# Assert we only have 3 node entries after the clean up
self.assertEqual(3, ovn_hash_ring_db.count_nodes_from_host(
self.admin_ctx, HASH_RING_TEST_GROUP))

View File

@ -0,0 +1,6 @@
---
other:
- |
Adds a maintenance task that runs once a day and is responsible for
cleaning up Hash Ring nodes that haven't been updated in 5 days or
more. See LP #2033281 for more information.