Skip to content

Commit ceddc5c

Browse files
committed
Merge remote-tracking branch 'origin/dmw'
* origin/dmw: issue #482: another Py3 fix ci: try removing exclude: to make Azure jobs work again compat: fix Py2.4 SyntaxError issue #482: remove 'ssh' from checked processes ci: Py3 fix issue #279: add one more test for max_message_size issue #482: ci: add stray process checks to all jobs tests: fix format string error core: MitogenProtocol.is_privileged was not set in children issue #482: tests: fail DockerMixin tests if stray processes exist docs: update Changelog. issue #586: update Changelog. docs: update Changelog. [security] core: undirectional routing wasn't respected in some cases docs: tidy up Select.all() issue #612: update Changelog.
2 parents c6de090 + 8bac1cf commit ceddc5c

File tree

13 files changed

+204
-34
lines changed

13 files changed

+204
-34
lines changed

.ci/ansible_tests.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,17 @@ def pause_if_interactive():
2020
signal.pause()
2121

2222

23+
interesting = ci_lib.get_interesting_procs()
24+
25+
2326
with ci_lib.Fold('unit_tests'):
2427
os.environ['SKIP_MITOGEN'] = '1'
2528
ci_lib.run('./run_tests -v')
2629

2730

31+
ci_lib.check_stray_processes(interesting)
32+
33+
2834
with ci_lib.Fold('docker_setup'):
2935
containers = ci_lib.make_containers()
3036
ci_lib.start_containers(containers)
@@ -75,4 +81,7 @@ def pause_if_interactive():
7581
pause_if_interactive()
7682
raise
7783

84+
85+
ci_lib.check_stray_processes(interesting, containers)
86+
7887
pause_if_interactive()

.ci/azure-pipelines.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@
33
# Add steps that analyze code, save the dist with the build record, publish to a PyPI-compatible index, and more:
44
# https://docs.microsoft.com/azure/devops/pipelines/languages/python
55

6-
trigger:
7-
branches:
8-
exclude:
9-
- docs-master
10-
116
jobs:
127

138
- job: Mac

.ci/ci_lib.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,46 @@ def make_containers(name_prefix='', port_offset=0):
215215
return lst
216216

217217

218+
# ssh removed from here because 'linear' strategy relies on processes that hang
219+
# around after the Ansible run completes
220+
INTERESTING_COMMS = ('python', 'sudo', 'su', 'doas')
221+
222+
223+
def proc_is_docker(pid):
224+
try:
225+
fp = open('/proc/%s/cgroup' % (pid,), 'r')
226+
except IOError:
227+
return False
228+
229+
try:
230+
return 'docker' in fp.read()
231+
finally:
232+
fp.close()
233+
234+
235+
def get_interesting_procs(container_name=None):
236+
args = ['ps', '-a', '-x', '-oppid=', '-opid=', '-ocomm=', '-ocommand=']
237+
if container_name is not None:
238+
args = ['docker', 'exec', container_name] + args
239+
240+
out = []
241+
for line in subprocess__check_output(args).decode().splitlines():
242+
ppid, pid, comm, rest = line.split(None, 3)
243+
if (
244+
(
245+
any(comm.startswith(s) for s in INTERESTING_COMMS) or
246+
'mitogen:' in rest
247+
) and
248+
(
249+
container_name is not None or
250+
(not proc_is_docker(pid))
251+
)
252+
):
253+
out.append((int(pid), line))
254+
255+
return sorted(out)
256+
257+
218258
def start_containers(containers):
219259
if os.environ.get('KEEP'):
220260
return
@@ -236,9 +276,44 @@ def start_containers(containers):
236276
]
237277
for container in containers
238278
])
279+
280+
for container in containers:
281+
container['interesting'] = get_interesting_procs(container['name'])
282+
239283
return containers
240284

241285

286+
def verify_procs(hostname, old, new):
287+
oldpids = set(pid for pid, _ in old)
288+
if any(pid not in oldpids for pid, _ in new):
289+
print('%r had stray processes running:' % (hostname,))
290+
for pid, line in new:
291+
if pid not in oldpids:
292+
print('New process:', line)
293+
294+
print()
295+
return False
296+
297+
return True
298+
299+
300+
def check_stray_processes(old, containers=None):
301+
ok = True
302+
303+
new = get_interesting_procs()
304+
if old is not None:
305+
ok &= verify_procs('test host machine', old, new)
306+
307+
for container in containers or ():
308+
ok &= verify_procs(
309+
container['name'],
310+
container['interesting'],
311+
get_interesting_procs(container['name'])
312+
)
313+
314+
assert ok, 'stray processes were found'
315+
316+
242317
def dump_file(path):
243318
print()
244319
print('--- %s ---' % (path,))

.ci/debops_common_tests.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,15 @@
6868
os.environ['ANSIBLE_HOST_KEY_CHECKING'] = 'False'
6969

7070

71+
interesting = ci_lib.get_interesting_procs()
72+
7173
with ci_lib.Fold('first_run'):
7274
ci_lib.run('debops common %s', ' '.join(sys.argv[1:]))
7375

76+
ci_lib.check_stray_processes(interesting, containers)
77+
7478

7579
with ci_lib.Fold('second_run'):
7680
ci_lib.run('debops common %s', ' '.join(sys.argv[1:]))
81+
82+
ci_lib.check_stray_processes(interesting, containers)

.ci/mitogen_install.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@
1414
'docker pull %s' % (ci_lib.image_for_distro(ci_lib.DISTRO),),
1515
])
1616

17+
1718
ci_lib.run_batches(batches)

.ci/mitogen_tests.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@
1414
if not ci_lib.have_docker():
1515
os.environ['SKIP_DOCKER_TESTS'] = '1'
1616

17+
interesting = ci_lib.get_interesting_procs()
1718
ci_lib.run('./run_tests -v')
19+
ci_lib.check_stray_processes(interesting)

docs/changelog.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,16 @@ Core Library
164164
`closed` flag, preventing historical bugs where a double close could destroy
165165
descriptors belonging to unrelated streams.
166166

167+
* `#586 <https://github.com/dw/mitogen/issues/586>`_: fix import of
168+
:mod:`__main__` on later versions of Python 3 when running from the
169+
interactive console.
170+
167171
* `#606 <https://github.com/dw/mitogen/issues/606>`_: fix example code on the
168172
documentation front page.
169173

174+
* `#612 <https://github.com/dw/mitogen/issues/612>`_: fix various errors
175+
introduced by stream refactoring.
176+
170177
* `a5536c35 <https://github.com/dw/mitogen/commit/a5536c35>`_: avoid quadratic
171178
buffer management when logging lines received from a child's redirected
172179
standard IO.
@@ -183,6 +190,14 @@ Core Library
183190
buffered items, causing future :meth:`get` calls to block or fail even though
184191
data existed that could be returned.
185192

193+
* `5924af15 <https://github.com/dw/mitogen/commit/5924af15>`_: *[security]* the
194+
unidirectional routing mode, in which contexts may only communicate with
195+
parents and never siblings (so a program cannot accidentally bridge
196+
air-gapped networks) was not inherited when a child context was initiated
197+
directly from an existing child. This did not effect the Ansible extension,
198+
since the controller initiates any new context used for routing, only forked
199+
tasks are initiated by children.
200+
186201

187202
Thanks!
188203
~~~~~~~
@@ -193,8 +208,10 @@ bug reports, testing, features and fixes in this release contributed by
193208
`Anton Markelov <https://github.com/strangeman>`_,
194209
`Dan <https://github.com/dsgnr>`_,
195210
`Dave Cottlehuber <https://github.com/dch>`_,
211+
`Denis Krienbühl <https://github.com/href>`_,
196212
`El Mehdi CHAOUKI <https://github.com/elmchaouki>`_,
197213
`James Hogarth <https://github.com/hogarthj>`_,
214+
`Marc Hartmayer <https://github.com/marc1006>`_,
198215
`Nigel Metheringham <https://github.com/nigelm>`_,
199216
`Orion Poplawski <https://github.com/opoplawski>`_,
200217
`Pieter Voet <https://github.com/pietervoet/>`_,

mitogen/compat/pkgutil.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,8 @@ def extend_path(path, name):
542542
if os.path.isfile(pkgfile):
543543
try:
544544
f = open(pkgfile)
545-
except IOError as msg:
545+
except IOError:
546+
msg = sys.exc_info()[1]
546547
sys.stderr.write("Can't open %s: %s\n" %
547548
(pkgfile, msg))
548549
else:

mitogen/core.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,18 +1937,28 @@ class MitogenProtocol(Protocol):
19371937
:class:`Protocol` implementing mitogen's :ref:`stream protocol
19381938
<stream-protocol>`.
19391939
"""
1940-
#: If not :data:`None`, :class:`Router` stamps this into
1941-
#: :attr:`Message.auth_id` of every message received on this stream.
1942-
auth_id = None
1943-
19441940
#: If not :data:`False`, indicates the stream has :attr:`auth_id` set and
19451941
#: its value is the same as :data:`mitogen.context_id` or appears in
19461942
#: :data:`mitogen.parent_ids`.
19471943
is_privileged = False
19481944

1949-
def __init__(self, router, remote_id):
1945+
def __init__(self, router, remote_id, auth_id=None,
1946+
local_id=None, parent_ids=None):
19501947
self._router = router
19511948
self.remote_id = remote_id
1949+
#: If not :data:`None`, :class:`Router` stamps this into
1950+
#: :attr:`Message.auth_id` of every message received on this stream.
1951+
self.auth_id = auth_id
1952+
1953+
if parent_ids is None:
1954+
parent_ids = mitogen.parent_ids
1955+
if local_id is None:
1956+
local_id = mitogen.context_id
1957+
1958+
self.is_privileged = (
1959+
(remote_id in parent_ids) or
1960+
auth_id in ([local_id] + parent_ids)
1961+
)
19521962
self.sent_modules = set(['mitogen', 'mitogen.core'])
19531963
self._input_buf = collections.deque()
19541964
self._input_buf_len = 0
@@ -2800,8 +2810,8 @@ class Router(object):
28002810
broker_exit_msg = 'Broker has exitted'
28012811
no_route_msg = 'no route to %r, my ID is %r'
28022812
unidirectional_msg = (
2803-
'routing mode prevents forward of message from context %d via '
2804-
'context %d'
2813+
'routing mode prevents forward of message from context %d to '
2814+
'context %d via context %d'
28052815
)
28062816

28072817
def __init__(self, broker):
@@ -3152,7 +3162,9 @@ def _async_route(self, msg, in_stream=None):
31523162
(in_stream.protocol.is_privileged or
31533163
out_stream.protocol.is_privileged):
31543164
self._maybe_send_dead(msg, self.unidirectional_msg,
3155-
in_stream.protocol.remote_id, out_stream.protocol.remote_id)
3165+
in_stream.protocol.remote_id,
3166+
out_stream.protocol.remote_id,
3167+
mitogen.context_id)
31563168
return
31573169

31583170
out_stream.protocol._send(msg)
@@ -3623,7 +3635,7 @@ def _setup_master(self):
36233635
self.broker = Broker(activate_compat=False)
36243636
self.router = Router(self.broker)
36253637
self.router.debug = self.config.get('debug', False)
3626-
self.router.undirectional = self.config['unidirectional']
3638+
self.router.unidirectional = self.config['unidirectional']
36273639
self.router.add_handler(
36283640
fn=self._on_shutdown_msg,
36293641
handle=SHUTDOWN,
@@ -3641,7 +3653,12 @@ def _setup_master(self):
36413653
os.close(in_fd)
36423654

36433655
out_fp = os.fdopen(os.dup(self.config.get('out_fd', 1)), 'wb', 0)
3644-
self.stream = MitogenProtocol.build_stream(self.router, parent_id)
3656+
self.stream = MitogenProtocol.build_stream(
3657+
self.router,
3658+
parent_id,
3659+
local_id=self.config['context_id'],
3660+
parent_ids=self.config['parent_ids']
3661+
)
36453662
self.stream.accept(in_fp, out_fp)
36463663
self.stream.name = 'parent'
36473664
self.stream.receive_side.keep_alive = False

mitogen/select.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,10 @@ def __init__(self, receivers=(), oneshot=True):
122122
@classmethod
123123
def all(cls, receivers):
124124
"""
125-
Take an iterable of receivers and retrieve a :class:`Message` from
126-
each, returning the result of calling `msg.unpickle()` on each in turn.
127-
Results are returned in the order they arrived.
125+
Take an iterable of receivers and retrieve a :class:`Message
126+
<mitogen.core.Message>` from each, returning the result of calling
127+
:meth:`Message.unpickle() <mitogen.core.Message.unpickle>` on each in
128+
turn. Results are returned in the order they arrived.
128129
129130
This is sugar for handling batch :meth:`Context.call_async
130131
<mitogen.parent.Context.call_async>` invocations:

0 commit comments

Comments
 (0)