Change external_network_bridge default to ''

This changes the default for external_network_bridge to '' to
encourage operators to deploy L3 agents in the correct manner.

This patch also adds a functional test to ensure that namespaces
with an existing external gateway interface are not torn down and
rewired on change.

Closes-Bug: #1563070
Change-Id: If533cf7c4c379be78f5a15073accaff7f65973ab
This commit is contained in:
Kevin Benton 2016-03-28 14:14:15 -07:00
parent 414f2ffc8d
commit 3f71a49e0f
6 changed files with 63 additions and 11 deletions

View File

@ -83,14 +83,14 @@ AVAILABILITY_ZONE_OPTS = [
] ]
EXT_NET_BRIDGE_OPTS = [ EXT_NET_BRIDGE_OPTS = [
cfg.StrOpt('external_network_bridge', default='br-ex', cfg.StrOpt('external_network_bridge', default='',
deprecated_for_removal=True, deprecated_for_removal=True,
help=_("Name of bridge used for external network " help=_("Name of bridge used for external network "
"traffic. This should be set to an empty value for the " "traffic. When this parameter is set, the L3 agent will "
"Linux Bridge. When this parameter is set, each L3 " "plug an interface directly into an external bridge "
"agent can be associated with no more than one external " "which will not allow any wiring by the L2 agent. Using "
"network. This option is deprecated and will be removed " "this will result in incorrect port statuses. This "
"in the M release.")), "option is deprecated and will be removed in Ocata."))
] ]

View File

@ -332,7 +332,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
ext_net_id = agent['configurations'].get( ext_net_id = agent['configurations'].get(
'gateway_external_network_id') 'gateway_external_network_id')
ext_bridge = agent['configurations'].get( ext_bridge = agent['configurations'].get(
'external_network_bridge', 'br-ex') 'external_network_bridge', '')
if (ext_net_id == network_id or if (ext_net_id == network_id or
(not ext_net_id and not ext_bridge)): (not ext_net_id and not ext_bridge)):
return return

View File

@ -24,6 +24,7 @@ from neutron.agent.linux import ip_lib
from neutron.callbacks import events from neutron.callbacks import events
from neutron.callbacks import registry from neutron.callbacks import registry
from neutron.callbacks import resources from neutron.callbacks import resources
from neutron.tests import base as tests_base
from neutron.tests.common import machine_fixtures from neutron.tests.common import machine_fixtures
from neutron.tests.common import net_helpers from neutron.tests.common import net_helpers
from neutron.tests.functional.agent.l3 import framework from neutron.tests.functional.agent.l3 import framework
@ -96,6 +97,39 @@ class L3AgentTestCase(framework.L3AgentTestFramework):
self.assertIsNone(device.route.get_gateway()) self.assertIsNone(device.route.get_gateway())
def _make_bridge(self):
bridge = framework.get_ovs_bridge(tests_base.get_rand_name())
bridge.create()
self.addCleanup(bridge.destroy)
return bridge
def test_external_network_bridge_change(self):
bridge1, bridge2 = self._make_bridge(), self._make_bridge()
self.agent.conf.set_override('external_network_bridge',
bridge1.br_name)
router_info = self.generate_router_info(False)
router = self.manage_router(self.agent, router_info)
gw_port = router.router['gw_port']
gw_inf_name = router.get_external_device_name(gw_port['id'])
self.assertIn(gw_inf_name,
[v.port_name for v in bridge1.get_vif_ports()])
# changeing the external_network_bridge should have no impact since
# the interface exists.
self.agent.conf.set_override('external_network_bridge',
bridge2.br_name)
self.manage_router(self.agent, router_info)
self.assertIn(gw_inf_name,
[v.port_name for v in bridge1.get_vif_ports()])
self.assertNotIn(gw_inf_name,
[v.port_name for v in bridge2.get_vif_ports()])
namespaces.Namespace.delete(router.router_namespace)
self.manage_router(self.agent, router_info)
self.assertIn(gw_inf_name,
[v.port_name for v in bridge2.get_vif_ports()])
self.assertNotIn(gw_inf_name,
[v.port_name for v in bridge1.get_vif_ports()])
def test_legacy_router_ns_rebuild(self): def test_legacy_router_ns_rebuild(self):
router_info = self.generate_router_info(False) router_info = self.generate_router_info(False)
router = self.manage_router(self.agent, router_info) router = self.manage_router(self.agent, router_info)

View File

@ -1813,7 +1813,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
self.mock_driver.unplug.assert_called_with( self.mock_driver.unplug.assert_called_with(
stale_devnames[0], stale_devnames[0],
bridge="br-ex", bridge="",
namespace=ri.ns_name, namespace=ri.ns_name,
prefix=l3_agent.EXTERNAL_DEV_PREFIX) prefix=l3_agent.EXTERNAL_DEV_PREFIX)
@ -1994,6 +1994,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
self._test_process_routers_update_router_deleted(True) self._test_process_routers_update_router_deleted(True)
def test_process_router_if_compatible_with_no_ext_net_in_conf(self): def test_process_router_if_compatible_with_no_ext_net_in_conf(self):
self.conf.set_override('external_network_bridge', 'br-ex')
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
self.plugin_api.get_external_network_id.return_value = 'aaa' self.plugin_api.get_external_network_id.return_value = 'aaa'
@ -2022,6 +2023,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
self.assertFalse(self.plugin_api.get_external_network_id.called) self.assertFalse(self.plugin_api.get_external_network_id.called)
def test_process_router_if_compatible_with_stale_cached_ext_net(self): def test_process_router_if_compatible_with_stale_cached_ext_net(self):
self.conf.set_override('external_network_bridge', 'br-ex')
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
self.plugin_api.get_external_network_id.return_value = 'aaa' self.plugin_api.get_external_network_id.return_value = 'aaa'
agent.target_ex_net_id = 'bbb' agent.target_ex_net_id = 'bbb'
@ -2037,6 +2039,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
agent.context) agent.context)
def test_process_router_if_compatible_w_no_ext_net_and_2_net_plugin(self): def test_process_router_if_compatible_w_no_ext_net_and_2_net_plugin(self):
self.conf.set_override('external_network_bridge', 'br-ex')
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
router = {'id': _uuid(), router = {'id': _uuid(),
@ -2078,7 +2081,6 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
'external_gateway_info': {'network_id': 'aaa'}} 'external_gateway_info': {'network_id': 'aaa'}}
agent.router_info = {} agent.router_info = {}
self.conf.set_override('external_network_bridge', '')
agent._process_router_if_compatible(router) agent._process_router_if_compatible(router)
self.assertIn(router['id'], agent.router_info) self.assertIn(router['id'], agent.router_info)

View File

@ -173,7 +173,7 @@ class TestDebugCommands(base.BaseTestCase):
'fake_port', 'fake_port',
'tap12345678-12', 'tap12345678-12',
'aa:bb:cc:dd:ee:ffa', 'aa:bb:cc:dd:ee:ffa',
bridge='br-ex', bridge='',
namespace=namespace), namespace=namespace),
mock.call.init_l3('tap12345678-12', mock.call.init_l3('tap12345678-12',
['10.0.0.3/24'], ['10.0.0.3/24'],
@ -223,7 +223,7 @@ class TestDebugCommands(base.BaseTestCase):
self.driver.assert_has_calls([mock.call.get_device_name(mock.ANY), self.driver.assert_has_calls([mock.call.get_device_name(mock.ANY),
mock.call.unplug('tap12345678-12', mock.call.unplug('tap12345678-12',
namespace=namespace, namespace=namespace,
bridge='br-ex')]) bridge='')])
def test_list_probe(self): def test_list_probe(self):
cmd = commands.ListProbe(self.app, None) cmd = commands.ListProbe(self.app, None)

View File

@ -0,0 +1,16 @@
---
prelude: >
The default value for 'external_network_bridge' in the L3 agent is now ''.
upgrade:
- The default value for 'external_network_bridge' has been changed to ''
since that is the preferred way to configure the L3 agent and will be the
only way in future releases. If you have not explicitly set this value
and you use the L3 agent, you will need to set this value to 'br-ex' to
match the old default.
If you are using 'br-ex', you should switch to '', ensure your external
network has a flat segment and ensure your L2 agent has a bridge_mapping
entry between the external network's flat segment physnet and 'br-ex' to
get the same connectivity. If the external network did not already have
the flat segment, you will need to detach all routers from the external
networks, delete the incorrect segment type, add the flat segment, and
re-attach the routers.