Skip to content

Commit a564d8a

Browse files
authored
Merge pull request #882 from moreati/macos-11
Fix macOS 11.x and 12.x bootstrap
2 parents 4c02ea6 + 9a19f0e commit a564d8a

File tree

6 files changed

+107
-14
lines changed

6 files changed

+107
-14
lines changed

.ci/azure-pipelines-steps.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ steps:
99
displayName: Install python
1010
inputs:
1111
versionSpec: '$(python.version)'
12+
condition: ne(variables['python.version'], '')
1213

1314
- script: python -mpip install tox
1415
displayName: Install tooling
1516

16-
- script: tox -e "$(tox.env)"
17+
- script: python -mtox -e "$(tox.env)"
1718
displayName: "Run tests"
1819
env:
1920
AWS_ACCESS_KEY_ID: $(AWS_ACCESS_KEY_ID)

.ci/azure-pipelines.yml

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,27 @@
99
#ANSIBLE_VERBOSITY: 3
1010

1111
jobs:
12+
- job: Mac1014
13+
# vanilla Ansible is really slow
14+
timeoutInMinutes: 120
15+
steps:
16+
- template: azure-pipelines-steps.yml
17+
pool:
18+
# https://github.com/actions/virtual-environments/blob/main/images/macos/
19+
vmImage: macOS-10.14
20+
strategy:
21+
matrix:
22+
Mito_27:
23+
python.version: '2.7'
24+
tox.env: py27-mode_mitogen
25+
Mito_36:
26+
python.version: '3.6'
27+
tox.env: py36-mode_mitogen
28+
Mito_39:
29+
python.version: '3.9'
30+
tox.env: py39-mode_mitogen
1231

13-
- job: Mac
32+
- job: Mac1015
1433
# vanilla Ansible is really slow
1534
timeoutInMinutes: 120
1635
steps:
@@ -23,6 +42,12 @@ jobs:
2342
Mito_27:
2443
python.version: '2.7'
2544
tox.env: py27-mode_mitogen
45+
Mito_36:
46+
python.version: '3.6'
47+
tox.env: py36-mode_mitogen
48+
Mito_39:
49+
python.version: '3.9'
50+
tox.env: py39-mode_mitogen
2651

2752
# TODO: test python3, python3 tests are broken
2853
Loc_27_210:
@@ -52,6 +77,46 @@ jobs:
5277
STRATEGY: linear
5378
ANSIBLE_SKIP_TAGS: resource_intensive
5479

80+
- job: MacLatest
81+
# vanilla Ansible is really slow
82+
timeoutInMinutes: 120
83+
steps:
84+
- template: azure-pipelines-steps.yml
85+
pool:
86+
# https://github.com/actions/virtual-environments/blob/main/images/macos/
87+
vmImage: macOS-latest
88+
strategy:
89+
matrix:
90+
Mito_27:
91+
tox.env: py27-mode_mitogen
92+
Mito_37:
93+
python.version: '3.7'
94+
tox.env: py37-mode_mitogen
95+
Mito_39:
96+
python.version: '3.9'
97+
tox.env: py39-mode_mitogen
98+
99+
# TODO: test python3, python3 tests are broken
100+
Loc_27_210:
101+
tox.env: py27-mode_localhost-ansible2.10
102+
Loc_27_3:
103+
tox.env: py27-mode_localhost-ansible3
104+
Loc_27_4:
105+
tox.env: py27-mode_localhost-ansible4
106+
107+
# NOTE: this hangs when ran in Ubuntu 18.04
108+
Van_27_210:
109+
tox.env: py27-mode_localhost-ansible2.10
110+
STRATEGY: linear
111+
ANSIBLE_SKIP_TAGS: resource_intensive
112+
Van_27_3:
113+
tox.env: py27-mode_localhost-ansible3
114+
STRATEGY: linear
115+
ANSIBLE_SKIP_TAGS: resource_intensive
116+
Van_27_4:
117+
tox.env: py27-mode_localhost-ansible4
118+
STRATEGY: linear
119+
ANSIBLE_SKIP_TAGS: resource_intensive
55120

56121
- job: Linux
57122
pool:

docs/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ To avail of fixes in an unreleased version, please download a ZIP file
2121
v0.3.1.dev0 (unreleased)
2222
------------------------
2323

24+
* :gh:issue:`774` Fix bootstrap failures on macOS 11.x and 12.x, involving Python 2.7 wrapper
2425
* :gh:issue:`834` Support for Ansible 3 and 4 (ansible-core 2.11)
2526
* :gh:issue:`869` Continuous Integration tests are now run with Tox
2627
* :gh:issue:`869` Continuous Integration tests now cover CentOS 6 & 8, Debian 9 & 11, Ubuntu 16.04 & 20.04

mitogen/master.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def _stdlib_paths():
108108
]
109109
prefixes = (getattr(sys, a, None) for a in attr_candidates)
110110
version = 'python%s.%s' % sys.version_info[0:2]
111-
s = set(os.path.abspath(os.path.join(p, 'lib', version))
111+
s = set(os.path.realpath(os.path.join(p, 'lib', version))
112112
for p in prefixes if p is not None)
113113

114114
# When running 'unit2 tests/module_finder_test.py' in a Py2 venv on Ubuntu

mitogen/parent.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,9 +1412,12 @@ def __repr__(self):
14121412
# * macOS <= 10.14 (Darwin <= 18) install an unreliable Python version
14131413
# switcher as /usr/bin/python, which introspects argv0. To workaround
14141414
# it we redirect attempts to call /usr/bin/python with an explicit
1415-
# call to /usr/bin/python2.7. macOS 10.15+ (Darwin 19+) removed it.
1416-
# On these versions /usr/bin/python is a symlink to
1417-
# /System/Library/Frameworks/Python.framework/Versions/2.7/.../Python
1415+
# call to /usr/bin/python2.7. macOS 10.15 (Darwin 19) removed it.
1416+
# * macOS 11.x (Darwin 20, Big Sur) and macOS 12.x (Darwin 21, Montery)
1417+
# do something slightly different. The Python executable is patched to
1418+
# perform an extra execvp(). I don't fully understand the details, but
1419+
# setting PYTHON_LAUNCHED_FROM_WRAPPER=1 avoids it.
1420+
# * macOS 13.x (Darwin 22?) may remove python 2.x entirely.
14181421
#
14191422
# Locals:
14201423
# R: read side of interpreter stdin.
@@ -1437,7 +1440,8 @@ def _first_stage():
14371440
os.close(r)
14381441
os.close(W)
14391442
os.close(w)
1440-
if sys.executable+sys.platform=='/usr/bin/pythondarwin'and os.uname()[2]<'19':sys.executable+='2.7'
1443+
if os.uname()[0]=='Darwin'and os.uname()[2][:2]<'19'and sys.executable=='/usr/bin/python':sys.executable='/usr/bin/python2.7'
1444+
if os.uname()[0]=='Darwin'and os.uname()[2][:2]in'2021'and sys.version[:3]=='2.7':os.environ['PYTHON_LAUNCHED_FROM_WRAPPER']='1'
14411445
os.environ['ARGV0']=sys.executable
14421446
os.execl(sys.executable,sys.executable+'(mitogen:CONTEXT_NAME)')
14431447
os.write(1,'MITO000\n'.encode())

tests/testlib.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11

2+
import errno
23
import logging
34
import os
45
import random
@@ -11,6 +12,7 @@
1112
import time
1213
import traceback
1314

15+
import psutil
1416
import unittest2
1517

1618
import mitogen.core
@@ -67,7 +69,6 @@ def get_fd_count():
6769
"""
6870
Return the number of FDs open by this process.
6971
"""
70-
import psutil
7172
return psutil.Process().num_fds()
7273

7374

@@ -334,6 +335,10 @@ def setUpClass(cls):
334335
# Broker() instantiations in setUp() etc.
335336
mitogen.fork.on_fork()
336337
cls._fd_count_before = get_fd_count()
338+
# Ignore children started by external packages - in particular
339+
# multiprocessing.resource_tracker.main()`, started when some Ansible
340+
# versions instantiate a `multithreading.Lock()`.
341+
cls._children_before = frozenset(psutil.Process().children())
337342
super(TestCase, cls).setUpClass()
338343

339344
ALLOWED_THREADS = set([
@@ -361,7 +366,10 @@ def _teardown_check_threads(self):
361366
def _teardown_check_fds(self):
362367
mitogen.core.Latch._on_fork()
363368
if get_fd_count() != self._fd_count_before:
364-
import os; os.system('lsof +E -w -p %s | grep -vw mem' % (os.getpid(),))
369+
if sys.platform == 'linux':
370+
os.system('lsof +E -w -p %i | grep -vw mem' % (os.getpid(),))
371+
else:
372+
os.system('lsof -w -p %i | grep -vw mem' % (os.getpid(),))
365373
assert 0, "%s leaked FDs. Count before: %s, after: %s" % (
366374
self, self._fd_count_before, get_fd_count(),
367375
)
@@ -374,19 +382,33 @@ def _teardown_check_zombies(self):
374382
if self.no_zombie_check:
375383
return
376384

385+
# pid=0: Wait for any child process in the same process group as us.
386+
# WNOHANG: Don't block if no processes ready to report status.
377387
try:
378388
pid, status = os.waitpid(0, os.WNOHANG)
379-
except OSError:
380-
return # ECHILD
389+
except OSError as e:
390+
# ECHILD: there are no child processes in our group.
391+
if e.errno == errno.ECHILD:
392+
return
393+
raise
381394

382395
if pid:
383396
assert 0, "%s failed to reap subprocess %d (status %d)." % (
384397
self, pid, status
385398
)
386399

387-
print('')
388-
print('Children of unit test process:')
389-
os.system('ps uww --ppid ' + str(os.getpid()))
400+
children_after = frozenset(psutil.Process().children())
401+
children_leaked = children_after.difference(self._children_before)
402+
if not children_leaked:
403+
return
404+
405+
print('Leaked children of unit test process:')
406+
os.system('ps -o "user,pid,%%cpu,%%mem,vsz,rss,tty,stat,start,time,command" -ww -p %s'
407+
% (','.join(str(p.pid) for p in children_leaked),))
408+
if self._children_before:
409+
print('Pre-existing children of unit test process:')
410+
os.system('ps -o "user,pid,%%cpu,%%mem,vsz,rss,tty,stat,start,time,command" -ww -p %s'
411+
% (','.join(str(p.pid) for p in self._children_before),))
390412
assert 0, "%s leaked still-running subprocesses." % (self,)
391413

392414
def tearDown(self):

0 commit comments

Comments
 (0)