AgentExtensionsManager and AgentCoreResourceExtension

This patch introduces the following classes:
L2Agent - abstract class for common L2Agent implementions.
AgentExtensionsManager - to load AgentCoreResourceExtension.
AgentCoreResourceExtension - interface class to define
the AgentCoreResourceExtension API.
This allows better segregation between L2 Agent Core
and L2 Agent Extensions.

The patch is missing unit test but it was tested manually.
I added a unit tests @TODO comments to come back
to them later.

Change-Id: I813de7ff1bee188f4294f4b3eb3645ebd903297b
This commit is contained in:
Moshe Levi 2015-06-24 18:10:05 +03:00 committed by Ihar Hrachyshka
parent 2d38c742e8
commit c26142be33
5 changed files with 187 additions and 0 deletions

View File

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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