Commit Graph

263 Commits (master)

Author SHA1 Message Date
David Wilson 9fe14e841c parent: reap the child process if connection fails
For example if no response is received in :attr:`connect_timeout`
seconds, the child would be left running.
6 years ago
David Wilson 46a311165e issue #148: parent: prevent race in iter_read()
There is no guarantee on the ordering select() returns file descriptors.
So if, e.g. in the case of sudo_nonexistent.yml, sudo prints an error
to a single FD before exitting, there was previously no gurantee
iter_read() would read off the error before failing due to detecting
disconnect on any FD.

Now instead we keep reading while any non-disconnected FD exists.
6 years ago
David Wilson e43c6c531b Mostly implement hybrid TTY/socket mode for sudo and SSH.
Presently there is still no mechanism to add :attr:`tty_stream` to the
multiplexer after connection is successful, but for now it's not
expected that anything will be logged to it anyway.

Closes #148.
6 years ago
David Wilson c6284e00e9 Use subprocess to start child processes; closes #185. 6 years ago
David Wilson bdc76c8231 parent: do not attempt to reap child twice. 6 years ago
David Wilson 202ce0f641 Prevent construction of unicode Message.data
And fix one case of it in parent.py.
6 years ago
David Wilson cc980569a3 issue #159: initial context LRU implementation
Now Connection.close() *must* be called in the worker, to ensure the
reference count for a context drops correctly.

Remove 'discriminator' for now, I'm not using it for testing any more
and it complicated this code.

This code is a car crash, it needs rewritten again. Ideally some/most of
this behaviour could live on services.DeduplicatingService somehow, but
I couldn't come up with a sensible design.
6 years ago
David Wilson 4c8ec131f9 issue #16: initial smorgasbord of 3.x fixes. 6 years ago
David Wilson c4bef102fe issue #16: Python 2.4-3.x compatible exception handling. 6 years ago
David Wilson e5b784ed32 parent: reduce cutpaste
Unclear whether exec() is better or worse than __import__(), but at
least the semantics are correct.
6 years ago
David Wilson 813d139d48 Import v2.7.11 tokenize.py for use on older Pythons; closes #189.
It's worth note that 2.7.10 shipped with Sierra, managed to not notice
this due to using a Homebrew 2.7.14.
6 years ago
Alex Willmer 1bc32adad4 Issue #160: Cache minimize_source()
Before

```
python tests/bench/local.py
0 120.245933533
1 119.300842285
2 118.355035782
3 123.839855194
```

After

```
python tests/bench/local.py
0 66.3640499115
1 65.9508705139
2 72.4799633026
3 65.7958984375
```
6 years ago
Alex Willmer dc3f5730a2 Merge branch 'master' into eye-of-the-token-its-the-thrill-of-the-light 6 years ago
David Wilson cd098ef158 issue #183: re-raise StreamError in calling context.
This allows catching just StreamError regardless of via=None or
via=<context>. Deserves a more general solution, but it's easy to fix up
later.
6 years ago
Alex Willmer 48623763d6 minimize_source: Implement reindentation 6 years ago
Alex Willmer 556ee2aec6 minimize_source: Handling indentation
In the case that string(s) are replaced, any indent or dedent tags must
be re-inserted after the replacemnts.
6 years ago
Alex Willmer a1e9b9e8db Issue #160: Reimplement minimize_source as token filters
Benefits:

- More correct than re.sub()
- Better handling of trailing whitespace
- Recognises doc-strings regardless of quoting style

Limitations:

- Still not entirely correct
  - Creates a syntax error when function/class body is only a docstring
  - Doesn't handle indented docstrings yet
- Slower by 50x - 8-10 ms vs 0.2 ms for re.sub()
  - Not much scope for improving this, tokenize is 100% pure Python
- Complex state machine, harder to understand
- Higher line count in parent.py
- Untested with Mitogen parent on Python 2.x and child on Python 2.x+y

No change

- Only requires Python stdlib modules
6 years ago
David Wilson 6670cba41c Introduce handler policy functions; closes #138.
Now you can specify a function to add_handler() that authenticates the
message header, with has_parent_authority() and is_immediate_child()
built in.
6 years ago
David Wilson 1ff27ada49 Add maximum message size checks. Closes #151. 6 years ago
David Wilson 45b81009f3 parent: call TIOCSCTTY on FreeBSD. Closes #171 6 years ago
David Wilson adf527440f issue #155: parent: split out make_call_msg(). 6 years ago
David Wilson 52d980ad58 issue #155: fork: nop out get_boot_command, it's become quite expensive
-16% reduction in fork cost.
6 years ago
David Wilson 4dc001f496 parent: fire disconnect upon receiving DEL_ROUTE for context
This lets context.shutdown(wait=True) succeed in the master or any
parent.
6 years ago
David Wilson 41ae6623c6 issue #155: parent: generic name generation
Let us override a class attribute to specify prefix from fork.py, rather
than reimplement the same logic.
6 years ago
David Wilson 1155de85af issue #155: parent: propagate context name too.
This allows context_by_id() in the master to succeed in returning a
Context with a .name matching the context's name, needed for correct
logging.

Previously this would have logged the empty string, because the master
had no mechanism to know the name of a context created by a child.
6 years ago
David Wilson cba3347556 issue #155: move connection factories to parent.py. 6 years ago
David Wilson 972f77c6b5 parent: have close_nonstandard_fds() ask OS for FD_MAX 6 years ago
David Wilson 48351a1889 issue #155: parent: support Context.shutdown(), reap children on exit.
This permits graceful shutdown of individual contexts, without tearing
down everything.

Update mitogen.parent.Stream to also wait for the child to exit, to
prevent the buildup of zombie processes. This introduces a blocking wait
for process exit on the Broker thread, let's see if we can get away with
it. Chances are reasonable that it'll cause needless hangs on heavily
loaded machines.
6 years ago
David Wilson 6a74edce6b issue #155: parent: move master.Context into parent.
The Context and Router APIs for constructing children and making
function calls should be available in every parent context, as user code
wants to have access to the same API.
6 years ago
David Wilson 1a8ac9f4d1 issue #155: introduce mitogen.fork / Router.fork() 6 years ago
David Wilson 878e7a0902 issue #155: pass reference to existing Router into Stream constructor
This is a hacky layering violation, but it seems the simplest approach
for now: fork needs access to Router, in order to recover the existing
Importer instance.
6 years ago
David Wilson 21ef540cd8 issue #155: parent: split create_socketpair() from create_child() 6 years ago
David Wilson c31a177ebe issue #155: parent: split get_main_kwargs() from get_preamble() 6 years ago
David Wilson b51365209e parent: needless duplicate ADD_ROUTE message
notice_stream() does that already.
6 years ago
David Wilson 08612d4ca2 issue #155: fix call_function_test regression
It's entirely unclear how test_aborted_on_local_context_disconnect ever
passed, but it was broken by the previous commit.
6 years ago
David Wilson 54ff1c90fa issue #155: add DEL_ROUTE, propagate ADD_ROUTE upwards
* IDs are allocated by the parent responsible for contructing a new
  child, using ALLOCATE_ID to the master as necessary to allocate new ID
  ranges.

* ADD_ROUTE is sent up the tree rather than down. This permits
  construction of the new context to complete concurrent to parent
  contexts learning about its existence. Since all streams are strictly
  ordered, it's not possible for any parent to observe messages from the
  new context prior to arrival of an ADD_ROUTE from the parent notifying
  of its existence.

  If the new context, for example, implements an Ansible async task, its
  parent can start executing that without waiting for any synchronous
  confirmation from any parent or the master.

* Since routes propagate up, it's no longer possible for a plain
  non-parent child to ever receive ADD_ROUTE, so that code can be moved
  out of core.py and into parent.py (-0.2kb compressed).

* Add a .routes attribute to parent.Stream, and respond to disconnection
  signal on the stream by propagating DEL_ROUTE for any ADD_ROUTE ever
  received from that stream.

* Centralize route management in a new parent.RouteMonitor class
6 years ago
David Wilson f4ba66e3ee issue #155: allocate child IDs in batches of 1000.
Avoids a roundtrip for every fork.
6 years ago
David Wilson f241eac5ce parent: allow Python to determine its install prefix from argv[0]
Fixes support for virtualenv. Closes #152.
6 years ago
David Wilson eba12e2ee2 issue #139: bump kernel socket buffer size to 128kb
This allows us to write 128kb at a time towards SSH, but it doesn't help
with sudo, where the ancient tty layer is always used.
6 years ago
David Wilson 587256bbce issue #141: unify connect deadline handling
Now there is a single deadline calculated by the parent.Stream
constructor, and reused for both SSH and sudo.
6 years ago
Alex Willmer f95b37429f parent: Read preamble in first stage with os.fdopen()
SSH command size: 439 (+4 bytes)
Preamble size: 8941 (no change)

This _increases_ the size of the first stage, but
- Eliminates one of the two remaining uses of `sys`
- Reads the preamble as a byte-string, no call `.encode()`
   is needed on Python 3 before calling `_()`
6 years ago
Alex Willmer a62edd0b7e parent: Use os.execl in first stage
SSH command size: 435 (-4 bytes)
Preamble size: 8962 (no change)

os.execl is the same as os.execv, but it take a variable number of
arguments instead of a single sequence.
6 years ago
Alex Willmer 545652c34f parent: Trim whitespace & e variable in first stage
SSH command size: 439 (-4 bytes)
Preamble size: 8962 (no change)
6 years ago
Alex Willmer 0336de6722 parent: Combine first stage imports
SSH command size: 443 (-5 bytes)
Preamble size: 8962
6 years ago
Alex Willmer 48949cd249 parent: Use 'zip' alias of 'zlib' decoder
SSH command size: 448 (-5 bytes)
Preamble size: 8941 (no change)

NB: The 'zip' alias was absent in Python 3.x, until Python 3.4. This
should change be reverted if Python 3.0, 3.2, or 3.3 support is
required.
6 years ago
Alex Willmer 0f82f68fee parent: Precompute preamble sizes for first stage
SSH command size: 453 (no change)
Preamble size: 8941 (-5 bytes)
6 years ago
Alex Willmer dfd7070ceb parent: reuse _=codecs.decode alias in exec'd first stage
SSH command size: 453 (-8 bytes)
Preamble size: 8946 (no change)
6 years ago
Alex Willmer 53a8c59ae5 parent: Remove redudant os.exit() in first stage
SSH command size: 461 (-8 bytes)
Preamble size: 8946 (no change)

Since python has reached the last statement this should occur anyway.
6 years ago
Alex Willmer e051cf0ea0 parent: Unroll os.close() loop in first stage
SSH command size: 469 (-11 bytes)
Preamble size: 8946 (no change)

Although the source is longer, the _compressed_ length is reduced.
6 years ago
Alex Willmer 85f36f4cb1 parent: Prefer "import foo;x=foo" in first stage
SSH command size: 481 (down 1)
Preamble size: 8946 (no change)
6 years ago
Alex Willmer f999b9adbf Crank zlib.compress() upto 9
SSH command size: 482 bytes (no change)
Preamble size: 8946 bytes (down 33)
6 years ago
David Wilson 8329bee889 parent: log discard_until() input when IOLOG is enabled
Trying to diagnose a Reddit user's problem.
6 years ago
David Wilson 37d38f8d9f importer: _is_stdlib_name() needed to handle relative paths
Was causing tons of log spam due to 'skipping absent related name'
6 years ago
David Wilson 5b0b973dba importer: quieten one more warning 6 years ago
David Wilson 0ef23d8644 parent: Add hack for OS X /usr/bin/python
It's a magical switcher that needs argv[0], which we don't provide.
6 years ago
David Wilson 7cf2edc3a8 ansible: Support many more common playbook variables. 6 years ago
David Wilson ff617824a1 ansible: fix some flake8 errors
* Unused imports
* Undefined names in helpers.py
* Copyright header wrapping
6 years ago
Alex Willmer d4a546dcbc parent: Fix ModuleForwarder not sending related packages
Found due to a LGTM warning about unused loop variable (related). As far
as I can tell the callback was sending fullname multiple times. KeyError
check added because I found NestedTest failed - mitogen.parent had
mitogen as one of it's related, and mitogen was not in the cache.

Refs #61
6 years ago
David Wilson 5036a9448f Add Docker method. 6 years ago
David Wilson fa804c7c80 parent: simplify route() call
Doesn't need to go via defer() since it's always running on the broker
thread.
6 years ago
David Wilson 8ec6ae1da0 importer: module whitelist/blacklist support
Hoped to avoid it, but it's the obvious solution for Ansible.
6 years ago
David Wilson 2848d35aff importer: warn on duplicate request, simplify preload logic
* Children should never generate a request for a module that has already
  been sent, however there are a variety of edge cases where, e.g.
  asynchronous calls are made into unloaded modules in a set of
  children, causing those children to request modules (and deps) in a
  different order, which might break deduplication. So add a warning to
  catch when this happens, so we can figure out how to handle it.
  Meanwhile it's only a warning since in the worst case, this just adds
  needless latency.

* Don't bother treating sent packages separately, there doesn't seem to
  be any need for this (after docs are updated to match how preloading
  actually works now).
6 years ago
David Wilson b158259c86 Split up parent and master modules
Knocks 4kb off network footprint for a proxy connection.
6 years ago