Merge "Restore the N535 eventlet import check"
This commit is contained in:
@@ -15,11 +15,9 @@
|
||||
|
||||
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.agent.linux import utils
|
||||
@@ -66,37 +64,6 @@ def is_agent_down(heart_beat_time):
|
||||
cfg.CONF.agent_down_time)
|
||||
|
||||
|
||||
class _SocketWrapper:
|
||||
"""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=host,
|
||||
port=port,
|
||||
family=family,
|
||||
flags=flags)
|
||||
|
||||
|
||||
def get_hypervisor_hostname():
|
||||
"""Get hypervisor hostname
|
||||
|
||||
@@ -108,12 +75,11 @@ def get_hypervisor_hostname():
|
||||
'.' in hypervisor_hostname):
|
||||
return hypervisor_hostname
|
||||
|
||||
_socket_wrap = _SocketWrapper()
|
||||
try:
|
||||
addrinfo = _socket_wrap.getaddrinfo(host=hypervisor_hostname,
|
||||
port=None,
|
||||
family=socket.AF_UNSPEC,
|
||||
flags=socket.AI_CANONNAME)
|
||||
addrinfo = socket.getaddrinfo(host=hypervisor_hostname,
|
||||
port=None,
|
||||
family=socket.AF_UNSPEC,
|
||||
flags=socket.AI_CANONNAME)
|
||||
# getaddrinfo returns a list of 5-tuples with;
|
||||
# (family, type, proto, canonname, sockaddr)
|
||||
if (addrinfo and addrinfo[0][3] and
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# 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.common import eventlet_utils
|
||||
|
||||
eventlet_utils.monkey_patch()
|
||||
@@ -1,54 +0,0 @@
|
||||
# Copyright (c) 2015 Cloudbase Solutions.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 os
|
||||
import threading
|
||||
|
||||
import eventlet
|
||||
from eventlet.green import threading as threading_eventlet
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import eventletutils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
IS_MONKEY_PATCHED = False
|
||||
|
||||
|
||||
def monkey_patch():
|
||||
global IS_MONKEY_PATCHED
|
||||
if not IS_MONKEY_PATCHED:
|
||||
# This environment variable will be used in eventlet 0.39.0
|
||||
# https://github.com/eventlet/eventlet/commit/
|
||||
# b754135b045306022a537b5797f2cb2cf47ba49b
|
||||
if os.getenv('EVENTLET_MONKEYPATCH', '1') == '1':
|
||||
IS_MONKEY_PATCHED = True
|
||||
return
|
||||
|
||||
eventlet.monkey_patch()
|
||||
LOG.warning('This program is using eventlet and has been '
|
||||
'monkey_patched')
|
||||
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from oslo_utils import importutils
|
||||
p_c_e = importutils.import_module('pyroute2.config.asyncio')
|
||||
p_c_e.asyncio_config()
|
||||
IS_MONKEY_PATCHED = True
|
||||
|
||||
|
||||
def get_threading_local():
|
||||
if eventletutils.is_monkey_patched('thread'):
|
||||
return threading_eventlet.local()
|
||||
return threading.local()
|
||||
@@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
import contextlib
|
||||
import threading
|
||||
|
||||
from keystoneauth1 import exceptions as ks_exceptions
|
||||
from keystoneauth1 import loading as ks_loading
|
||||
@@ -34,7 +35,6 @@ from oslo_utils import uuidutils
|
||||
from sqlalchemy.orm import attributes as sql_attr
|
||||
import tenacity
|
||||
|
||||
from neutron.common import eventlet_utils
|
||||
from neutron.notifiers import batch_notifier
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ NOTIFIER_ENABLE_DEFAULT = True
|
||||
# callbacks from the agents (DHCP, L2), trying to update the provisioning
|
||||
# status of a port. In order to handle each context notifier enable flag, a
|
||||
# thread local variable is used.
|
||||
_notifier_store = eventlet_utils.get_threading_local()
|
||||
_notifier_store = threading.local()
|
||||
|
||||
|
||||
@registry.has_registry_receivers
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# 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.common import eventlet_utils
|
||||
|
||||
|
||||
eventlet_utils.monkey_patch()
|
||||
|
||||
@@ -18,9 +18,10 @@ import copy
|
||||
import functools
|
||||
import itertools
|
||||
import random
|
||||
import threading
|
||||
import time
|
||||
from unittest import mock
|
||||
|
||||
import eventlet
|
||||
import netaddr
|
||||
from neutron_lib.api.definitions import external_net as enet_api
|
||||
from neutron_lib.callbacks import exceptions
|
||||
@@ -6976,11 +6977,12 @@ class DbModelMixin:
|
||||
return thing
|
||||
|
||||
with lock():
|
||||
coro = eventlet.spawn(_lock_blocked_name_update)
|
||||
coro = threading.Thread(target=_lock_blocked_name_update)
|
||||
coro.start()
|
||||
# wait for the coroutine to get blocked on the lock before
|
||||
# we proceed to update the record underneath it
|
||||
while not self._blocked_on_lock:
|
||||
eventlet.sleep(0)
|
||||
time.sleep(0)
|
||||
ctx = context.get_admin_context()
|
||||
with db_api.CONTEXT_WRITER.using(ctx):
|
||||
thing = ctx.session.query(model).filter_by(id=dbid).one()
|
||||
@@ -6992,7 +6994,7 @@ class DbModelMixin:
|
||||
# the coroutine should have encountered a stale data error because
|
||||
# the status update thread would have bumped the revision number
|
||||
# while it was waiting to commit
|
||||
coro.wait()
|
||||
coro.join()
|
||||
# another attempt should work fine
|
||||
thing = _lock_blocked_name_update()
|
||||
self.assertEqual('a description', thing.description)
|
||||
@@ -7119,21 +7121,22 @@ class DbModelMixin:
|
||||
try:
|
||||
with db_api.CONTEXT_WRITER.using(ctx):
|
||||
thing = ctx.session.query(model).filter_by(id=dbid).one()
|
||||
eventlet.sleep(0)
|
||||
time.sleep(0)
|
||||
ctx.session.delete(thing)
|
||||
except orm.exc.StaleDataError as e:
|
||||
if e and "confirm_deleted_rows" in str(e):
|
||||
self.fail("Meets bug 1916889")
|
||||
|
||||
with lock():
|
||||
coro = eventlet.spawn(_lock_blocked_object_delete)
|
||||
coro = threading.Thread(target=_lock_blocked_object_delete)
|
||||
coro.start()
|
||||
ctx = context.get_admin_context()
|
||||
with db_api.CONTEXT_WRITER.using(ctx):
|
||||
thing = ctx.session.query(model).filter_by(id=dbid).one()
|
||||
eventlet.sleep(0)
|
||||
time.sleep(0)
|
||||
ctx.session.delete(thing)
|
||||
|
||||
coro.wait()
|
||||
coro.join()
|
||||
|
||||
# The DB object with its standard_attr should be deleted
|
||||
with testtools.ExpectedException(orm.exc.NoResultFound):
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# 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.common import eventlet_utils
|
||||
|
||||
|
||||
eventlet_utils.monkey_patch()
|
||||
|
||||
@@ -17,25 +17,10 @@ import sys
|
||||
|
||||
from oslo_config import cfg # noqa
|
||||
|
||||
from neutron.agent.l3 import ha
|
||||
from neutron.common import config
|
||||
from neutron.common import eventlet_utils
|
||||
from neutron.tests.common.agents import l3_agent
|
||||
|
||||
|
||||
eventlet_utils.monkey_patch()
|
||||
|
||||
|
||||
# NOTE(ralonsoh): remove when eventlet is removed.
|
||||
def patch_keepalived_notifications_server():
|
||||
def start_keepalived_notifications_server():
|
||||
pass
|
||||
|
||||
ha.AgentMixin._start_keepalived_notifications_server = (
|
||||
start_keepalived_notifications_server)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
config.register_common_config_options()
|
||||
patch_keepalived_notifications_server()
|
||||
sys.exit(l3_agent.main())
|
||||
|
||||
@@ -18,13 +18,11 @@ import os
|
||||
import random
|
||||
import time
|
||||
|
||||
import eventlet
|
||||
import netaddr
|
||||
from neutron_lib.tests import tools
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from neutron._i18n import _
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.common import utils as common_utils
|
||||
from neutron.conf.agent import common as config
|
||||
@@ -101,7 +99,7 @@ class BaseFullStackTestCase(testlib_api.MySQLTestCaseMixin,
|
||||
agent = self.client.show_agent(agent_id)['agent']
|
||||
return agent.get('alive')
|
||||
|
||||
wait_until_true(_agent_up)
|
||||
common_utils.wait_until_true(_agent_up)
|
||||
|
||||
def _wait_until_agent_down(self, agent_id):
|
||||
def _agent_down():
|
||||
@@ -119,7 +117,7 @@ class BaseFullStackTestCase(testlib_api.MySQLTestCaseMixin,
|
||||
agent = self.client.show_agent(agent_id)['agent']
|
||||
return not agent.get('alive')
|
||||
|
||||
wait_until_true(_agent_down)
|
||||
common_utils.wait_until_true(_agent_down)
|
||||
|
||||
def _assert_ping_during_agents_restart(
|
||||
self, agents, src_namespace, ips, restart_timeout=30,
|
||||
@@ -142,7 +140,7 @@ class BaseFullStackTestCase(testlib_api.MySQLTestCaseMixin,
|
||||
# happen only after RPC is established
|
||||
agent_names = ', '.join({agent.process_fixture.process_name
|
||||
for agent in agents})
|
||||
wait_until_true(
|
||||
common_utils.wait_until_true(
|
||||
done,
|
||||
timeout=count * (ping_timeout + 1),
|
||||
exception=RuntimeError("Could not ping the other VM, "
|
||||
@@ -199,32 +197,6 @@ class BaseFullStackTestCase(testlib_api.MySQLTestCaseMixin,
|
||||
return vms
|
||||
|
||||
def assert_namespace_exists(self, ns_name):
|
||||
wait_until_true(
|
||||
common_utils.wait_until_true(
|
||||
lambda: ip_lib.network_namespace_exists(ns_name,
|
||||
try_is_ready=True))
|
||||
|
||||
|
||||
def wait_until_true(predicate, timeout=60, sleep=1, exception=None):
|
||||
"""Wait until callable predicate is evaluated as True
|
||||
|
||||
NOTE(ralonsoh): this method should be replaced with
|
||||
``neutron.common.utils.wait_until_true`` once the eventlet deprecation is
|
||||
finished in the fullstack framework.
|
||||
|
||||
:param predicate: Callable deciding whether waiting should continue.
|
||||
Best practice is to instantiate predicate with functools.partial()
|
||||
:param timeout: Timeout in seconds how long should function wait.
|
||||
:param sleep: Polling interval for results in seconds.
|
||||
:param exception: Exception instance to raise on timeout. If None is passed
|
||||
(default) then WaitTimeout exception is raised.
|
||||
"""
|
||||
try:
|
||||
with eventlet.Timeout(timeout):
|
||||
while not predicate():
|
||||
eventlet.sleep(sleep)
|
||||
except eventlet.Timeout:
|
||||
if exception is not None:
|
||||
# pylint: disable=raising-bad-type
|
||||
raise exception
|
||||
raise common_utils.WaitTimeout(
|
||||
_("Timed out after %d seconds") % timeout)
|
||||
|
||||
@@ -77,7 +77,7 @@ class TestLoadInterfaceDriver(base.BaseTestCase):
|
||||
|
||||
class TestGetHypervisorHostname(base.BaseTestCase):
|
||||
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch.object(socket, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_gethostname_fqdn(self, hostname_mock,
|
||||
addrinfo_mock):
|
||||
@@ -87,7 +87,7 @@ class TestGetHypervisorHostname(base.BaseTestCase):
|
||||
utils.get_hypervisor_hostname())
|
||||
addrinfo_mock.assert_not_called()
|
||||
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch.object(socket, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_gethostname_localhost(self, hostname_mock,
|
||||
addrinfo_mock):
|
||||
@@ -97,7 +97,7 @@ class TestGetHypervisorHostname(base.BaseTestCase):
|
||||
utils.get_hypervisor_hostname())
|
||||
addrinfo_mock.assert_not_called()
|
||||
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch.object(socket, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_getaddrinfo(self, hostname_mock,
|
||||
addrinfo_mock):
|
||||
@@ -110,7 +110,7 @@ class TestGetHypervisorHostname(base.BaseTestCase):
|
||||
host='host', port=None, family=socket.AF_UNSPEC,
|
||||
flags=socket.AI_CANONNAME)
|
||||
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch.object(socket, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_getaddrinfo_no_canonname(self,
|
||||
hostname_mock,
|
||||
@@ -124,7 +124,7 @@ class TestGetHypervisorHostname(base.BaseTestCase):
|
||||
host='host', port=None, family=socket.AF_UNSPEC,
|
||||
flags=socket.AI_CANONNAME)
|
||||
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch.object(socket, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_getaddrinfo_localhost(self, hostname_mock,
|
||||
addrinfo_mock):
|
||||
@@ -138,7 +138,7 @@ class TestGetHypervisorHostname(base.BaseTestCase):
|
||||
host='host', port=None, family=socket.AF_UNSPEC,
|
||||
flags=socket.AI_CANONNAME)
|
||||
|
||||
@mock.patch.object(utils._SocketWrapper, 'getaddrinfo')
|
||||
@mock.patch.object(socket, 'getaddrinfo')
|
||||
@mock.patch('socket.gethostname')
|
||||
def test_get_hypervisor_hostname_getaddrinfo_fail(self, hostname_mock,
|
||||
addrinfo_mock):
|
||||
|
||||
@@ -8,7 +8,6 @@ PasteDeploy>=1.5.0 # MIT
|
||||
Routes>=2.3.1 # MIT
|
||||
debtcollector>=1.19.0 # Apache-2.0
|
||||
decorator>=4.1.0 # BSD
|
||||
eventlet>=0.36.1 # MIT
|
||||
pecan>=1.4.0 # BSD
|
||||
httplib2>=0.22.0 # MIT
|
||||
requests>=2.32.3 # Apache-2.0
|
||||
|
||||
2
tox.ini
2
tox.ini
@@ -239,7 +239,7 @@ select = H,N
|
||||
# N535: Usage of Python eventlet module not allowed
|
||||
# N536: Use assertIsNone
|
||||
enable-extensions = H106,H203,H204,H205,H904,N521,N524,N529,N530,N532,N534,N535,N536
|
||||
ignore = H405,H701,H702,H703,N530,N535
|
||||
ignore = H405,H701,H702,H703,N530
|
||||
show-source = true
|
||||
exclude = ./.*,build,dist,doc
|
||||
|
||||
|
||||
Reference in New Issue
Block a user