diff --git a/neutron/agent/l2/__init__.py b/neutron/agent/l2/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/neutron/agent/l2/agent_extension.py b/neutron/agent/l2/agent_extension.py new file mode 100644 index 00000000000..50137d49f12 --- /dev/null +++ b/neutron/agent/l2/agent_extension.py @@ -0,0 +1,61 @@ +# Copyright (c) 2015 Mellanox Technologies, Ltd +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import abc + +import six + + +@six.add_metaclass(abc.ABCMeta) +class AgentCoreResourceExtension(object): + """Define stable abstract interface for Agent extension. + + An agent extension extends the agent core functionality. + """ + + def initialize(self, resource_rpc): + """Perform agent core resource extension initialization. + + Called after all extensions have been loaded. + No abstract methods defined below will be + called prior to this method being called. + :param resource_rpc - the agent side rpc for getting + resource by type and id + """ + self.resource_rpc = resource_rpc + + def handle_network(self, context, data): + """handle agent extension for network. + + :param context - rpc context + :param data - network data + """ + pass + + def handle_subnet(self, context, data): + """handle agent extension for subnet. + + :param context - rpc context + :param data - subnet data + """ + pass + + def handle_port(self, context, data): + """handle agent extension for port. + + :param context - rpc context + :param data - port data + """ + pass diff --git a/neutron/agent/l2/agent_extensions_manager.py b/neutron/agent/l2/agent_extensions_manager.py new file mode 100644 index 00000000000..622dbc0bdfd --- /dev/null +++ b/neutron/agent/l2/agent_extensions_manager.py @@ -0,0 +1,70 @@ +# Copyright (c) 2015 Mellanox Technologies, Ltd +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from oslo_log import log +import stevedore + +from neutron.i18n import _LE, _LI + +LOG = log.getLogger(__name__) + + +# TODO(QoS) add unit tests to Agent extensions mgr +class AgentExtensionsManager(stevedore.named.NamedExtensionManager): + """Manage agent extensions.""" + + def __init__(self, agent_extensions): + # Ordered list of agent extensions, defining + # the order in which the agent extensions are called. + + LOG.info(_LI("Configured agent extensions names: %s"), + agent_extensions) + + super(AgentExtensionsManager, self).__init__( + 'neutron.agent.l2.extensions', agent_extensions, + invoke_on_load=True, name_order=True) + LOG.info(_LI("Loaded agent extensions names: %s"), self.names()) + + def _call_on_agent_extensions(self, method_name, context, data): + """Helper method for calling a method across all agent extensions.""" + for extension in self: + try: + getattr(extension.obj, method_name)(context, data) + # TODO(QoS) add agent extensions exception and catch them here + except AttributeError: + LOG.exception( + _LE("Agent Extension '%(name)s' failed in %(method)s"), + {'name': extension.name, 'method': method_name} + ) + + def initialize(self, resource_rpc): + # Initialize each agent extension in the list. + for extension in self: + LOG.info(_LI("Initializing agent extension '%s'"), extension.name) + extension.obj.initialize(resource_rpc) + + def handle_network(self, context, data): + """Notify all agent extensions to handle network.""" + self._call_on_agent_extensions("handle_network", context, data) + + def handle_subnet(self, context, data): + """Notify all agent extensions to handle subnet.""" + self._call_on_agent_extensions("handle_subnet", context, data) + + def handle_port(self, context, data): + """Notify all agent extensions to handle port.""" + self._call_on_agent_extensions("handle_port", context, data) + #TODO(Qos) we are missing how to handle delete. we can pass action + #type in all the handle methods or add handle_delete_resource methods diff --git a/neutron/agent/l2/l2_agent.py b/neutron/agent/l2/l2_agent.py new file mode 100644 index 00000000000..0ee6c9c747f --- /dev/null +++ b/neutron/agent/l2/l2_agent.py @@ -0,0 +1,55 @@ +# Copyright (c) 2015 Mellanox Technologies, Ltd +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import abc + +import six + +from neutron.agent.l2 import agent_extensions_manager + + +#TODO(QoS): add unit tests to L2 Agent +@six.add_metaclass(abc.ABCMeta) +class L2Agent(object): + """Define stable abstract interface for L2 Agent + + This class initialize the agent extension manager and + provides API for calling the extensions manager process + extensions methods. + """ + def __init__(self, polling_interval): + self.polling_interval = polling_interval + self.agent_extensions_mgr = None + self.resource_rpc = None + + def initialize(self): + #TODO(QoS): get extensions from server ???? + agent_extensions = ('qos', ) + self.agent_extensions_mgr = ( + agent_extensions_manager.AgentExtensionsManager( + agent_extensions)) + self.agent_extensions_mgr.initialize(self.resource_rpc) + + def process_network_extensions(self, context, network): + self.agent_extensions_mgr.handle_network( + context, network) + + def process_subnet_extensions(self, context, subnet): + self.agent_extensions_mgr.handle_subnet( + context, subnet) + + def process_port_extensions(self, context, port): + self.agent_extensions_mgr.handle_port( + context, port) diff --git a/setup.cfg b/setup.cfg index 7c636307500..90f75e1d2cb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -202,6 +202,7 @@ neutron.openstack.common.cache.backends = neutron.ipam_drivers = fake = neutron.tests.unit.ipam.fake_driver:FakeDriver internal = neutron.ipam.drivers.neutrondb_ipam.driver:NeutronDbPool +neutron.agent.l2.extensions = # These are for backwards compat with Icehouse notification_driver configuration values oslo.messaging.notify.drivers = neutron.openstack.common.notifier.log_notifier = oslo_messaging.notify._impl_log:LogDriver