Browse Source

Fix AttributeError on select.poll()

Change-Id: Iefcae89cdedd13535c3135ca7227362f1cf9abc8
Closes-Bug: #1889396
Aurelien Lourot 2 years ago
  1. 37


@ -14,7 +14,6 @@
# limitations under the License.
import json
from multiprocessing import Queue
from neutron_lib.api.definitions import portbindings
from neutron_lib import constants as n_const
@ -28,10 +27,42 @@ from neutron.db import segments_db
from networking_arista.common import constants as a_const
from networking_arista.common import db_lib
from networking_arista.ml2 import arista_sync
from networking_arista.ml2 import arista_trunk
from networking_arista.ml2.rpc.arista_eapi import AristaRPCWrapperEapi
# When used as a Neutron plugin, neutron-lib imports this code. However earlier
# neutron-lib has already imported 'multiprocessing'. This means the python
# module cache (sys.modules) contains a version of 'multiprocessing' where
# select.poll() exists.
# Further down we import arista_sync, which spawns a greenthread. This
# greenthread then uses a green version of 'multiprocessing' where
# select.poll() has been removed.
# Doing here multiprocessing.Queue.put() and in the greenthread
# multiprocessing.Queue.get(timeout=...) leads to:
# AttributeError: module 'select' has no attribute 'poll'
# We can't do eventlet.monkey_patch() early enough (before the first
# 'mutiprocessing' import) as we would have to do it in neutron-lib and it's
# forbidden, see
# The solution is to let the python module cache here forget the already
# imported 'multiprocessing' and re-import a green one. Here again
# eventlet.monkey_patch() doesn't seem to help as it doesn't seem to touch
# 'multiprocessing'. Thus we use eventlet.import_patched() instead:
import eventlet
import sys
modules_to_forget = []
for imported_module_name in sys.modules:
if imported_module_name.startswith('multiprocessing'):
for module_to_forget in modules_to_forget:
del sys.modules[module_to_forget]
# import a green 'multiprocessing':
multiprocessing = eventlet.import_patched('multiprocessing')
from networking_arista.ml2 import arista_sync # noqa: E402
LOG = logging.getLogger(__name__)
cfg.CONF.import_group('ml2_arista', 'networking_arista.common.config')
@ -70,7 +101,7 @@ class AristaDriver(driver_api.MechanismDriver):
self.eapi = AristaRPCWrapperEapi()
self.mlag_pairs = dict()
self.provision_queue = Queue()
self.provision_queue = multiprocessing.Queue()
self.trunk_driver = None
self.vif_details = {portbindings.VIF_DETAILS_CONNECTIVITY: