Commit Graph

212 Commits (master)

Author SHA1 Message Date
David Wilson e615265ebd master: make is_stdlib_path() a free function
For Ansible module loader work.
6 years ago
David Wilson 7f1060f54a issue #186: initial version of subtree detachment. 6 years ago
David Wilson 6fb3a76e68 master: annotate LogForwarder messages.
mitogen/master.py:
    Annotate forwarded log entries with their original source, logger
    name, and message.

ansible:
    mark stderr in red with -vvv

    Tempting to make this appaer 100% of the time, but some crappy
    bashrcs may cause lots of junk to be printed.
6 years ago
David Wilson 7c88e4d013 Move _DEAD into header, autogenerate dead messages
This change blocks off 2 common scenarios where a race condition is
upgraded to a hang, when the library could internally do better.

* Since we don't know whether the receiver of a `reply_to` is expecting
  a raw or pickled message, and since in the case of a raw reply, there
  is no way to signal "dead" to the receiver, override the reply_to
  field to explicitly mark a message as dead using a special handle.

  This replaces the serialized _DEAD sentinel value with a slightly
  neater interface, in the form of the reserved IS_DEAD handle, and
  enables an important subsequent change: when a context cannot route a
  message, it can send a generic 'dead' reply back towards the message
  source, ensuring any sleeping thread is woken with ChannelError.

  The use of this field could potentially be extended later on if
  additional flags are needed, but for now this seems to suffice.

* Teach Router._invoke() to reply with a dead message when it receives a
  message for an invalid local handle.

* Teach Router._async_route() to reply with a dead message when it
  receives an unroutable message.
6 years ago
David Wilson ce6fb05d87 tests: 'fix' responder test.
Needs a complete rewrite, but this will do for now.
6 years ago
David Wilson f9eb66e76e _py_filename() must handle None too. 6 years ago
David Wilson 34a1e3337f Fix get_module_via_sys_modules when running under unit2. 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 cba3347556 issue #155: move connection factories to parent.py. 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 90791768be issue #155: core: slightly rearrange how shutdown works
This eliminates Context.on_disconnect() and instead moves its
functionality to a signal wired up by ExternalContext.main().

It leaves mitogen.master.Context is in a better condition to move into
mitogen.parent where it belongs.
6 years ago
David Wilson 1a8ac9f4d1 issue #155: introduce mitogen.fork / Router.fork() 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 469279d9ca master: refactor ThreadWatcher
In order to support a .remove() method, to prevent a minor but annoying
(log visible) memory leak while running the tests.
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 4f361be7e7 issue #144: teach Select() to close its latch
Causes all threads sleeping on the select to wake.
6 years ago
David Wilson 65df36895e issue #140: prevent duplicate watcher thread creation
When a Broker() is running with install_watcher=True, arrange for only
one watcher thread to exist for each target thread, and to reset the
mapping of watchers to targets after process fork.

This is probably the last change I want to make to the watcher feature
before deciding to rip it out, it may be more trouble than it is worth.
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 b243da087c issue #121: fix call_function_test by not raising the dead
A first small mea culpa to all my testing sins of late :)
6 years ago
David Wilson 7aca02c2c7 importer: don't include related modules that are blacklisted
Cuts down on even more spam
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 6ec349b386 importer: quieten 'cannot find source' warning, closes #110 6 years ago
David Wilson d348a826ff master: tidy up trixxy importer syntax slightly 6 years ago
David Wilson ff617824a1 ansible: fix some flake8 errors
* Unused imports
* Undefined names in helpers.py
* Copyright header wrapping
6 years ago
David Wilson 5036a9448f Add Docker method. 6 years ago
Alex Willmer 2dcab3fe06 master: Reword ModuleFinder.find_realted*() docstrings
Hopefully these are correct, and clearerabout the
behaviour/pre-conditions of these methods.
6 years ago
Alex Willmer c2405369d2 ModuleFinder: Get stdlib paths by sys.prefix, sys.real_prefix etc.
I took the liberty of renaming ModuleFinder.STDLIB_DIRS to
_STDLIB_PATHS, since it felt like an implementation detail that
shouldn't be baked into a public API and stdlib can also be imported
from e.g. a zip file.

I also changed it to a set to handle any duplicates.

Fixes #86
6 years ago
David Wilson afc8697288 core: Ensure add_handler() callbacks really receive _DEAD on shutdown 6 years ago
David Wilson 4d940f08ae importer: drop redundant prefix from pkg_present
For the 52 submodules of ansible.modules.system, this produced a 1602
byte pkg_present list. After stripping it becomes 406 bytes, and the
entire LOAD_MODULE size drops from 1988 bytes to 792 bytes (-60%).

For the 68 submodules of ansible.module_utils, 1902 bytes pkg_present
becomes 474 bytes (-75%), and LOAD_MODULE size drops from 2867 bytes to
1439 bytes (-49%).

In a simple test running Ansible's "setup" module followed by its "apt"
module, wire bytes sent drops from 140,357 to 135,531 (-3.4%).
6 years ago
David Wilson 71a6b9e32a master: Select.all() sugar 6 years ago
David Wilson b543b84e80 importer: share blacklist logic between master/parent 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 6905dc4e8d master: use queue-like Latch in Select() too. 6 years ago
David Wilson e6a107c5aa core: replace Queue with Latch
On Python 2.x, operations on pthread objects with a timeout set actually
cause internal polling. When polling fails to yield a positive result,
it quickly backs off to a 50ms loop, which results in a huge amount of
latency throughout.

Instead, give up using Queue.Queue.get(timeout=...) and replace it with
the UNIX self-pipe trick. Knocks another 45% off my.yml in the Ansible
examples directory against a local VM.

This has the potential to burn a *lot* of file descriptors, but hell,
it's not the 1940s any more, RAM is all but infinite. I can live with
that.

This gets things down to around 75ms per playbook step, still hunting
for additional sources of latency.
6 years ago
David Wilson beb16d0db6 master: helper functions to force disconnect everything 6 years ago
David Wilson 10230f62dd core: Message.reply() helper function 6 years ago
David Wilson dd088908df select: clean up API. 6 years ago
David Wilson df07e47d24 core: de-munge Message.unpickle() vs. Receiver.get(). 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 2e729e54cc importer: fix glaring bug in find_related()
Overwriting 'fullname' variable caused basically nonsensical filtering.
Result was including the module being searched in the list of
dependencies, which was causing ModuleResponder to send it early, which
was causing contexts to start importing the module before preloading of
dependencies had completed.
6 years ago
David Wilson 0dbb1ec028 importer: warn once about missing source and cache negative hit 6 years ago
David Wilson b158259c86 Split up parent and master modules
Knocks 4kb off network footprint for a proxy connection.
6 years ago
David Wilson 0f899f34ff importer: new format to signal ImportError
Previously we'd send just None in GET_MODULE reply, but now since there
is no single request-reply structure, we must include the fullname in
the LOAD_MODULE response and make all of its data fields None to
indicate the same.
6 years ago
David Wilson 07ae14f11d importer: semi-functional preloader
Doesn't yet implement the rules in the docs, but I think the doc rules
could maybe change to match this. Needs lots of cleanup work and
thorough testing, but this is a great start.
6 years ago
David Wilson 4d01dc3ba6 Initial pass at module preloading
* Don't implement the rules for when preloading occurs yet
* Don't attempt to streamily preload modules downstream while this
  context hasn't yet received the final module. There is quite
  significant latency buried in here, but for now it's a lot of work to
  fix.

This works well enough to handle at least the mitogen package, but it's
likely broken for anything bigger.
6 years ago
David Wilson b75e77b410 master: force set_block() in tty_create_child too.
For gevent, just as in 5f7633cd56
6 years ago
David Wilson ed71ae72f8 master: make mitogen minimally functional under gevent
It seems gevent automatically sets blocking behaviour on fds produced by
the socket module, which causes the Python process we fork to fail
horribly. So in the child, always reset the blocking flag.
6 years ago
David Wilson 247f50e08d master: add comment 6 years ago
David Wilson bbcfc585a8 master: add a comment to explain what's going on, and fix log msg.
Closes #70
6 years ago
David Wilson 3cbe9baf6d issue #70: remove redundant 'raise SystemExit'
Either execvp succeeds, in which case the process image is replaced, or
execvp throws an exception, in which case control flow exits the frame
anyway.
6 years ago
David Wilson 326886832e Add license text everywhere. 6 years ago
David Wilson f1f36cec35 Simplify the API, make Broker optional and auto-shutdown on main thread exit. 6 years ago
David Wilson c09dcd82a7 Fix Python 3 fix :/ closes #57 6 years ago
David Wilson b3491b190c master: Lazy-format more logging arguments, minor 3.x compat increments 6 years ago
Alex Willmer 0e7cc55e33 first stage: Remove/dedent else block
Since the above if block ends in a call to os.execv() this block will
only ever run when the if condition was false. Hence putting it in an
else clause is unnecessary.
6 years ago
Alex Willmer d1c10f64a5 first stage: Use string concatenation 6 years ago
Alex Willmer b490cde604 first stage: eliminate whitespace 6 years ago
Alex Willmer c7c0266e99 first stage: single letter variables 6 years ago
David Wilson 3d0e8c36d2 issue #49: 2.x/3.x compatible decode.
Much uglier command line, but it works across major Python releases.
6 years ago
David Wilson db9bec8720 Implement Alex's awesome idea of zlibbing the first stage too! Closes #49 6 years ago
David Wilson 828f60351b importer: Delete _get_module_via_parent entirely
Can't figure out what it's supposed to do any more, and can't find a
version of Ansible before August 2016 (when I wrote that code) that
seems to need it.

Add some more mitigations to avoid sending dylibs.
6 years ago
David Wilson b7a9aa46cf core: More robust shutdown
Now there is a separate SHUTDOWN message that relies only on being
received by the broker thread, the main thread can be hung horribly and
the process will still eventually receive a SIGTERM.
6 years ago
David Wilson 690ee6dbe2 Fix select_test failure, remove crap old timing_test. 6 years ago
David Wilson 15bf0f54e2 Beginnings of module_finder_test 6 years ago
David Wilson 9b13a4cc61 Fix 2 call_function_test failures. 6 years ago
David Wilson 79dd00db5a master: hack to avoid executing __main__. 6 years ago
David Wilson 6f5d4882da We don't support sets, so don't use them in module loader(!) 6 years ago
David Wilson ecd39e4f2a add missing IOLOG, fixes _iter_read/SshTest. 6 years ago
David Wilson 451fb347d0 master: include related modules in ModuleResponder response 6 years ago
David Wilson 4af920094a iter_read: also treat 0-byte read as disconnection 6 years ago
David Wilson d169b55d64 select: fix typo 6 years ago
David Wilson af6812b458 Fix context naming for sudo and via=. 6 years ago
David Wilson f1d82c7284 More API documentation. 6 years ago
David Wilson b7f95e558f Better document Router API and constructors. 6 years ago
David Wilson 849ccebe04 receiver: only permit one notify callback
There is no point spamming a list for every function call, there is no
use case where multiple notify callbacks would be useful.
6 years ago
David Wilson 1be10575a1 importer: Don't respond to non-.py[co] imports. 6 years ago
David Wilson f869e088f8 issue #20: tests and fixes for mitogen.master.Select(). 6 years ago
David Wilson e3d967ebeb issue #20: initial implementation of mitogen.master.Select(). 6 years ago
David Wilson 14783c75e8 issue #9: log warning when a cross-sibling CALL_FUNCTION occurs
First step to making it a fatal error.
6 years ago
David Wilson 4de321a3b0 Adjust get_boot_command to match _first_stage change
inspect module includes the staticmethod decorator added by
a8d1dc6730
6 years ago
David Wilson c810f66bcc issue #19: whoops, implement sliding window properly 6 years ago
David Wilson 43ccbf0459 issue #19: second attempt at import scanner
This version is based on the modulefinder standard library module,
pruned back just to handle modules we know have been loaded already, and
to scan module-level imports only, rather than imports occurring in
class and function scope (crappy heuristic, but assume they are lazy
imports).

The ast and compiler modules were far too slow, whereas this version can
bytecode compile and scan all the imports for django.db.models (58
modules) in around 200ms.. 3.4ms per dependency, it's probably not going
to get much faster than that.
6 years ago
David Wilson 175abee2c9 Fix inverted logic. 6 years ago
David Wilson 8054fa867a Only import compiler when necessary, it's not available in 3.x. 6 years ago
Alex Willmer aa817f1b83 Handle failure to import the ast module 6 years ago
Alex Willmer 1f955fc655 Declare self-less method as static
Found using pylint
6 years ago
Alex Willmer 36754254b2 Add missing imports: ast, compiler
Found using pylint
6 years ago
David Wilson eb060e1a0e Document Router.profiling. 6 years ago
David Wilson 9c4bf37cfc Remove final vestiges of context.key. 6 years ago
David Wilson 05cc74d142 core: Support profiling 6 years ago
David Wilson 04ea5306e9 Document a bunch of mitogen.master and move more docstrings into Sphinx. 6 years ago
David Wilson b2f13f1fa4 master: propagate routes for IDs allocated via ALLOCATE_ID
needed for inter-child rsync.
6 years ago
David Wilson a9387b0504 core: remove pointless eval() of ARGV0 environment variable. 6 years ago
David Wilson 1411790f56 master: make write_all() handle O_NONBLOCK and deadlines. 6 years ago
David Wilson 2ee7309378 master: send_await() always unpickles now. 6 years ago
David Wilson db225638f0 core: Make iter_read() handle deadline (and non-blocking IO) properly 6 years ago
David Wilson 7a60b20dc6 core: Generalize/duplicate the call/send_await code using Receiver. 6 years ago
David Wilson 76d35df889 master: use decorators rather than call_with_deadline(with_context=..) 6 years ago
David Wilson 2a365aa9b0 Replace `with_context` parameter with mitogen.core.takes_econtext decorator 6 years ago
David Wilson c67119501b Keep allocate_id() in the enhanced router class. 6 years ago
David Wilson 02a37d2339 Fix format string. 6 years ago
David Wilson 4720eb1c55 core: add ALLOCATE_ID message for fakessh. 6 years ago
David Wilson 78d5575d4e Fix proxy connection: pickling changes broke it. 6 years ago
David Wilson 76e476dcfa Tidy up logging of command lines for easier cutpaste. 6 years ago
David Wilson e66590f098 Initial version of ModuleFinder, but it's slooooow. 6 years ago
David Wilson 53467d394d Log forwarded events just as the docs suggest they're logged. 6 years ago
David Wilson dc446f9042 ssh: Learn to type passwords and supply pubkeys.
Now ssh requires a tty allocation. This presents a scalability problem,
a future version could selectively allocate a tty only if typing
passwords is desired.

Sudo's tty handling is now moved into mitogen.master.
6 years ago
David Wilson be9e55fe8c pickle: support Context(), use same unpickler everywhere.
* Support passing Context() objects in function calls and return values.
  Now the fakessh demo from the documentation index would work
  correctly.

* Since slaves can communicate with each other now, they should also use
  the same approach to unpickling as the master already used. Collapse
  away all the unpickle extension crap and hard-wire just the 3 types
  that support unpickling.
6 years ago
David Wilson 11acc031a9 pickle: Prevent access to the _Dead and CallError constructors
This should be pretty much identical the same behaviour as before, but
the extra assertion makes me feel happier.
6 years ago
David Wilson e75f1d8579 Add call_function_test, fix various exception bugs. 6 years ago
David Wilson e7ff6259a3 Initial commit. 6 years ago