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 <adolfo.duarte@hpe.com>
Change-Id: Id70553e8980593f99548a4d2b0a78355933f7c2c
This commit is contained in:
Armando Migliaccio 2016-08-03 14:00:04 -07:00 committed by Kevin Benton
parent e47da4edf5
commit e354599134
9 changed files with 201 additions and 0 deletions

View File

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

View File

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

View File

@ -52,11 +52,14 @@ from neutron import context
from neutron.extensions import portbindings from neutron.extensions import portbindings
from neutron.plugins.common import constants as p_const from neutron.plugins.common import constants as p_const
from neutron.plugins.common import utils as p_utils 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.l2pop.rpc_manager import l2population_rpc
from neutron.plugins.ml2.drivers.openvswitch.agent.common \ from neutron.plugins.ml2.drivers.openvswitch.agent.common \
import constants import constants
from neutron.plugins.ml2.drivers.openvswitch.agent \ from neutron.plugins.ml2.drivers.openvswitch.agent \
import ovs_agent_extension_api as ovs_ext_api 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 \ from neutron.plugins.ml2.drivers.openvswitch.agent \
import ovs_dvr_neutron_agent import ovs_dvr_neutron_agent
from neutron.plugins.ml2.drivers.openvswitch.agent import vlanmanager from neutron.plugins.ml2.drivers.openvswitch.agent import vlanmanager
@ -2152,10 +2155,12 @@ def prepare_xen_compute():
def main(bridge_classes): def main(bridge_classes):
prepare_xen_compute() prepare_xen_compute()
ovs_capabilities.register()
validate_tunnel_config(cfg.CONF.AGENT.tunnel_types, cfg.CONF.OVS.local_ip) validate_tunnel_config(cfg.CONF.AGENT.tunnel_types, cfg.CONF.OVS.local_ip)
try: try:
agent = OVSNeutronAgent(bridge_classes, cfg.CONF) agent = OVSNeutronAgent(bridge_classes, cfg.CONF)
capabilities.notify_init_event(n_const.AGENT_TYPE_OVS, agent)
except (RuntimeError, ValueError) as e: except (RuntimeError, ValueError) as e:
LOG.error(_LE("%s Agent terminated!"), e) LOG.error(_LE("%s Agent terminated!"), e)
sys.exit(1) sys.exit(1)

View File

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

View File

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

View File

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

View File

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