Merge "Switch isolated metadata proxy to bind to 169.254.169.254"

This commit is contained in:
Zuul 2019-02-05 13:51:37 +00:00 committed by Gerrit Code Review
commit 46dc30991a
10 changed files with 45 additions and 28 deletions

View File

@ -657,7 +657,7 @@ class DhcpAgent(manager.Manager):
metadata_driver.MetadataDriver.spawn_monitored_metadata_proxy( metadata_driver.MetadataDriver.spawn_monitored_metadata_proxy(
self._process_monitor, network.namespace, dhcp.METADATA_PORT, self._process_monitor, network.namespace, dhcp.METADATA_PORT,
self.conf, **kwargs) self.conf, bind_address=dhcp.METADATA_DEFAULT_IP, **kwargs)
def disable_isolated_metadata_proxy(self, network): def disable_isolated_metadata_proxy(self, network):
if (self.conf.enable_metadata_network and if (self.conf.enable_metadata_network and

View File

@ -208,16 +208,8 @@ class FipNamespace(namespaces.Namespace):
LOG.debug("DVR: add fip namespace: %s", self.name) LOG.debug("DVR: add fip namespace: %s", self.name)
# parent class will ensure the namespace exists and turn-on forwarding # parent class will ensure the namespace exists and turn-on forwarding
super(FipNamespace, self).create() super(FipNamespace, self).create()
# Somewhere in the 3.19 kernel timeframe ip_nonlocal_bind was ip_lib.set_ip_nonlocal_bind_for_namespace(self.name, 1,
# changed to be a per-namespace attribute. To be backwards root_namespace=True)
# compatible we need to try both if at first we fail.
failed = ip_lib.set_ip_nonlocal_bind(
value=1, namespace=self.name, log_fail_as_error=False)
if failed:
LOG.debug('DVR: fip namespace (%s) does not support setting '
'net.ipv4.ip_nonlocal_bind, trying in root namespace',
self.name)
ip_lib.set_ip_nonlocal_bind(value=1)
# no connection tracking needed in fip namespace # no connection tracking needed in fip namespace
self._iptables_manager.ipv4['raw'].add_rule('PREROUTING', self._iptables_manager.ipv4['raw'].add_rule('PREROUTING',

View File

@ -32,7 +32,7 @@ class SnatNamespace(namespaces.Namespace):
super(SnatNamespace, self).create() super(SnatNamespace, self).create()
# This might be an HA router namespaces and it should not have # This might be an HA router namespaces and it should not have
# ip_nonlocal_bind enabled # ip_nonlocal_bind enabled
ip_lib.set_ip_nonlocal_bind_for_namespace(self.name) ip_lib.set_ip_nonlocal_bind_for_namespace(self.name, 0)
# Set nf_conntrack_tcp_loose to 0 to ensure mid-stream # Set nf_conntrack_tcp_loose to 0 to ensure mid-stream
# TCP conversations aren't taken over by SNAT # TCP conversations aren't taken over by SNAT
cmd = ['net.netfilter.nf_conntrack_tcp_loose=0'] cmd = ['net.netfilter.nf_conntrack_tcp_loose=0']

View File

@ -57,7 +57,7 @@ class HaRouterNamespace(namespaces.RouterNamespace):
def create(self): def create(self):
super(HaRouterNamespace, self).create(ipv6_forwarding=False) super(HaRouterNamespace, self).create(ipv6_forwarding=False)
# HA router namespaces should not have ip_nonlocal_bind enabled # HA router namespaces should not have ip_nonlocal_bind enabled
ip_lib.set_ip_nonlocal_bind_for_namespace(self.name) ip_lib.set_ip_nonlocal_bind_for_namespace(self.name, 0)
class HaRouter(router.RouterInfo): class HaRouter(router.RouterInfo):

View File

@ -1486,6 +1486,8 @@ class DeviceManager(object):
# and added back statically in the call to init_l3() below. # and added back statically in the call to init_l3() below.
if network.namespace: if network.namespace:
ip_lib.IPWrapper().ensure_namespace(network.namespace) ip_lib.IPWrapper().ensure_namespace(network.namespace)
ip_lib.set_ip_nonlocal_bind_for_namespace(network.namespace, 1,
root_namespace=True)
if ipv6_utils.is_enabled_and_bind_by_default(): if ipv6_utils.is_enabled_and_bind_by_default():
self.driver.configure_ipv6_ra(network.namespace, 'default', self.driver.configure_ipv6_ra(network.namespace, 'default',
n_const.ACCEPT_RA_DISABLED) n_const.ACCEPT_RA_DISABLED)

View File

@ -1175,18 +1175,25 @@ def set_ip_nonlocal_bind(value, namespace=None, log_fail_as_error=True):
log_fail_as_error=log_fail_as_error) log_fail_as_error=log_fail_as_error)
def set_ip_nonlocal_bind_for_namespace(namespace): def set_ip_nonlocal_bind_for_namespace(namespace, value, root_namespace=False):
"""Set ip_nonlocal_bind but don't raise exception on failure.""" """Set ip_nonlocal_bind but don't raise exception on failure."""
failed = set_ip_nonlocal_bind(value=0, namespace=namespace, failed = set_ip_nonlocal_bind(value, namespace=namespace,
log_fail_as_error=False) log_fail_as_error=False)
if failed and root_namespace:
# Somewhere in the 3.19 kernel timeframe ip_nonlocal_bind was
# changed to be a per-namespace attribute. To be backwards
# compatible we need to try both if at first we fail.
LOG.debug('Namespace (%s) does not support setting %s, '
'trying in root namespace', namespace, IP_NONLOCAL_BIND)
return set_ip_nonlocal_bind(value)
if failed: if failed:
LOG.warning( LOG.warning(
"%s will not be set to 0 in the root namespace in order to " "%s will not be set to %d in the root namespace in order to "
"not break DVR, which requires this value be set to 1. This " "not break DVR, which requires this value be set to 1. This "
"may introduce a race between moving a floating IP to a " "may introduce a race between moving a floating IP to a "
"different network node, and the peer side getting a " "different network node, and the peer side getting a "
"populated ARP cache for a given floating IP address.", "populated ARP cache for a given floating IP address.",
IP_NONLOCAL_BIND) IP_NONLOCAL_BIND, value)
def get_ipv6_forwarding(device, namespace=None): def get_ipv6_forwarding(device, namespace=None):

View File

@ -62,7 +62,7 @@ defaults
timeout http-keep-alive 30s timeout http-keep-alive 30s
listen listener listen listener
bind 0.0.0.0:%(port)s bind %(host)s:%(port)s
server metadata %(unix_socket_path)s server metadata %(unix_socket_path)s
http-request add-header X-Neutron-%(res_type)s-ID %(res_id)s http-request add-header X-Neutron-%(res_type)s-ID %(res_id)s
""" """
@ -73,13 +73,14 @@ class InvalidUserOrGroupException(Exception):
class HaproxyConfigurator(object): class HaproxyConfigurator(object):
def __init__(self, network_id, router_id, unix_socket_path, port, user, def __init__(self, network_id, router_id, unix_socket_path, host, port,
group, state_path, pid_file): user, group, state_path, pid_file):
self.network_id = network_id self.network_id = network_id
self.router_id = router_id self.router_id = router_id
if network_id is None and router_id is None: if network_id is None and router_id is None:
raise exceptions.NetworkIdOrRouterIdRequiredError() raise exceptions.NetworkIdOrRouterIdRequiredError()
self.host = host
self.port = port self.port = port
self.user = user self.user = user
self.group = group self.group = group
@ -117,6 +118,7 @@ class HaproxyConfigurator(object):
_("Invalid group/gid: '%s'") % self.group) _("Invalid group/gid: '%s'") % self.group)
cfg_info = { cfg_info = {
'host': self.host,
'port': self.port, 'port': self.port,
'unix_socket_path': self.unix_socket_path, 'unix_socket_path': self.unix_socket_path,
'user': username, 'user': username,
@ -210,8 +212,8 @@ class MetadataDriver(object):
return user, group return user, group
@classmethod @classmethod
def _get_metadata_proxy_callback(cls, port, conf, network_id=None, def _get_metadata_proxy_callback(cls, bind_address, port, conf,
router_id=None): network_id=None, router_id=None):
def callback(pid_file): def callback(pid_file):
metadata_proxy_socket = conf.metadata_proxy_socket metadata_proxy_socket = conf.metadata_proxy_socket
user, group = ( user, group = (
@ -219,6 +221,7 @@ class MetadataDriver(object):
haproxy = HaproxyConfigurator(network_id, haproxy = HaproxyConfigurator(network_id,
router_id, router_id,
metadata_proxy_socket, metadata_proxy_socket,
bind_address,
port, port,
user, user,
group, group,
@ -233,10 +236,12 @@ class MetadataDriver(object):
@classmethod @classmethod
def spawn_monitored_metadata_proxy(cls, monitor, ns_name, port, conf, def spawn_monitored_metadata_proxy(cls, monitor, ns_name, port, conf,
network_id=None, router_id=None): bind_address="0.0.0.0", network_id=None,
router_id=None):
uuid = network_id or router_id uuid = network_id or router_id
callback = cls._get_metadata_proxy_callback( callback = cls._get_metadata_proxy_callback(
port, conf, network_id=network_id, router_id=router_id) bind_address, port, conf, network_id=network_id,
router_id=router_id)
pm = cls._get_metadata_proxy_process_manager(uuid, conf, pm = cls._get_metadata_proxy_process_manager(uuid, conf,
ns_name=ns_name, ns_name=ns_name,
callback=callback) callback=callback)
@ -270,7 +275,7 @@ def after_router_added(resource, event, l3_agent, **kwargs):
router = kwargs['router'] router = kwargs['router']
proxy = l3_agent.metadata_driver proxy = l3_agent.metadata_driver
for c, r in proxy.metadata_filter_rules(proxy.metadata_port, for c, r in proxy.metadata_filter_rules(proxy.metadata_port,
proxy.metadata_access_mark): proxy.metadata_access_mark):
router.iptables_manager.ipv4['filter'].add_rule(c, r) router.iptables_manager.ipv4['filter'].add_rule(c, r)
for c, r in proxy.metadata_nat_rules(proxy.metadata_port): for c, r in proxy.metadata_nat_rules(proxy.metadata_port):
router.iptables_manager.ipv4['nat'].add_rule(c, r) router.iptables_manager.ipv4['nat'].add_rule(c, r)

View File

@ -221,6 +221,9 @@ fake_down_network = dhcp.NetModel(
class TestDhcpAgent(base.BaseTestCase): class TestDhcpAgent(base.BaseTestCase):
METADATA_DEFAULT_IP = dhcp.METADATA_DEFAULT_IP
def setUp(self): def setUp(self):
super(TestDhcpAgent, self).setUp() super(TestDhcpAgent, self).setUp()
entry.register_options(cfg.CONF) entry.register_options(cfg.CONF)
@ -495,6 +498,7 @@ class TestDhcpAgent(base.BaseTestCase):
dhcp.configure_dhcp_for_network(fake_network) dhcp.configure_dhcp_for_network(fake_network)
md_cls.spawn_monitored_metadata_proxy.assert_called_once_with( md_cls.spawn_monitored_metadata_proxy.assert_called_once_with(
mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY,
bind_address=self.METADATA_DEFAULT_IP,
network_id=fake_network.id) network_id=fake_network.id)
dhcp.disable_dhcp_helper(fake_network.id) dhcp.disable_dhcp_helper(fake_network.id)
md_cls.destroy_monitored_metadata_proxy.assert_called_once_with( md_cls.destroy_monitored_metadata_proxy.assert_called_once_with(
@ -890,10 +894,12 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
'.spawn_monitored_metadata_proxy') '.spawn_monitored_metadata_proxy')
with mock.patch(method_path) as spawn: with mock.patch(method_path) as spawn:
self.dhcp.enable_isolated_metadata_proxy(network) self.dhcp.enable_isolated_metadata_proxy(network)
metadata_ip = dhcp.METADATA_DEFAULT_IP
spawn.assert_called_once_with(self.dhcp._process_monitor, spawn.assert_called_once_with(self.dhcp._process_monitor,
network.namespace, network.namespace,
dhcp.METADATA_PORT, dhcp.METADATA_PORT,
cfg.CONF, cfg.CONF,
bind_address=metadata_ip,
router_id='forzanapoli') router_id='forzanapoli')
def test_enable_isolated_metadata_proxy_with_metadata_network(self): def test_enable_isolated_metadata_proxy_with_metadata_network(self):

View File

@ -1712,7 +1712,7 @@ class TestSetIpNonlocalBindForHaNamespace(base.BaseTestCase):
def test_setting_failure(self): def test_setting_failure(self):
"""Make sure message is formatted correctly.""" """Make sure message is formatted correctly."""
with mock.patch.object(ip_lib, 'set_ip_nonlocal_bind', return_value=1): with mock.patch.object(ip_lib, 'set_ip_nonlocal_bind', return_value=1):
ip_lib.set_ip_nonlocal_bind_for_namespace('foo') ip_lib.set_ip_nonlocal_bind_for_namespace('foo', value=1)
class TestSysctl(base.BaseTestCase): class TestSysctl(base.BaseTestCase):

View File

@ -64,6 +64,7 @@ class TestMetadataDriverProcess(base.BaseTestCase):
EUNAME = 'neutron' EUNAME = 'neutron'
EGNAME = 'neutron' EGNAME = 'neutron'
METADATA_DEFAULT_IP = '169.254.169.254'
METADATA_PORT = 8080 METADATA_PORT = 8080
METADATA_SOCKET = '/socket/path' METADATA_SOCKET = '/socket/path'
PIDFILE = 'pidfile' PIDFILE = 'pidfile'
@ -146,6 +147,7 @@ class TestMetadataDriverProcess(base.BaseTestCase):
router_ns, router_ns,
self.METADATA_PORT, self.METADATA_PORT,
agent.conf, agent.conf,
bind_address=self.METADATA_DEFAULT_IP,
router_id=router_id) router_id=router_id)
netns_execute_args = [ netns_execute_args = [
@ -157,6 +159,7 @@ class TestMetadataDriverProcess(base.BaseTestCase):
cfg_contents = metadata_driver._HAPROXY_CONFIG_TEMPLATE % { cfg_contents = metadata_driver._HAPROXY_CONFIG_TEMPLATE % {
'user': self.EUNAME, 'user': self.EUNAME,
'group': self.EGNAME, 'group': self.EGNAME,
'host': self.METADATA_DEFAULT_IP,
'port': self.METADATA_PORT, 'port': self.METADATA_PORT,
'unix_socket_path': self.METADATA_SOCKET, 'unix_socket_path': self.METADATA_SOCKET,
'res_type': 'Router', 'res_type': 'Router',
@ -178,7 +181,8 @@ class TestMetadataDriverProcess(base.BaseTestCase):
def test_create_config_file_wrong_user(self): def test_create_config_file_wrong_user(self):
with mock.patch('pwd.getpwnam', side_effect=KeyError): with mock.patch('pwd.getpwnam', side_effect=KeyError):
config = metadata_driver.HaproxyConfigurator(_uuid(), mock.ANY, config = metadata_driver.HaproxyConfigurator(_uuid(),
mock.ANY, mock.ANY,
mock.ANY, mock.ANY, mock.ANY, mock.ANY,
self.EUNAME, self.EUNAME,
self.EGNAME, self.EGNAME,
@ -190,7 +194,8 @@ class TestMetadataDriverProcess(base.BaseTestCase):
with mock.patch('grp.getgrnam', side_effect=KeyError),\ with mock.patch('grp.getgrnam', side_effect=KeyError),\
mock.patch('pwd.getpwnam', mock.patch('pwd.getpwnam',
return_value=test_utils.FakeUser(self.EUNAME)): return_value=test_utils.FakeUser(self.EUNAME)):
config = metadata_driver.HaproxyConfigurator(_uuid(), mock.ANY, config = metadata_driver.HaproxyConfigurator(_uuid(),
mock.ANY, mock.ANY,
mock.ANY, mock.ANY, mock.ANY, mock.ANY,
self.EUNAME, self.EUNAME,
self.EGNAME, self.EGNAME,