Use agent chassis table based on schema

The patch determines a table that should be used for the agent API
in the runtime, based on the current available schema. It means OVN
database can be updated or downgraded while neutron-server is running
and agents will always report its liveness based on currently available
tables.

Change-Id: I679945b68acf391901c8602fb1828c46cd1eec55
Closes-bug: #1901527
Signed-off-by: Jakub Libosvar <libosvar@redhat.com>
This commit is contained in:
Jakub Libosvar 2020-11-13 11:01:21 +00:00
parent ab8a17c6a4
commit da8e655963
4 changed files with 90 additions and 2 deletions

View File

@ -79,7 +79,7 @@ oslo.versionedobjects==1.35.1
oslotest==3.2.0
osprofiler==2.3.0
ovs==2.10.0
ovsdbapp==1.6.0
ovsdbapp==1.7.0
packaging==20.4
Paste==2.0.2
PasteDeploy==1.5.0

View File

@ -545,8 +545,30 @@ class OvnIdlDistributedLock(BaseOvnIdl):
self._hash_ring = hash_ring_manager.HashRingManager(
self.driver.hash_ring_group)
self._last_touch = None
# This is a map of tables that may be new after OVN database is updated
self._tables_to_register = {
'OVN_Southbound': ['Chassis_Private'],
}
def handle_db_schema_changes(self, event, row):
if (event == row_event.RowEvent.ROW_CREATE and
row._table.name == 'Database'):
try:
tables = self._tables_to_register[row.name]
except KeyError:
return
self.update_tables(tables, row.schema[0])
if 'Chassis_Private' == self.driver.agent_chassis_table:
if 'Chassis_Private' not in self.tables:
self.driver.agent_chassis_table = 'Chassis'
else:
if 'Chassis_Private' in self.tables:
self.driver.agent_chassis_table = 'Chassis_Private'
def notify(self, event, row, updates=None):
self.handle_db_schema_changes(event, row)
self.notify_handler.notify(event, row, updates, global_=True)
try:
target_node = self._hash_ring.get_node(str(row.uuid))

View File

@ -219,6 +219,8 @@ class TestOvnIdlDistributedLock(base.BaseTestCase):
self.mock_get_node = mock.patch.object(
hash_ring_manager.HashRingManager,
'get_node', return_value=self.node_uuid).start()
self.mock_update_tables = mock.patch.object(
self.idl, 'update_tables').start()
def _assert_has_notify_calls(self):
self.idl.notify_handler.notify.assert_has_calls([
@ -279,6 +281,69 @@ class TestOvnIdlDistributedLock(base.BaseTestCase):
self.idl.notify_handler.notify.assert_called_once_with(
self.fake_event, self.fake_row, None, global_=True)
@staticmethod
def _create_fake_row(table_name):
# name is a parameter in Mock() so it can't be passed to constructor
table = mock.Mock()
table.name = table_name
return fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'_table': table, 'schema': ['foo']})
def test_handle_db_schema_changes_no_match_events(self):
other_table_row = self._create_fake_row('other')
database_table_row = self._create_fake_row('Database')
self.idl.handle_db_schema_changes(
ovsdb_monitor.BaseEvent.ROW_UPDATE, other_table_row)
self.idl.handle_db_schema_changes(
ovsdb_monitor.BaseEvent.ROW_CREATE, other_table_row)
self.idl.handle_db_schema_changes(
ovsdb_monitor.BaseEvent.ROW_UPDATE, database_table_row)
self.assertFalse(self.mock_update_tables.called)
def _test_handle_db_schema(self, agent_table, chassis_private_present):
database_table_row = self._create_fake_row('Database')
self.idl._tables_to_register[database_table_row.name] = 'foo'
self.fake_driver.agent_chassis_table = agent_table
if chassis_private_present:
self.idl.tables['Chassis_Private'] = 'foo'
else:
try:
del self.idl.tables['Chassis_Private']
except KeyError:
pass
self.idl.handle_db_schema_changes(
ovsdb_monitor.BaseEvent.ROW_CREATE, database_table_row)
def test_handle_db_schema_changes_old_schema_to_old_schema(self):
"""Agents use Chassis and should keep using Chassis table"""
self._test_handle_db_schema('Chassis', chassis_private_present=False)
self.assertEqual('Chassis', self.fake_driver.agent_chassis_table)
def test_handle_db_schema_changes_old_schema_to_new_schema(self):
"""Agents use Chassis and should start using Chassis_Private table"""
self._test_handle_db_schema('Chassis', chassis_private_present=True)
self.assertEqual('Chassis_Private',
self.fake_driver.agent_chassis_table)
def test_handle_db_schema_changes_new_schema_to_old_schema(self):
"""Agents use Chassis_Private and should start using Chassis table"""
self._test_handle_db_schema('Chassis_Private',
chassis_private_present=False)
self.assertEqual('Chassis', self.fake_driver.agent_chassis_table)
def test_handle_db_schema_changes_new_schema_to_new_schema(self):
"""Agents use Chassis_Private and should keep using Chassis_Private
table.
"""
self._test_handle_db_schema('Chassis_Private',
chassis_private_present=True)
self.assertEqual('Chassis_Private',
self.fake_driver.agent_chassis_table)
class TestPortBindingChassisUpdateEvent(base.BaseTestCase):
def setUp(self):
@ -319,6 +384,7 @@ class TestOvnNbIdlNotifyHandler(test_mech_driver.OVNMechanismDriverTestCase):
self.lp_table = self.idl.tables.get('Logical_Switch_Port')
self.driver.set_port_status_up = mock.Mock()
self.driver.set_port_status_down = mock.Mock()
mock.patch.object(self.idl, 'handle_db_schema_changes').start()
def _test_lsp_helper(self, event, new_row_json, old_row_json=None,
table=None):

View File

@ -45,7 +45,7 @@ oslo.versionedobjects>=1.35.1 # Apache-2.0
osprofiler>=2.3.0 # Apache-2.0
os-ken >= 0.3.0 # Apache-2.0
ovs>=2.10.0 # Apache-2.0
ovsdbapp>=1.6.0 # Apache-2.0
ovsdbapp>=1.7.0 # Apache-2.0
packaging>=20.4 # Apache-2.0
psutil>=5.3.0 # BSD
pyroute2>=0.5.13;sys_platform!='win32' # Apache-2.0 (+ dual licensed GPL2)