[OVN] The OVN agent should handle its own tags and status
The OVN agent should handle its own tags, written in the "Chassis_Private.external_ids" dictionary. These are: * neutron:ovn-neutron-agent-sb-cfg * neutron:description-neutron-agent * neutron:ovn-neutron-agent-id The "metadata" extension should not create nor update these tags. This patch removes from the "metadata" extension the ``SbGlobalUpdateEvent`` and ``ChassisPrivateCreateEvent`` events. Partial-Bug: #2119097 Signed-off-by: Rodolfo Alonso Hernandez <ralonsoh@redhat.com> Change-Id: I7f0ecf8f8727e363d98e981948c999305ae33426
This commit is contained in:
@@ -49,6 +49,32 @@ class SbGlobalUpdateEvent(row_event.RowEvent):
|
|||||||
('external_ids', ext_ids)).execute()
|
('external_ids', ext_ids)).execute()
|
||||||
|
|
||||||
|
|
||||||
|
class ChassisPrivateCreateEvent(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
|
||||||
|
of our own chassis it has to be a reconnection. In this case, we need
|
||||||
|
to do a full sync to make sure that we capture all changes while the
|
||||||
|
connection to OVSDB was down.
|
||||||
|
"""
|
||||||
|
def __init__(self, ovn_agent):
|
||||||
|
self._first_time = True
|
||||||
|
self.ovn_agent = ovn_agent
|
||||||
|
events = (self.ROW_CREATE,)
|
||||||
|
super().__init__(events, 'Chassis_Private', None)
|
||||||
|
self.conditions = (('name', '=', self.ovn_agent.chassis),)
|
||||||
|
self.event_name = self.__class__.__name__
|
||||||
|
|
||||||
|
def run(self, event, row, old):
|
||||||
|
if self._first_time:
|
||||||
|
self._first_time = False
|
||||||
|
return
|
||||||
|
|
||||||
|
# Re-register the OVN agent with the local chassis in case its
|
||||||
|
# entry was re-created (happens when restarting the ovn-controller)
|
||||||
|
self.ovn_agent.register_ovn_agent()
|
||||||
|
|
||||||
|
|
||||||
class OVNNeutronAgent(service.Service):
|
class OVNNeutronAgent(service.Service):
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf):
|
||||||
@@ -139,7 +165,9 @@ class OVNNeutronAgent(service.Service):
|
|||||||
return ovsdb.MonitorAgentOvnNbIdl(tables, events).start()
|
return ovsdb.MonitorAgentOvnNbIdl(tables, events).start()
|
||||||
|
|
||||||
def _load_sb_idl(self):
|
def _load_sb_idl(self):
|
||||||
events = [SbGlobalUpdateEvent]
|
events = [SbGlobalUpdateEvent,
|
||||||
|
ChassisPrivateCreateEvent,
|
||||||
|
]
|
||||||
tables = ['SB_Global', 'Chassis_Private']
|
tables = ['SB_Global', 'Chassis_Private']
|
||||||
for extension in self.ext_manager:
|
for extension in self.ext_manager:
|
||||||
events += extension.obj.sb_idl_events
|
events += extension.obj.sb_idl_events
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import threading
|
|||||||
from neutron_lib.agent import extension
|
from neutron_lib.agent import extension
|
||||||
from neutron_lib import exceptions
|
from neutron_lib import exceptions
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_service import service
|
||||||
|
|
||||||
from neutron._i18n import _
|
from neutron._i18n import _
|
||||||
from neutron.agent import agent_extensions_manager as agent_ext_mgr
|
from neutron.agent import agent_extensions_manager as agent_ext_mgr
|
||||||
@@ -33,6 +34,35 @@ class ConfigException(exceptions.NeutronException):
|
|||||||
message = _('Error configuring the OVN Neutron Agent: %(description)s.')
|
message = _('Error configuring the OVN Neutron Agent: %(description)s.')
|
||||||
|
|
||||||
|
|
||||||
|
class OVNExtensionEvent(metaclass=abc.ABCMeta):
|
||||||
|
"""Implements a method to retrieve the correct caller agent
|
||||||
|
|
||||||
|
The events inheriting from this class could be called from the OVN metadata
|
||||||
|
agent or as part of an extension of the OVN agent ("metadata" extension,
|
||||||
|
for example). In future releases, the OVN metadata agent will be superseded
|
||||||
|
by the OVN agent (with the "metadata" extension) and this class removed,
|
||||||
|
keeping only the compatibility with the OVN agent (to be removed in C+2).
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self._agent_or_extension = None
|
||||||
|
self._agent = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def agent(self):
|
||||||
|
"""This method provide support for the OVN agent
|
||||||
|
|
||||||
|
This event can be used in the OVN metadata agent and in the OVN
|
||||||
|
agent metadata extension.
|
||||||
|
"""
|
||||||
|
if not self._agent_or_extension:
|
||||||
|
if isinstance(self._agent, service.Service):
|
||||||
|
self._agent_or_extension = self._agent['metadata']
|
||||||
|
else:
|
||||||
|
self._agent_or_extension = self._agent
|
||||||
|
return self._agent_or_extension
|
||||||
|
|
||||||
|
|
||||||
class OVNAgentExtensionManager(agent_ext_mgr.AgentExtensionsManager):
|
class OVNAgentExtensionManager(agent_ext_mgr.AgentExtensionsManager):
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf):
|
||||||
|
|||||||
@@ -115,8 +115,6 @@ class MetadataExtension(extension_manager.OVNAgentExtension,
|
|||||||
def sb_idl_events(self):
|
def sb_idl_events(self):
|
||||||
return [metadata_agent.PortBindingUpdatedEvent,
|
return [metadata_agent.PortBindingUpdatedEvent,
|
||||||
metadata_agent.PortBindingDeletedEvent,
|
metadata_agent.PortBindingDeletedEvent,
|
||||||
metadata_agent.SbGlobalUpdateEvent,
|
|
||||||
metadata_agent.ChassisPrivateCreateEvent,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# NOTE(ralonsoh): the following properties are needed during the migration
|
# NOTE(ralonsoh): the following properties are needed during the migration
|
||||||
@@ -162,7 +160,6 @@ class MetadataExtension(extension_manager.OVNAgentExtension,
|
|||||||
"""
|
"""
|
||||||
self.agent_api.load_config()
|
self.agent_api.load_config()
|
||||||
self._update_chassis_private_config()
|
self._update_chassis_private_config()
|
||||||
self.agent_api.update_neutron_sb_cfg_key()
|
|
||||||
self.sync()
|
self.sync()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import abc
|
|
||||||
import collections
|
import collections
|
||||||
import functools
|
import functools
|
||||||
import re
|
import re
|
||||||
@@ -31,7 +30,7 @@ from ovsdbapp.backend.ovs_idl import vlog
|
|||||||
from neutron.agent.linux import external_process
|
from neutron.agent.linux import external_process
|
||||||
from neutron.agent.linux import ip_lib
|
from neutron.agent.linux import ip_lib
|
||||||
from neutron.agent.linux import iptables_manager
|
from neutron.agent.linux import iptables_manager
|
||||||
from neutron.agent.ovn.agent import ovn_neutron_agent
|
from neutron.agent.ovn.extensions import extension_manager
|
||||||
from neutron.agent.ovn.metadata import driver as metadata_driver
|
from neutron.agent.ovn.metadata import driver as metadata_driver
|
||||||
from neutron.agent.ovn.metadata import ovsdb
|
from neutron.agent.ovn.metadata import ovsdb
|
||||||
from neutron.agent.ovn.metadata import server_socket as metadata_server
|
from neutron.agent.ovn.metadata import server_socket as metadata_server
|
||||||
@@ -87,36 +86,8 @@ class ConfigException(Exception):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class _OVNExtensionEvent(metaclass=abc.ABCMeta):
|
class PortBindingEvent(extension_manager.OVNExtensionEvent,
|
||||||
"""Implements a method to retrieve the correct caller agent
|
row_event.RowEvent):
|
||||||
|
|
||||||
The events inheriting from this class could be called from the OVN metadata
|
|
||||||
agent or as part of an extension of the OVN agent ("metadata" extension,
|
|
||||||
for example). In future releases, the OVN metadata agent will be superseded
|
|
||||||
by the OVN agent (with the "metadata" extension) and this class removed,
|
|
||||||
keeping only the compatibility with the OVN agent (to be removed in C+2).
|
|
||||||
"""
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self._agent_or_extension = None
|
|
||||||
self._agent = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def agent(self):
|
|
||||||
"""This method provide support for the OVN agent
|
|
||||||
|
|
||||||
This event can be used in the OVN metadata agent and in the OVN
|
|
||||||
agent metadata extension.
|
|
||||||
"""
|
|
||||||
if not self._agent_or_extension:
|
|
||||||
if isinstance(self._agent, ovn_neutron_agent.OVNNeutronAgent):
|
|
||||||
self._agent_or_extension = self._agent['metadata']
|
|
||||||
else:
|
|
||||||
self._agent_or_extension = self._agent
|
|
||||||
return self._agent_or_extension
|
|
||||||
|
|
||||||
|
|
||||||
class PortBindingEvent(_OVNExtensionEvent, row_event.RowEvent):
|
|
||||||
def __init__(self, agent):
|
def __init__(self, agent):
|
||||||
table = 'Port_Binding'
|
table = 'Port_Binding'
|
||||||
super().__init__((self.__class__.EVENT,), table, None)
|
super().__init__((self.__class__.EVENT,), table, None)
|
||||||
@@ -301,7 +272,7 @@ class PortBindingDeletedEvent(PortBindingEvent):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class ChassisPrivateCreateEvent(_OVNExtensionEvent, row_event.RowEvent):
|
class ChassisPrivateCreateEvent(row_event.RowEvent):
|
||||||
"""Row create event - Chassis name == our_chassis.
|
"""Row create event - Chassis name == our_chassis.
|
||||||
|
|
||||||
On connection, we get a dump of all chassis so if we catch a creation
|
On connection, we get a dump of all chassis so if we catch a creation
|
||||||
@@ -314,9 +285,7 @@ class ChassisPrivateCreateEvent(_OVNExtensionEvent, row_event.RowEvent):
|
|||||||
self.first_time = True
|
self.first_time = True
|
||||||
events = (self.ROW_CREATE,)
|
events = (self.ROW_CREATE,)
|
||||||
super().__init__(events, 'Chassis_Private', None)
|
super().__init__(events, 'Chassis_Private', None)
|
||||||
# NOTE(ralonsoh): ``self._agent`` needs to be assigned before being
|
self.agent = agent
|
||||||
# used in the property ``self.agent``.
|
|
||||||
self._agent = agent
|
|
||||||
self.conditions = (('name', '=', self.agent.chassis),)
|
self.conditions = (('name', '=', self.agent.chassis),)
|
||||||
self.event_name = self.__class__.__name__
|
self.event_name = self.__class__.__name__
|
||||||
|
|
||||||
@@ -332,14 +301,14 @@ class ChassisPrivateCreateEvent(_OVNExtensionEvent, row_event.RowEvent):
|
|||||||
self.agent.sync()
|
self.agent.sync()
|
||||||
|
|
||||||
|
|
||||||
class SbGlobalUpdateEvent(_OVNExtensionEvent, row_event.RowEvent):
|
class SbGlobalUpdateEvent(row_event.RowEvent):
|
||||||
"""Row update event on SB_Global table."""
|
"""Row update event on SB_Global table."""
|
||||||
|
|
||||||
def __init__(self, agent):
|
def __init__(self, agent):
|
||||||
table = 'SB_Global'
|
table = 'SB_Global'
|
||||||
events = (self.ROW_UPDATE,)
|
events = (self.ROW_UPDATE,)
|
||||||
super().__init__(events, table, None)
|
super().__init__(events, table, None)
|
||||||
self._agent = agent
|
self.agent = agent
|
||||||
self.event_name = self.__class__.__name__
|
self.event_name = self.__class__.__name__
|
||||||
self.first_run = True
|
self.first_run = True
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import uuid
|
|||||||
|
|
||||||
from oslo_config import fixture as fixture_config
|
from oslo_config import fixture as fixture_config
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
from ovsdbapp.backend.ovs_idl import idlutils
|
||||||
|
|
||||||
from neutron.agent.ovn.agent import ovn_neutron_agent
|
from neutron.agent.ovn.agent import ovn_neutron_agent
|
||||||
from neutron.agent.ovn.agent import ovsdb as agent_ovsdb
|
from neutron.agent.ovn.agent import ovsdb as agent_ovsdb
|
||||||
@@ -94,6 +95,29 @@ class TestOVNNeutronAgentBase(base.TestOVNFunctionalBase):
|
|||||||
return agt
|
return agt
|
||||||
|
|
||||||
|
|
||||||
|
class TestOVNNeutronAgent(TestOVNNeutronAgentBase):
|
||||||
|
def setUp(self, **kwargs):
|
||||||
|
super().setUp(extensions=[METADATA_EXTENSION], **kwargs)
|
||||||
|
|
||||||
|
def test_chassis_private_create_event(self):
|
||||||
|
def _check_chassis_private():
|
||||||
|
try:
|
||||||
|
ext_ids = self.ovn_agent.sb_idl.db_get(
|
||||||
|
'Chassis_Private', self.chassis_name,
|
||||||
|
'external_ids').execute(check_error=True)
|
||||||
|
return (ext_ids.get(ovn_const.OVN_AGENT_NEUTRON_ID_KEY)
|
||||||
|
is not None)
|
||||||
|
except idlutils.RowNotFound:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# If the "Chassis_Private" register is deleted and created again,
|
||||||
|
# the agent should be able to re-register itself.
|
||||||
|
self.ovn_agent.sb_idl.chassis_del(self.chassis_name).execute(
|
||||||
|
check_error=True)
|
||||||
|
self.add_fake_chassis(self.host_name, name=self.chassis_name)
|
||||||
|
n_utils.wait_until_true(_check_chassis_private, timeout=10)
|
||||||
|
|
||||||
|
|
||||||
class TestOVNNeutronAgentFakeAgent(TestOVNNeutronAgentBase):
|
class TestOVNNeutronAgentFakeAgent(TestOVNNeutronAgentBase):
|
||||||
|
|
||||||
def setUp(self, **kwargs):
|
def setUp(self, **kwargs):
|
||||||
|
|||||||
Reference in New Issue
Block a user