Merge "[OVN] Use the Chassis_Private table for agents healthcheck"
This commit is contained in:
commit
661e3c192d
@ -129,7 +129,7 @@ class PortBindingChassisDeletedEvent(PortBindingChassisEvent):
|
||||
return False
|
||||
|
||||
|
||||
class ChassisCreateEvent(row_event.RowEvent):
|
||||
class ChassisCreateEventBase(row_event.RowEvent):
|
||||
"""Row create event - Chassis name == our_chassis.
|
||||
|
||||
On connection, we get a dump of all chassis so if we catch a creation
|
||||
@ -137,14 +137,14 @@ class ChassisCreateEvent(row_event.RowEvent):
|
||||
to do a full sync to make sure that we capture all changes while the
|
||||
connection to OVSDB was down.
|
||||
"""
|
||||
table = None
|
||||
|
||||
def __init__(self, metadata_agent):
|
||||
self.agent = metadata_agent
|
||||
self.first_time = True
|
||||
table = 'Chassis'
|
||||
events = (self.ROW_CREATE,)
|
||||
super(ChassisCreateEvent, self).__init__(
|
||||
events, table, (('name', '=', self.agent.chassis),))
|
||||
super(ChassisCreateEventBase, self).__init__(
|
||||
events, self.table, (('name', '=', self.agent.chassis),))
|
||||
self.event_name = self.__class__.__name__
|
||||
|
||||
def run(self, event, row, old):
|
||||
@ -159,6 +159,14 @@ class ChassisCreateEvent(row_event.RowEvent):
|
||||
self.agent.sync()
|
||||
|
||||
|
||||
class ChassisCreateEvent(ChassisCreateEventBase):
|
||||
table = 'Chassis'
|
||||
|
||||
|
||||
class ChassisPrivateCreateEvent(ChassisCreateEventBase):
|
||||
table = 'Chassis_Private'
|
||||
|
||||
|
||||
class SbGlobalUpdateEvent(row_event.RowEvent):
|
||||
"""Row update event on SB_Global table."""
|
||||
|
||||
@ -170,8 +178,12 @@ class SbGlobalUpdateEvent(row_event.RowEvent):
|
||||
self.event_name = self.__class__.__name__
|
||||
|
||||
def run(self, event, row, old):
|
||||
self.agent.sb_idl.update_metadata_health_status(
|
||||
self.agent.chassis, row.nb_cfg).execute()
|
||||
table = ('Chassis_Private' if self.agent.has_chassis_private
|
||||
else 'Chassis')
|
||||
self.agent.sb_idl.db_set(
|
||||
table, self.agent.chassis, ('external_ids', {
|
||||
ovn_const.OVN_AGENT_METADATA_SB_CFG_KEY:
|
||||
str(row.nb_cfg)})).execute()
|
||||
|
||||
|
||||
class MetadataAgent(object):
|
||||
@ -207,13 +219,26 @@ class MetadataAgent(object):
|
||||
proxy = metadata_server.UnixDomainMetadataProxy(self.conf)
|
||||
proxy.run()
|
||||
|
||||
tables = ('Encap', 'Port_Binding', 'Datapath_Binding', 'SB_Global',
|
||||
'Chassis')
|
||||
events = (PortBindingChassisCreatedEvent(self),
|
||||
PortBindingChassisDeletedEvent(self),
|
||||
SbGlobalUpdateEvent(self))
|
||||
|
||||
# TODO(lucasagomes): Remove this in the future. Try to register
|
||||
# the Chassis_Private table, if not present, fallback to the normal
|
||||
# Chassis table.
|
||||
# Open the connection to OVN SB database.
|
||||
self.sb_idl = ovsdb.MetadataAgentOvnSbIdl(
|
||||
chassis=self.chassis,
|
||||
events=[PortBindingChassisCreatedEvent(self),
|
||||
PortBindingChassisDeletedEvent(self),
|
||||
ChassisCreateEvent(self),
|
||||
SbGlobalUpdateEvent(self)]).start()
|
||||
self.has_chassis_private = False
|
||||
try:
|
||||
self.sb_idl = ovsdb.MetadataAgentOvnSbIdl(
|
||||
chassis=self.chassis, tables=tables + ('Chassis_Private', ),
|
||||
events=events + (ChassisPrivateCreateEvent(self), )).start()
|
||||
self.has_chassis_private = True
|
||||
except AssertionError:
|
||||
self.sb_idl = ovsdb.MetadataAgentOvnSbIdl(
|
||||
chassis=self.chassis, tables=tables,
|
||||
events=events + (ChassisCreateEvent(self), )).start()
|
||||
|
||||
# Do the initial sync.
|
||||
self.sync()
|
||||
@ -226,9 +251,10 @@ class MetadataAgent(object):
|
||||
def register_metadata_agent(self):
|
||||
# NOTE(lucasagomes): db_add() will not overwrite the UUID if
|
||||
# it's already set.
|
||||
table = ('Chassis_Private' if self.has_chassis_private else 'Chassis')
|
||||
ext_ids = {
|
||||
ovn_const.OVN_AGENT_METADATA_ID_KEY: uuidutils.generate_uuid()}
|
||||
self.sb_idl.db_add('Chassis', self.chassis, 'external_ids',
|
||||
self.sb_idl.db_add(table, self.chassis, 'external_ids',
|
||||
ext_ids).execute(check_error=True)
|
||||
|
||||
def _get_own_chassis_name(self):
|
||||
|
@ -38,8 +38,10 @@ class MetadataAgentOvnSbIdl(ovsdb_monitor.OvnIdl):
|
||||
helper.register_table(table)
|
||||
super(MetadataAgentOvnSbIdl, self).__init__(
|
||||
None, connection_string, helper)
|
||||
if chassis and 'Chassis' in tables:
|
||||
self.tables['Chassis'].condition = [['name', '==', chassis]]
|
||||
if chassis:
|
||||
table = ('Chassis_Private' if 'Chassis_Private' in tables
|
||||
else 'Chassis')
|
||||
self.tables[table].condition = [['name', '==', chassis]]
|
||||
if events:
|
||||
self.notify_handler.watch_events(events)
|
||||
|
||||
|
@ -28,8 +28,13 @@ class NeutronAgent(abc.ABC):
|
||||
for _type in cls.types:
|
||||
NeutronAgent.types[_type] = cls
|
||||
|
||||
def __init__(self, chassis):
|
||||
self.chassis = chassis
|
||||
def __init__(self, chassis_private):
|
||||
self.chassis_private = chassis_private
|
||||
try:
|
||||
self.chassis = self.chassis_private.chassis[0]
|
||||
except (AttributeError, IndexError):
|
||||
# No Chassis_Private support, just use Chassis
|
||||
self.chassis = self.chassis_private
|
||||
|
||||
@property
|
||||
def updated_at(self):
|
||||
@ -58,8 +63,8 @@ class NeutronAgent(abc.ABC):
|
||||
'admin_state_up': True}
|
||||
|
||||
@classmethod
|
||||
def from_type(cls, _type, chassis):
|
||||
return cls.types[_type](chassis)
|
||||
def from_type(cls, _type, chassis_private):
|
||||
return cls.types[_type](chassis_private)
|
||||
|
||||
@staticmethod
|
||||
def agent_types():
|
||||
@ -85,15 +90,15 @@ class ControllerAgent(NeutronAgent):
|
||||
|
||||
@property
|
||||
def nb_cfg(self):
|
||||
return self.chassis.nb_cfg
|
||||
return self.chassis_private.nb_cfg
|
||||
|
||||
@property
|
||||
def agent_id(self):
|
||||
return self.chassis.name
|
||||
return self.chassis_private.name
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return self.chassis.external_ids.get(
|
||||
return self.chassis_private.external_ids.get(
|
||||
ovn_const.OVN_AGENT_DESC_KEY, '')
|
||||
|
||||
|
||||
@ -105,15 +110,15 @@ class MetadataAgent(NeutronAgent):
|
||||
|
||||
@property
|
||||
def nb_cfg(self):
|
||||
return int(self.chassis.external_ids.get(
|
||||
return int(self.chassis_private.external_ids.get(
|
||||
ovn_const.OVN_AGENT_METADATA_SB_CFG_KEY, 0))
|
||||
|
||||
@property
|
||||
def agent_id(self):
|
||||
return self.chassis.external_ids.get(
|
||||
return self.chassis_private.external_ids.get(
|
||||
ovn_const.OVN_AGENT_METADATA_ID_KEY)
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return self.chassis.external_ids.get(
|
||||
return self.chassis_private.external_ids.get(
|
||||
ovn_const.OVN_AGENT_METADATA_DESC_KEY, '')
|
||||
|
@ -120,6 +120,9 @@ class OVNMechanismDriver(api.MechanismDriver):
|
||||
self.subscribe()
|
||||
self.qos_driver = qos_driver.OVNQosDriver.create(self)
|
||||
self.trunk_driver = trunk_driver.OVNTrunkDriver.create(self)
|
||||
# The agent_chassis_table will be changed to Chassis_Private if it
|
||||
# exists, we need to have a connection in order to check that.
|
||||
self.agent_chassis_table = 'Chassis'
|
||||
|
||||
@property
|
||||
def _plugin(self):
|
||||
@ -262,6 +265,9 @@ class OVNMechanismDriver(api.MechanismDriver):
|
||||
self._nb_ovn, self._sb_ovn = impl_idl_ovn.get_ovn_idls(
|
||||
self, trigger, binding_events=not is_maintenance)
|
||||
|
||||
if self._sb_ovn.is_table_present('Chassis_Private'):
|
||||
self.agent_chassis_table = 'Chassis_Private'
|
||||
|
||||
# AGENTS must be populated after fork so if ovn-controller is stopped
|
||||
# before a worker handles a get_agents request, we still show agents
|
||||
populate_agents(self)
|
||||
@ -1105,14 +1111,15 @@ class OVNMechanismDriver(api.MechanismDriver):
|
||||
def mark_agent_alive(self, agent):
|
||||
# Update the time of our successful check
|
||||
value = timeutils.utcnow(with_timezone=True).isoformat()
|
||||
self._sb_ovn.db_set('Chassis', agent.chassis.uuid,
|
||||
('external_ids', {agent.key: value})).execute(
|
||||
check_error=True)
|
||||
self._sb_ovn.db_set(
|
||||
self.agent_chassis_table, agent.chassis_private.uuid,
|
||||
('external_ids', {agent.key: value})).execute(check_error=True)
|
||||
|
||||
def agents_from_chassis(self, chassis, update_db=True):
|
||||
def agents_from_chassis(self, chassis_private, update_db=True):
|
||||
agent_dict = {}
|
||||
# Iterate over each unique Agent subclass
|
||||
for agent in [a(chassis) for a in n_agent.NeutronAgent.agent_types()]:
|
||||
for agent in [a(chassis_private)
|
||||
for a in n_agent.NeutronAgent.agent_types()]:
|
||||
if not agent.agent_id:
|
||||
continue
|
||||
alive = self.agent_alive(agent, update_db)
|
||||
@ -1186,7 +1193,7 @@ class OVNMechanismDriver(api.MechanismDriver):
|
||||
|
||||
|
||||
def populate_agents(driver):
|
||||
for ch in driver._sb_ovn.tables['Chassis'].rows.values():
|
||||
for ch in driver._sb_ovn.tables[driver.agent_chassis_table].rows.values():
|
||||
# update the cache, rows are hashed on uuid but it is the name that
|
||||
# stays consistent across ovn-controller restarts
|
||||
AGENTS.update({ch.name: ch})
|
||||
@ -1207,11 +1214,12 @@ def get_agents(self, context, filters=None, fields=None, _driver=None):
|
||||
def get_agent(self, context, id, fields=None, _driver=None):
|
||||
chassis = None
|
||||
try:
|
||||
# look up Chassis by *name*, which the id attribte is
|
||||
chassis = _driver._sb_ovn.lookup('Chassis', id)
|
||||
# look up Chassis by *name*, which the id attribute is
|
||||
chassis = _driver._sb_ovn.lookup(_driver.agent_chassis_table, id)
|
||||
except idlutils.RowNotFound:
|
||||
# If the UUID is not found, check for the metadata agent ID
|
||||
for ch in _driver._sb_ovn.tables['Chassis'].rows.values():
|
||||
for ch in _driver._sb_ovn.tables[
|
||||
_driver.agent_chassis_table].rows.values():
|
||||
metadata_agent_id = ch.external_ids.get(
|
||||
ovn_const.OVN_AGENT_METADATA_ID_KEY)
|
||||
if id == metadata_agent_id:
|
||||
|
@ -836,12 +836,6 @@ class OvsdbSbOvnIdl(sb_impl_idl.OvnSbApiIdlImpl, Backend):
|
||||
if (r.mac and str(r.datapath.uuid) == network) and
|
||||
ip_address in r.mac[0].split(' ')]
|
||||
|
||||
def update_metadata_health_status(self, chassis, nb_cfg):
|
||||
return cmd.UpdateChassisExtIdsCommand(
|
||||
self, chassis,
|
||||
{ovn_const.OVN_AGENT_METADATA_SB_CFG_KEY: str(nb_cfg)},
|
||||
if_exists=True)
|
||||
|
||||
def set_port_cidrs(self, name, cidrs):
|
||||
# TODO(twilson) add if_exists to db commands
|
||||
return self.db_set('Port_Binding', name, 'external_ids',
|
||||
|
@ -528,6 +528,8 @@ class OvnSbIdl(OvnIdlDistributedLock):
|
||||
def from_server(cls, connection_string, schema_name, driver):
|
||||
_check_and_set_ssl_files(schema_name)
|
||||
helper = idlutils.get_schema_helper(connection_string, schema_name)
|
||||
if 'Chassis_Private' in helper.schema_json['tables']:
|
||||
helper.register_table('Chassis_Private')
|
||||
helper.register_table('Chassis')
|
||||
helper.register_table('Encap')
|
||||
helper.register_table('Port_Binding')
|
||||
|
@ -169,6 +169,8 @@ class FakeOvsdbSbOvnIdl(object):
|
||||
self.db_set = mock.Mock()
|
||||
self.lookup = mock.MagicMock()
|
||||
self.chassis_list = mock.MagicMock()
|
||||
self.is_table_present = mock.Mock()
|
||||
self.is_table_present.return_value = False
|
||||
|
||||
|
||||
class FakeOvsdbTransaction(object):
|
||||
|
@ -1615,18 +1615,21 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
|
||||
|
||||
def _add_chassis_agent(self, nb_cfg, agent_type, updated_at=None):
|
||||
updated_at = updated_at or datetime.datetime.utcnow()
|
||||
chassis = mock.Mock()
|
||||
chassis.nb_cfg = nb_cfg
|
||||
chassis.uuid = uuid.uuid4()
|
||||
chassis.external_ids = {ovn_const.OVN_LIVENESS_CHECK_EXT_ID_KEY:
|
||||
datetime.datetime.isoformat(updated_at)}
|
||||
chassis_private = mock.Mock()
|
||||
chassis_private.nb_cfg = nb_cfg
|
||||
chassis_private.uuid = uuid.uuid4()
|
||||
chassis_private.external_ids = {
|
||||
ovn_const.OVN_LIVENESS_CHECK_EXT_ID_KEY:
|
||||
datetime.datetime.isoformat(updated_at)}
|
||||
if agent_type == ovn_const.OVN_METADATA_AGENT:
|
||||
chassis.external_ids.update({
|
||||
chassis_private.external_ids.update({
|
||||
ovn_const.OVN_AGENT_METADATA_SB_CFG_KEY: nb_cfg,
|
||||
ovn_const.METADATA_LIVENESS_CHECK_EXT_ID_KEY:
|
||||
datetime.datetime.isoformat(updated_at)})
|
||||
chassis_private.chassis = [chassis_private]
|
||||
|
||||
return neutron_agent.NeutronAgent.from_type(agent_type, chassis)
|
||||
return neutron_agent.NeutronAgent.from_type(
|
||||
agent_type, chassis_private)
|
||||
|
||||
def test_agent_alive_true(self):
|
||||
for agent_type in (ovn_const.OVN_CONTROLLER_AGENT,
|
||||
|
Loading…
x
Reference in New Issue
Block a user