Merge "Add workaround for eventlet.greendns bug" into stable/train
This commit is contained in:
commit
c7e955658e
|
@ -16,9 +16,11 @@
|
|||
import os
|
||||
import socket
|
||||
|
||||
from eventlet import patcher
|
||||
from neutron_lib.utils import runtime
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import eventletutils
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from neutron.conf.agent import common as config
|
||||
|
@ -70,6 +72,34 @@ def is_agent_down(heart_beat_time):
|
|||
cfg.CONF.agent_down_time)
|
||||
|
||||
|
||||
class _SocketWrapper(object):
|
||||
"""Determines if socket module is patched by eventlet
|
||||
and unpatches it.
|
||||
|
||||
If python standard library socket module is patched, it will request
|
||||
an unpached version of the socket module. The sole purpose of this
|
||||
class is to workaround eventlet bug
|
||||
https://github.com/eventlet/eventlet/issues/764 and for the
|
||||
class to be used with get_hypervisor_hostname. This class also helps
|
||||
with socket mocks as it abstracts eventlet under the hood module
|
||||
imports which can be tricky to target with mocks.
|
||||
TODO(mtomaska): This class(workaround) can be removed once eventlet
|
||||
issue is resolved.
|
||||
"""
|
||||
def __init__(self):
|
||||
if eventletutils.is_monkey_patched(socket.__name__):
|
||||
LOG.debug("Std library socket module is patched by eventlet. "
|
||||
"Requesting std library socket module from eventlet.")
|
||||
self._socket = patcher.original(socket.__name__)
|
||||
else:
|
||||
LOG.debug("Std library socket module is not patched by eventlet. "
|
||||
"Using socket module as imported from std library.")
|
||||
self._socket = socket
|
||||
|
||||
def getaddrinfo(self, host, port, family, flags):
|
||||
return self._socket.getaddrinfo(host, port, family, 0, 0, flags)
|
||||
|
||||
|
||||
def get_hypervisor_hostname():
|
||||
"""Get hypervisor hostname
|
||||
|
||||
|
@ -81,18 +111,21 @@ def get_hypervisor_hostname():
|
|||
'.' in hypervisor_hostname):
|
||||
return hypervisor_hostname
|
||||
|
||||
_socket_wrap = _SocketWrapper()
|
||||
try:
|
||||
addrinfo = socket.getaddrinfo(host=hypervisor_hostname,
|
||||
port=None,
|
||||
family=socket.AF_UNSPEC,
|
||||
flags=socket.AI_CANONNAME)
|
||||
addrinfo = _socket_wrap.getaddrinfo(hypervisor_hostname,
|
||||
None,
|
||||
socket.AF_UNSPEC,
|
||||
socket.AI_CANONNAME)
|
||||
# getaddrinfo returns a list of 5-tuples with;
|
||||
# (family, type, proto, canonname, sockaddr)
|
||||
if (addrinfo and addrinfo[0][3] and
|
||||
not addrinfo[0][3].startswith('localhost')):
|
||||
return addrinfo[0][3]
|
||||
except (OSError, socket.gaierror):
|
||||
pass
|
||||
except (OSError, socket.gaierror) as err:
|
||||
LOG.warning("Error: %s, occured while querying for fqdn. "
|
||||
"get_hypervisor_hostname will just "
|
||||
"return %s", err, hypervisor_hostname)
|
||||
|
||||
return hypervisor_hostname
|
||||
|
||||
|
@ -101,15 +134,13 @@ def default_rp_hypervisors(hypervisors, device_mappings,
|
|||
default_hypervisor=None):
|
||||
"""Fill config option 'resource_provider_hypervisors' with defaults.
|
||||
|
||||
Default hypervisor names to socket.gethostname() unless default_hypervisor
|
||||
is set.
|
||||
|
||||
:param hypervisors: Config option 'resource_provider_hypervisors'
|
||||
as parsed by oslo.config, that is a dict with keys of physical devices
|
||||
and values of hypervisor names.
|
||||
:param device_mappings: Device mappings standardized to the list-valued
|
||||
format.
|
||||
:param default_hypervisor: Default hypervisor hostname.
|
||||
:param default_hypervisor: Default hypervisor hostname. If not set,
|
||||
it tries to default to fully qualified domain name (fqdn)
|
||||
"""
|
||||
_default_hypervisor = default_hypervisor or get_hypervisor_hostname()
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ class TestLoadInterfaceDriver(base.BaseTestCase):
|
|||
|
||||
class TestGetHypervisorHostname(base.BaseTestCase):
|
||||
|
||||
@mock.patch('socket.getaddrinfo')
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_gethostname_fqdn(self, hostname_mock,
|
||||
addrinfo_mock):
|
||||
|
@ -91,7 +91,7 @@ class TestGetHypervisorHostname(base.BaseTestCase):
|
|||
utils.get_hypervisor_hostname())
|
||||
addrinfo_mock.assert_not_called()
|
||||
|
||||
@mock.patch('socket.getaddrinfo')
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_gethostname_localhost(self, hostname_mock,
|
||||
addrinfo_mock):
|
||||
|
@ -101,7 +101,7 @@ class TestGetHypervisorHostname(base.BaseTestCase):
|
|||
utils.get_hypervisor_hostname())
|
||||
addrinfo_mock.assert_not_called()
|
||||
|
||||
@mock.patch('socket.getaddrinfo')
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_getaddrinfo(self, hostname_mock,
|
||||
addrinfo_mock):
|
||||
|
@ -111,10 +111,9 @@ class TestGetHypervisorHostname(base.BaseTestCase):
|
|||
'host.domain',
|
||||
utils.get_hypervisor_hostname())
|
||||
addrinfo_mock.assert_called_once_with(
|
||||
host='host', port=None, family=socket.AF_UNSPEC,
|
||||
flags=socket.AI_CANONNAME)
|
||||
'host', None, socket.AF_UNSPEC, socket.AI_CANONNAME)
|
||||
|
||||
@mock.patch('socket.getaddrinfo')
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_getaddrinfo_no_canonname(self,
|
||||
hostname_mock,
|
||||
|
@ -125,10 +124,9 @@ class TestGetHypervisorHostname(base.BaseTestCase):
|
|||
'host',
|
||||
utils.get_hypervisor_hostname())
|
||||
addrinfo_mock.assert_called_once_with(
|
||||
host='host', port=None, family=socket.AF_UNSPEC,
|
||||
flags=socket.AI_CANONNAME)
|
||||
'host', None, socket.AF_UNSPEC, socket.AI_CANONNAME)
|
||||
|
||||
@mock.patch('socket.getaddrinfo')
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_getaddrinfo_localhost(self, hostname_mock,
|
||||
addrinfo_mock):
|
||||
|
@ -139,10 +137,9 @@ class TestGetHypervisorHostname(base.BaseTestCase):
|
|||
'host',
|
||||
utils.get_hypervisor_hostname())
|
||||
addrinfo_mock.assert_called_once_with(
|
||||
host='host', port=None, family=socket.AF_UNSPEC,
|
||||
flags=socket.AI_CANONNAME)
|
||||
'host', None, socket.AF_UNSPEC, socket.AI_CANONNAME)
|
||||
|
||||
@mock.patch('socket.getaddrinfo')
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_getaddrinfo_fail(self, hostname_mock,
|
||||
addrinfo_mock):
|
||||
|
@ -152,8 +149,7 @@ class TestGetHypervisorHostname(base.BaseTestCase):
|
|||
'host',
|
||||
utils.get_hypervisor_hostname())
|
||||
addrinfo_mock.assert_called_once_with(
|
||||
host='host', port=None, family=socket.AF_UNSPEC,
|
||||
flags=socket.AI_CANONNAME)
|
||||
'host', None, socket.AF_UNSPEC, socket.AI_CANONNAME)
|
||||
|
||||
|
||||
class TestDefaultRpHypervisors(base.BaseTestCase):
|
||||
|
|
Loading…
Reference in New Issue