[OVN] Remove maintenance method "remove_duplicated_chassis_registers"
Since OVN 21.03.0 [1], ovn-controller no longer will try to reuse the
stale Chassis/Chassis_Private records but will try to create new ones.
If the stale records have no been manually deleted and ovn-controller
tries to register a new Chassis with the same values, the transaction will
fail.
[1]fc359bfe93
Closes-Bug: #2073613
Change-Id: I2f14558b0910fed03fe0243c4daa33947feeedcb
This commit is contained in:
parent
ed927f8485
commit
836fd55073
@ -1011,63 +1011,6 @@ class DBInconsistenciesPeriodics(SchemaAwarePeriodicsBase):
|
|||||||
from_reload=True)
|
from_reload=True)
|
||||||
raise periodics.NeverAgain()
|
raise periodics.NeverAgain()
|
||||||
|
|
||||||
@periodics.periodic(spacing=300, run_immediately=True)
|
|
||||||
def remove_duplicated_chassis_registers(self):
|
|
||||||
"""Remove the "Chassis" and "Chassis_Private" duplicated registers.
|
|
||||||
|
|
||||||
When the ovn-controller service of a node is updated and the system-id
|
|
||||||
is changed, if the old service is not stopped gracefully, it will leave
|
|
||||||
a "Chassis" and a "Chassis_Private" registers on the OVN SB database.
|
|
||||||
These leftovers must be removed.
|
|
||||||
|
|
||||||
NOTE: this method is executed every 5 minutes. If a new chassis is
|
|
||||||
added, this method will perform again the clean-up process.
|
|
||||||
|
|
||||||
NOTE: this method can be executed only if the OVN SB has the
|
|
||||||
"Chassis_Private" table. Otherwise, is not possible to find out which
|
|
||||||
register is newer and thus must be kept in the database.
|
|
||||||
"""
|
|
||||||
if not self._sb_idl.is_table_present('Chassis_Private'):
|
|
||||||
raise periodics.NeverAgain()
|
|
||||||
|
|
||||||
if not self.has_lock:
|
|
||||||
return
|
|
||||||
|
|
||||||
# dup_chassis_port_host = {host_name: [(ch1, ch_private1),
|
|
||||||
# (ch2, ch_private2), ... ]}
|
|
||||||
dup_chassis_port_host = {}
|
|
||||||
chassis = self._sb_idl.chassis_list().execute(check_error=True)
|
|
||||||
chassis_hostnames = {ch.hostname for ch in chassis}
|
|
||||||
# Find the duplicated "Chassis" and "Chassis_Private" registers,
|
|
||||||
# comparing the hostname.
|
|
||||||
for hostname in chassis_hostnames:
|
|
||||||
ch_list = []
|
|
||||||
# Find these chassis matching the hostname and create a list.
|
|
||||||
for ch in (ch for ch in chassis if ch.hostname == hostname):
|
|
||||||
ch_private = self._sb_idl.lookup('Chassis_Private', ch.name,
|
|
||||||
default=None)
|
|
||||||
if ch_private:
|
|
||||||
ch_list.append((ch, ch_private))
|
|
||||||
|
|
||||||
# If the chassis list > 1, then we have duplicated chassis.
|
|
||||||
if len(ch_list) > 1:
|
|
||||||
# Order ch_list by Chassis_Private.nb_cfg_timestamp, from newer
|
|
||||||
# (greater value) to older.
|
|
||||||
ch_list.sort(key=lambda x: x[1].nb_cfg_timestamp, reverse=True)
|
|
||||||
dup_chassis_port_host[hostname] = ch_list
|
|
||||||
|
|
||||||
if not dup_chassis_port_host:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Remove the "Chassis" and "Chassis_Private" registers with the
|
|
||||||
# older Chassis_Private.nb_cfg_timestamp.
|
|
||||||
with self._sb_idl.transaction(check_error=True) as txn:
|
|
||||||
for ch_list in dup_chassis_port_host.values():
|
|
||||||
# The first item is skipped, this is the newest element.
|
|
||||||
for ch, ch_private in ch_list[1:]:
|
|
||||||
for table in ('Chassis_Private', 'Chassis'):
|
|
||||||
txn.add(self._sb_idl.db_destroy(table, ch.name))
|
|
||||||
|
|
||||||
@has_lock_periodic(spacing=86400, run_immediately=True)
|
@has_lock_periodic(spacing=86400, run_immediately=True)
|
||||||
def cleanup_old_hash_ring_nodes(self):
|
def cleanup_old_hash_ring_nodes(self):
|
||||||
"""Daily task to cleanup old stable Hash Ring node entries.
|
"""Daily task to cleanup old stable Hash Ring node entries.
|
||||||
|
@ -1014,64 +1014,6 @@ class TestMaintenance(_TestMaintenanceHelper):
|
|||||||
lsp = self.nb_api.lookup('Logical_Switch_Port', p1['id'])
|
lsp = self.nb_api.lookup('Logical_Switch_Port', p1['id'])
|
||||||
self.assertEqual(hcg_uuid, lsp.ha_chassis_group[0].uuid)
|
self.assertEqual(hcg_uuid, lsp.ha_chassis_group[0].uuid)
|
||||||
|
|
||||||
def test_remove_duplicated_chassis_registers(self):
|
|
||||||
hostnames = ['host1', 'host2']
|
|
||||||
for hostname in hostnames:
|
|
||||||
for _ in range(3):
|
|
||||||
self.add_fake_chassis(hostname)
|
|
||||||
|
|
||||||
chassis = self.sb_api.chassis_list().execute(check_error=True)
|
|
||||||
self.assertEqual(6, len(chassis))
|
|
||||||
# Make the chassis private timestamp different
|
|
||||||
for idx, ch in enumerate(chassis):
|
|
||||||
self.sb_api.db_set('Chassis_Private', ch.name,
|
|
||||||
('nb_cfg_timestamp', idx)).execute()
|
|
||||||
|
|
||||||
ch_private_dict = {} # host: [ch_private1, ch_private2, ...]
|
|
||||||
for hostname in hostnames:
|
|
||||||
ch_private_list = []
|
|
||||||
for ch in (ch for ch in chassis if ch.hostname == hostname):
|
|
||||||
ch_private = self.sb_api.lookup('Chassis_Private', ch.name,
|
|
||||||
default=None)
|
|
||||||
if ch_private:
|
|
||||||
# One of the "Chassis_Private" has been deleted on purpose
|
|
||||||
# in this test.
|
|
||||||
ch_private_list.append(ch_private)
|
|
||||||
ch_private_list.sort(key=lambda x: x.nb_cfg_timestamp,
|
|
||||||
reverse=True)
|
|
||||||
ch_private_dict[hostname] = ch_private_list
|
|
||||||
|
|
||||||
self.maint.remove_duplicated_chassis_registers()
|
|
||||||
chassis_result = self.sb_api.chassis_list().execute(check_error=True)
|
|
||||||
self.assertEqual(2, len(chassis_result))
|
|
||||||
for ch in chassis_result:
|
|
||||||
self.assertIn(ch.hostname, hostnames)
|
|
||||||
hostnames.remove(ch.hostname)
|
|
||||||
# From ch_private_dict[ch.hostname], we retrieve the first
|
|
||||||
# "Chassis_Private" register because these are ordered by
|
|
||||||
# timestamp. The newer one (bigger timestamp) should remain in the
|
|
||||||
# system.
|
|
||||||
ch_expected = ch_private_dict[ch.hostname][0].chassis[0]
|
|
||||||
self.assertEqual(ch_expected.name, ch.name)
|
|
||||||
|
|
||||||
def test_remove_duplicated_chassis_registers_no_ch_private_register(self):
|
|
||||||
for _ in range(2):
|
|
||||||
self.add_fake_chassis('host1')
|
|
||||||
|
|
||||||
chassis = self.sb_api.chassis_list().execute(check_error=True)
|
|
||||||
self.assertEqual(2, len(chassis))
|
|
||||||
# Make the chassis private timestamp different
|
|
||||||
# Delete on of the "Chassis_Private" registers.
|
|
||||||
self.sb_api.db_destroy('Chassis_Private', chassis[0].name).execute()
|
|
||||||
self.sb_api.db_set('Chassis_Private', chassis[1].name,
|
|
||||||
('nb_cfg_timestamp', 1)).execute()
|
|
||||||
|
|
||||||
self.maint.remove_duplicated_chassis_registers()
|
|
||||||
chassis_result = self.sb_api.chassis_list().execute(check_error=True)
|
|
||||||
# Both "Chassis" registers are still in the DB because one
|
|
||||||
# "Chassis_Private" register was missing.
|
|
||||||
self.assertEqual(2, len(chassis_result))
|
|
||||||
|
|
||||||
def test_configure_nb_global(self):
|
def test_configure_nb_global(self):
|
||||||
def options_intersect(options1, options2):
|
def options_intersect(options1, options2):
|
||||||
return bool(set(
|
return bool(set(
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
deprecations:
|
||||||
|
- |
|
||||||
|
Removed the maintenance method ``remove_duplicated_chassis_registers``.
|
||||||
|
This method is no longer needed since OVN 21.03.0. For more information,
|
||||||
|
see the bug
|
||||||
|
`2073613 <https://bugs.launchpad.net/neutron/+bug/2073613>`_.
|
Loading…
Reference in New Issue
Block a user