From e3545991349dd93b707705272e14b45943671f32 Mon Sep 17 00:00:00 2001 From: Armando Migliaccio Date: Wed, 3 Aug 2016 14:00:04 -0700 Subject: [PATCH] Add agent-side driver scaffolding for trunk functionality The agent code is enhanced to allow the trunk agent-side counterpart to be activated seamlessly by means or local registry notifications. Some integration with the server side is provided by loading the RPC agent-side skeleton. Basic unit testing provides some coverage. More effective functional and system coverage will be provided once everything comes together. Partially-implements: blueprint vlan-aware-vms Co-Authored-By: Adolfo Duarte Change-Id: Id70553e8980593f99548a4d2b0a78355933f7c2c --- .../plugins/ml2/drivers/agent/capabilities.py | 29 ++++++++++++ .../openvswitch/agent/ovs_capabilities.py | 23 ++++++++++ .../openvswitch/agent/ovs_neutron_agent.py | 5 ++ .../drivers/openvswitch/agent/__init__.py | 0 .../trunk/drivers/openvswitch/agent/driver.py | 46 +++++++++++++++++++ .../ml2/drivers/agent/test_capabilities.py | 40 ++++++++++++++++ .../agent/test_ovs_capabilities.py | 30 ++++++++++++ .../drivers/openvswitch/agent/__init__.py | 0 .../drivers/openvswitch/agent/test_driver.py | 28 +++++++++++ 9 files changed, 201 insertions(+) create mode 100644 neutron/plugins/ml2/drivers/agent/capabilities.py create mode 100644 neutron/plugins/ml2/drivers/openvswitch/agent/ovs_capabilities.py create mode 100644 neutron/services/trunk/drivers/openvswitch/agent/__init__.py create mode 100644 neutron/services/trunk/drivers/openvswitch/agent/driver.py create mode 100644 neutron/tests/unit/plugins/ml2/drivers/agent/test_capabilities.py create mode 100644 neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_capabilities.py create mode 100644 neutron/tests/unit/services/trunk/drivers/openvswitch/agent/__init__.py create mode 100644 neutron/tests/unit/services/trunk/drivers/openvswitch/agent/test_driver.py diff --git a/neutron/plugins/ml2/drivers/agent/capabilities.py b/neutron/plugins/ml2/drivers/agent/capabilities.py new file mode 100644 index 00000000000..7cc053523dd --- /dev/null +++ b/neutron/plugins/ml2/drivers/agent/capabilities.py @@ -0,0 +1,29 @@ +# Copyright 2016 Hewlett Packard Enterprise Development LP +# +# 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 neutron.callbacks import events +from neutron.callbacks import registry + + +def notify_init_event(agent_type, agent): + """Notify init event for the specified agent.""" + registry.notify(agent_type, events.AFTER_INIT, agent, agent=agent) + + +def register(callback, agent_type): + """Subscribe callback to init event for the specified agent. + + :param agent_type: an agent type as defined in neutron_lib.constants. + :param callback: a callback that can process the agent init event. + """ + registry.subscribe(callback, agent_type, events.AFTER_INIT) diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_capabilities.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_capabilities.py new file mode 100644 index 00000000000..0d1f1078bab --- /dev/null +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_capabilities.py @@ -0,0 +1,23 @@ +# Copyright 2016 Hewlett Packard Enterprise Development LP +# +# 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 neutron_lib import constants + +from neutron.plugins.ml2.drivers.agent import capabilities +from neutron.services.trunk.drivers.openvswitch.agent import driver + + +def register(): + """Register OVS capabilities.""" + # Add capabilities to be loaded during agent initialization + capabilities.register(driver.init_handler, constants.AGENT_TYPE_OVS) diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py index b983cd2ae26..edcf179cea5 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py @@ -52,11 +52,14 @@ from neutron import context from neutron.extensions import portbindings from neutron.plugins.common import constants as p_const from neutron.plugins.common import utils as p_utils +from neutron.plugins.ml2.drivers.agent import capabilities from neutron.plugins.ml2.drivers.l2pop.rpc_manager import l2population_rpc from neutron.plugins.ml2.drivers.openvswitch.agent.common \ import constants from neutron.plugins.ml2.drivers.openvswitch.agent \ import ovs_agent_extension_api as ovs_ext_api +from neutron.plugins.ml2.drivers.openvswitch.agent \ + import ovs_capabilities from neutron.plugins.ml2.drivers.openvswitch.agent \ import ovs_dvr_neutron_agent from neutron.plugins.ml2.drivers.openvswitch.agent import vlanmanager @@ -2152,10 +2155,12 @@ def prepare_xen_compute(): def main(bridge_classes): prepare_xen_compute() + ovs_capabilities.register() validate_tunnel_config(cfg.CONF.AGENT.tunnel_types, cfg.CONF.OVS.local_ip) try: agent = OVSNeutronAgent(bridge_classes, cfg.CONF) + capabilities.notify_init_event(n_const.AGENT_TYPE_OVS, agent) except (RuntimeError, ValueError) as e: LOG.error(_LE("%s Agent terminated!"), e) sys.exit(1) diff --git a/neutron/services/trunk/drivers/openvswitch/agent/__init__.py b/neutron/services/trunk/drivers/openvswitch/agent/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/neutron/services/trunk/drivers/openvswitch/agent/driver.py b/neutron/services/trunk/drivers/openvswitch/agent/driver.py new file mode 100644 index 00000000000..ebf2c6adba1 --- /dev/null +++ b/neutron/services/trunk/drivers/openvswitch/agent/driver.py @@ -0,0 +1,46 @@ +# 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 as logging + +from neutron.api.rpc.callbacks.consumer import registry +from neutron.api.rpc.callbacks import resources +from neutron.services.trunk.rpc import agent + +LOG = logging.getLogger(__name__) + +TRUNK_SKELETON = None + + +class OVSTrunkSkeleton(agent.TrunkSkeleton): + + def __init__(self): + super(OVSTrunkSkeleton, self).__init__() + registry.unsubscribe(self.handle_trunks, resources.TRUNK) + + def handle_trunks(self, trunk, event_type): + """This method is not required by the OVS Agent driver. + + Trunk notifications are handled via local OVSDB events. + """ + raise NotImplementedError() + + def handle_subports(self, subports, event_type): + # TODO(armax): call into TrunkManager to wire the subports + LOG.debug("Event %s for subports: %s", event_type, subports) + + +def init_handler(resource, event, trigger, agent=None): + """Handler for agent init event.""" + # Set up agent-side RPC for receiving trunk events; we may want to + # make this setup conditional based on server-side capabilities. + global TRUNK_SKELETON + TRUNK_SKELETON = OVSTrunkSkeleton() diff --git a/neutron/tests/unit/plugins/ml2/drivers/agent/test_capabilities.py b/neutron/tests/unit/plugins/ml2/drivers/agent/test_capabilities.py new file mode 100644 index 00000000000..214174c42fe --- /dev/null +++ b/neutron/tests/unit/plugins/ml2/drivers/agent/test_capabilities.py @@ -0,0 +1,40 @@ +# Copyright 2016 Hewlett Packard Enterprise Development LP +# +# 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 mock + +from neutron.callbacks import events +from neutron.plugins.ml2.drivers.agent import capabilities +from neutron.tests import base + + +class CapabilitiesTest(base.BaseTestCase): + + @mock.patch("neutron.callbacks.manager.CallbacksManager.notify") + def test_notify_init_event(self, mocked_manager): + mock_agent_type = mock.Mock() + mock_agent = mock.Mock() + capabilities.notify_init_event(mock_agent_type, mock_agent) + mocked_manager.assert_called_with(mock_agent_type, + events.AFTER_INIT, + mock_agent, + agent=mock_agent) + + @mock.patch("neutron.callbacks.manager.CallbacksManager.subscribe") + def test_register(self, mocked_subscribe): + mock_callback = mock.Mock() + mock_agent_type = mock.Mock() + capabilities.register(mock_callback, mock_agent_type) + mocked_subscribe.assert_called_with(mock_callback, + mock_agent_type, + events.AFTER_INIT) diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_capabilities.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_capabilities.py new file mode 100644 index 00000000000..5714c620390 --- /dev/null +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_capabilities.py @@ -0,0 +1,30 @@ +# Copyright 2016 Hewlett Packard Enterprise Development LP +# +# 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 mock + +from neutron.callbacks import events +from neutron.plugins.ml2.drivers.openvswitch.agent import ovs_capabilities +from neutron.services.trunk.drivers.openvswitch.agent import driver +from neutron.tests import base +from neutron_lib import constants + + +class CapabilitiesTest(base.BaseTestCase): + + @mock.patch("neutron.callbacks.manager.CallbacksManager.subscribe") + def test_register(self, mocked_subscribe): + ovs_capabilities.register() + mocked_subscribe.assert_called_with(driver.init_handler, + constants.AGENT_TYPE_OVS, + events.AFTER_INIT) diff --git a/neutron/tests/unit/services/trunk/drivers/openvswitch/agent/__init__.py b/neutron/tests/unit/services/trunk/drivers/openvswitch/agent/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/neutron/tests/unit/services/trunk/drivers/openvswitch/agent/test_driver.py b/neutron/tests/unit/services/trunk/drivers/openvswitch/agent/test_driver.py new file mode 100644 index 00000000000..c363d4aeaa0 --- /dev/null +++ b/neutron/tests/unit/services/trunk/drivers/openvswitch/agent/test_driver.py @@ -0,0 +1,28 @@ +# Copyright 2016 Hewlett Packard Enterprise Development LP +# +# 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 mock + +from neutron.api.rpc.callbacks import resources +from neutron.services.trunk.drivers.openvswitch.agent import driver +from neutron.tests import base + + +class OvsTrunkSkeletonTest(base.BaseTestCase): + + @mock.patch("neutron.api.rpc.callbacks.resource_manager." + "ConsumerResourceCallbacksManager.unregister") + def test___init__(self, mocked_unregister): + test_obj = driver.OVSTrunkSkeleton() + mocked_unregister.assert_called_with(test_obj.handle_trunks, + resources.TRUNK)