Merge "Ensure that l3 agent does not crash on restart"
This commit is contained in:
commit
a5a4e5f2f9
@ -29,6 +29,7 @@ from quantum.agent.common import config
|
|||||||
from quantum.agent.linux import interface
|
from quantum.agent.linux import interface
|
||||||
from quantum.agent.linux import ip_lib
|
from quantum.agent.linux import ip_lib
|
||||||
from quantum.agent.linux import iptables_manager
|
from quantum.agent.linux import iptables_manager
|
||||||
|
from quantum.agent.linux import utils
|
||||||
from quantum.db import l3_db
|
from quantum.db import l3_db
|
||||||
from quantum.openstack.common import cfg
|
from quantum.openstack.common import cfg
|
||||||
from quantum.openstack.common import importutils
|
from quantum.openstack.common import importutils
|
||||||
@ -147,22 +148,19 @@ class L3NATAgent(object):
|
|||||||
def _destroy_router_namespace(self, namespace):
|
def _destroy_router_namespace(self, namespace):
|
||||||
ns_ip = ip_lib.IPWrapper(self.conf.root_helper,
|
ns_ip = ip_lib.IPWrapper(self.conf.root_helper,
|
||||||
namespace=namespace)
|
namespace=namespace)
|
||||||
for d in ns_ip.get_devices():
|
for d in ns_ip.get_devices(exclude_loopback=True):
|
||||||
if d.name.startswith(INTERNAL_DEV_PREFIX):
|
if d.name.startswith(INTERNAL_DEV_PREFIX):
|
||||||
# device is on default bridge
|
# device is on default bridge
|
||||||
self.driver.unplug(d.name)
|
self.driver.unplug(d.name, namespace=namespace)
|
||||||
elif d.name.startswith(EXTERNAL_DEV_PREFIX):
|
elif d.name.startswith(EXTERNAL_DEV_PREFIX):
|
||||||
self.driver.unplug(d.name,
|
self.driver.unplug(d.name,
|
||||||
bridge=self.conf.external_network_bridge)
|
bridge=self.conf.external_network_bridge,
|
||||||
if self.conf.use_namespaces:
|
namespace=namespace)
|
||||||
ns_ip.netns.delete(namespace)
|
#(TODO) Address the failure for the deletion of the namespace
|
||||||
|
|
||||||
def _create_router_namespace(self, ri):
|
def _create_router_namespace(self, ri):
|
||||||
ip_wrapper_root = ip_lib.IPWrapper(self.conf.root_helper)
|
ip_wrapper_root = ip_lib.IPWrapper(self.conf.root_helper)
|
||||||
ip_wrapper_root.netns.add(ri.ns_name())
|
ip_wrapper = ip_wrapper_root.ensure_namespace(ri.ns_name())
|
||||||
|
|
||||||
ip_wrapper = ip_lib.IPWrapper(self.conf.root_helper,
|
|
||||||
namespace=ri.ns_name())
|
|
||||||
ip_wrapper.netns.execute(['sysctl', '-w', 'net.ipv4.ip_forward=1'])
|
ip_wrapper.netns.execute(['sysctl', '-w', 'net.ipv4.ip_forward=1'])
|
||||||
|
|
||||||
def daemon_loop(self):
|
def daemon_loop(self):
|
||||||
@ -364,10 +362,13 @@ class L3NATAgent(object):
|
|||||||
gw_ip = ex_gw_port['subnet']['gateway_ip']
|
gw_ip = ex_gw_port['subnet']['gateway_ip']
|
||||||
if ex_gw_port['subnet']['gateway_ip']:
|
if ex_gw_port['subnet']['gateway_ip']:
|
||||||
cmd = ['route', 'add', 'default', 'gw', gw_ip]
|
cmd = ['route', 'add', 'default', 'gw', gw_ip]
|
||||||
ip_wrapper = ip_lib.IPWrapper(self.conf.root_helper,
|
|
||||||
namespace=ri.ns_name())
|
|
||||||
if self.conf.use_namespaces:
|
if self.conf.use_namespaces:
|
||||||
ip_wrapper.netns.execute(cmd)
|
ip_wrapper = ip_lib.IPWrapper(self.conf.root_helper,
|
||||||
|
namespace=ri.ns_name())
|
||||||
|
ip_wrapper.netns.execute(cmd, check_exit_code=False)
|
||||||
|
else:
|
||||||
|
utils.execute(cmd, check_exit_code=False,
|
||||||
|
root_helper=self.conf.root_helper)
|
||||||
|
|
||||||
for (c, r) in self.external_gateway_filter_rules():
|
for (c, r) in self.external_gateway_filter_rules():
|
||||||
ri.iptables_manager.ipv4['filter'].add_rule(c, r)
|
ri.iptables_manager.ipv4['filter'].add_rule(c, r)
|
||||||
@ -384,7 +385,8 @@ class L3NATAgent(object):
|
|||||||
root_helper=self.conf.root_helper,
|
root_helper=self.conf.root_helper,
|
||||||
namespace=ri.ns_name()):
|
namespace=ri.ns_name()):
|
||||||
self.driver.unplug(interface_name,
|
self.driver.unplug(interface_name,
|
||||||
bridge=self.conf.external_network_bridge)
|
bridge=self.conf.external_network_bridge,
|
||||||
|
namespace=ri.ns_name())
|
||||||
|
|
||||||
ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address']
|
ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address']
|
||||||
for c, r in self.external_gateway_filter_rules():
|
for c, r in self.external_gateway_filter_rules():
|
||||||
@ -442,7 +444,7 @@ class L3NATAgent(object):
|
|||||||
if ip_lib.device_exists(interface_name,
|
if ip_lib.device_exists(interface_name,
|
||||||
root_helper=self.conf.root_helper,
|
root_helper=self.conf.root_helper,
|
||||||
namespace=ri.ns_name()):
|
namespace=ri.ns_name()):
|
||||||
self.driver.unplug(interface_name)
|
self.driver.unplug(interface_name, namespace=ri.ns_name())
|
||||||
|
|
||||||
if ex_gw_port:
|
if ex_gw_port:
|
||||||
ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address']
|
ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address']
|
||||||
|
@ -154,10 +154,6 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
|
|||||||
bridge = ovs_lib.OVSBridge(bridge, self.conf.root_helper)
|
bridge = ovs_lib.OVSBridge(bridge, self.conf.root_helper)
|
||||||
bridge.delete_port(device_name)
|
bridge.delete_port(device_name)
|
||||||
|
|
||||||
if namespace:
|
|
||||||
ip = ip_lib.IPWrapper(self.conf.root_helper, namespace)
|
|
||||||
ip.garbage_collect_namespace()
|
|
||||||
|
|
||||||
|
|
||||||
class BridgeInterfaceDriver(LinuxInterfaceDriver):
|
class BridgeInterfaceDriver(LinuxInterfaceDriver):
|
||||||
"""Driver for creating bridge interfaces."""
|
"""Driver for creating bridge interfaces."""
|
||||||
@ -200,10 +196,6 @@ class BridgeInterfaceDriver(LinuxInterfaceDriver):
|
|||||||
LOG.error(_("Failed unplugging interface '%s'") %
|
LOG.error(_("Failed unplugging interface '%s'") %
|
||||||
device_name)
|
device_name)
|
||||||
|
|
||||||
if namespace:
|
|
||||||
ip = ip_lib.IPWrapper(self.conf.root_helper, namespace)
|
|
||||||
ip.garbage_collect_namespace()
|
|
||||||
|
|
||||||
|
|
||||||
class RyuInterfaceDriver(OVSInterfaceDriver):
|
class RyuInterfaceDriver(OVSInterfaceDriver):
|
||||||
"""Driver for creating a Ryu OVS interface."""
|
"""Driver for creating a Ryu OVS interface."""
|
||||||
|
@ -338,7 +338,7 @@ class IpNetnsCommand(IpCommandBase):
|
|||||||
def delete(self, name):
|
def delete(self, name):
|
||||||
self._as_root('delete', name, use_root_namespace=True)
|
self._as_root('delete', name, use_root_namespace=True)
|
||||||
|
|
||||||
def execute(self, cmds, addl_env={}):
|
def execute(self, cmds, addl_env={}, check_exit_code=True):
|
||||||
if not self._parent.root_helper:
|
if not self._parent.root_helper:
|
||||||
raise exceptions.SudoRequired()
|
raise exceptions.SudoRequired()
|
||||||
elif not self._parent.namespace:
|
elif not self._parent.namespace:
|
||||||
@ -347,7 +347,8 @@ class IpNetnsCommand(IpCommandBase):
|
|||||||
return utils.execute(
|
return utils.execute(
|
||||||
['%s=%s' % pair for pair in addl_env.items()] +
|
['%s=%s' % pair for pair in addl_env.items()] +
|
||||||
['ip', 'netns', 'exec', self._parent.namespace] + list(cmds),
|
['ip', 'netns', 'exec', self._parent.namespace] + list(cmds),
|
||||||
root_helper=self._parent.root_helper)
|
root_helper=self._parent.root_helper,
|
||||||
|
check_exit_code=check_exit_code)
|
||||||
|
|
||||||
def exists(self, name):
|
def exists(self, name):
|
||||||
output = self._as_root('list', options='o', use_root_namespace=True)
|
output = self._as_root('list', options='o', use_root_namespace=True)
|
||||||
|
@ -331,7 +331,8 @@ class TestDhcpLocalProcess(TestBase):
|
|||||||
|
|
||||||
self.assertFalse(delegate.called)
|
self.assertFalse(delegate.called)
|
||||||
exp_args = ['ip', 'netns', 'exec', 'qdhcp-ns', 'kill', '-9', 5]
|
exp_args = ['ip', 'netns', 'exec', 'qdhcp-ns', 'kill', '-9', 5]
|
||||||
self.execute.assert_called_once_with(exp_args, root_helper='sudo')
|
self.execute.assert_called_once_with(exp_args, root_helper='sudo',
|
||||||
|
check_exit_code=True)
|
||||||
|
|
||||||
def test_disable(self):
|
def test_disable(self):
|
||||||
attrs_to_mock = dict([(a, mock.DEFAULT) for a in
|
attrs_to_mock = dict([(a, mock.DEFAULT) for a in
|
||||||
@ -348,7 +349,8 @@ class TestDhcpLocalProcess(TestBase):
|
|||||||
|
|
||||||
delegate.assert_has_calls([mock.call.destroy(network, 'tap0')])
|
delegate.assert_has_calls([mock.call.destroy(network, 'tap0')])
|
||||||
exp_args = ['ip', 'netns', 'exec', 'qdhcp-ns', 'kill', '-9', 5]
|
exp_args = ['ip', 'netns', 'exec', 'qdhcp-ns', 'kill', '-9', 5]
|
||||||
self.execute.assert_called_once_with(exp_args, root_helper='sudo')
|
self.execute.assert_called_once_with(exp_args, root_helper='sudo',
|
||||||
|
check_exit_code=True)
|
||||||
|
|
||||||
def test_pid(self):
|
def test_pid(self):
|
||||||
with mock.patch('__builtin__.open') as mock_open:
|
with mock.patch('__builtin__.open') as mock_open:
|
||||||
@ -452,7 +454,8 @@ class TestDnsmasq(TestBase):
|
|||||||
dm.spawn_process()
|
dm.spawn_process()
|
||||||
self.assertTrue(mocks['_output_opts_file'].called)
|
self.assertTrue(mocks['_output_opts_file'].called)
|
||||||
self.execute.assert_called_once_with(expected,
|
self.execute.assert_called_once_with(expected,
|
||||||
root_helper='sudo')
|
root_helper='sudo',
|
||||||
|
check_exit_code=True)
|
||||||
|
|
||||||
def test_spawn(self):
|
def test_spawn(self):
|
||||||
self._test_spawn([])
|
self._test_spawn([])
|
||||||
@ -539,7 +542,8 @@ tag:tag1,option:classless-static-route,%s,%s""".lstrip() % (fake_v6,
|
|||||||
|
|
||||||
self.safe.assert_has_calls([mock.call(exp_host_name, exp_host_data),
|
self.safe.assert_has_calls([mock.call(exp_host_name, exp_host_data),
|
||||||
mock.call(exp_opt_name, exp_opt_data)])
|
mock.call(exp_opt_name, exp_opt_data)])
|
||||||
self.execute.assert_called_once_with(exp_args, root_helper='sudo')
|
self.execute.assert_called_once_with(exp_args, root_helper='sudo',
|
||||||
|
check_exit_code=True)
|
||||||
|
|
||||||
def _test_lease_relay_script_helper(self, action, lease_remaining,
|
def _test_lease_relay_script_helper(self, action, lease_remaining,
|
||||||
path_exists=True):
|
path_exists=True):
|
||||||
|
@ -580,7 +580,8 @@ class TestIpNetnsCommand(TestIPCmdBase):
|
|||||||
self.netns_cmd.execute(['ip', 'link', 'list'])
|
self.netns_cmd.execute(['ip', 'link', 'list'])
|
||||||
execute.assert_called_once_with(['ip', 'netns', 'exec', 'ns', 'ip',
|
execute.assert_called_once_with(['ip', 'netns', 'exec', 'ns', 'ip',
|
||||||
'link', 'list'],
|
'link', 'list'],
|
||||||
root_helper='sudo')
|
root_helper='sudo',
|
||||||
|
check_exit_code=True)
|
||||||
|
|
||||||
def test_execute_env_var_prepend(self):
|
def test_execute_env_var_prepend(self):
|
||||||
self.parent.namespace = 'ns'
|
self.parent.namespace = 'ns'
|
||||||
@ -590,7 +591,7 @@ class TestIpNetnsCommand(TestIPCmdBase):
|
|||||||
execute.assert_called_once_with(
|
execute.assert_called_once_with(
|
||||||
['FOO=1', 'BAR=2', 'ip', 'netns', 'exec', 'ns', 'ip', 'link',
|
['FOO=1', 'BAR=2', 'ip', 'netns', 'exec', 'ns', 'ip', 'link',
|
||||||
'list'],
|
'list'],
|
||||||
root_helper='sudo')
|
root_helper='sudo', check_exit_code=True)
|
||||||
|
|
||||||
|
|
||||||
class TestDeviceExists(unittest.TestCase):
|
class TestDeviceExists(unittest.TestCase):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user