Commit Graph

29 Commits

Author SHA1 Message Date
David Wilson e647adc62e ansible: copy GIL change from linear2 branch.
Reduces runtime by 25% given 100 25ms SSH targets:

    ANSIBLE_STRATEGY=mitogen \
    MITOGEN_POOL_SIZE=100 \
    /usr/bin/time -l ansible k3-x100 -m shell -a hostname

Before:
           39.56 real        35.29 user        17.24 sys
      59600896  maximum resident set size
       1784252  page reclaims
          9016  messages sent
         10382  messages received
         18774  voluntary context switches
        770070  involuntary context switches

After:
           29.79 real        22.10 user        11.77 sys
      59281408  maximum resident set size
       1725268  page reclaims
          8582  messages sent
          9959  messages received
         14582  voluntary context switches
         75280  involuntary context switches
2018-09-08 20:53:11 +01:00
David Wilson 2647f73501 ansible: bump UNIX listener default backlog, and set it to match forks.
The connection multiplexer can expect to not be scheduled at least until
every $forks worker processes has attempted a connection, so the backlog
must be able to hold every worker.
2018-09-08 20:53:11 +01:00
David Wilson 8ab11f415f ansible: better support for diagnosing hangs
* Always enable the faulthandler module in the top-level process if it
  is available.
* Make MITOGEN_DUMP_THREAD_STACKS interval configurable, to better
  handle larger runs.
* Add docs subsection on diagnosing hangs.

Conflicts:
	ansible_mitogen/process.py
2018-09-08 20:53:11 +01:00
David Wilson e18396d54d ansible: enable profiling by default!
Thankfully this never made it into a release
2018-08-20 12:48:52 +01:00
David Wilson 9e572a7939 ansible: fix duplicate MuxProcess socket write.
The while: loop was necessary due to some cutpaste further on down the
file.
2018-08-18 16:43:59 +01:00
David Wilson 053c594d65 ansible: prevent logs spamming user console on exit.
Closes #331.
2018-08-18 16:43:59 +01:00
David Wilson 5c573f7fcb ansible: insert short sleep when MITOGEN_PROFILING active.
Hacky, but works fine.
2018-07-31 23:27:36 -07:00
David Wilson d8e0c9e12c issue #297: local commands must execute with WorkerProcess environment. 2018-07-10 18:42:09 +01:00
David Wilson 410016ff47 Initial Python 3.x port work.
* ansible: use unicode_literals everywhere since it only needs to be
  compatible back to 2.6.
* compat/collections.py: delete this entirely and rip out the parts of
  functools that require it.
* Introduce serializable Kwargs dict subclass that translates keys to
  Unicode on instantiation.
* enable_debug_logging() must set _v/_vv globals.
* cStringIO does not exist in 3.x.
* Treat IOLogger and LogForwarder input as latin-1.
* Avoid ResourceWarnings in first stage by explicitly closing fps.
* Fix preamble_size.py syntax errors.
2018-07-07 14:55:47 +01:00
David Wilson 6377f2d69c issue #257: split pool shutdown and join. 2018-06-10 04:34:44 +01:00
David Wilson d33ef1866e ansible: wrap socket calls in io_op()
Breaks under signal stress test.
2018-06-10 03:06:18 +00:00
David Wilson e35694acd5 ansible: flake8 fixes. 2018-06-10 01:22:46 +01:00
David Wilson caffaa79f7 issue #186: rework async/forked tasks again.
The controller must know the ID of the forked child in order to
propagate dependencies to it, so forking+starting the module run cannot
happen entirely on the target, without some additional mechanism to
wait-and-repropagate the deps as they arrive on the target.

Rework things so that init_child() also handles starting the fork parent,
and returns it along with the context's home directory in a single round
trip.

Now master knows the identity of the fork parent, it can directly create
fork children and call run_module_async() in them. This necessitates 2
roundtrips to start an asynchronous task.

This whole thing sucks and entirely needs simplified, but for now things
almost work, so keeping it.

connection.py:
  * Expect ContextService to return the entire dict return value of
    init_child(). Store the fork_contxt from the return value.

planner.py:
  * Rework Planner to store the invocation as an instance attribute, to
    simplify method calls.
  * Add Planner.get_push_files() and Planner.get_module_deps().
  * Add _propagate_deps() which takes a Planner and ensures the deps it
    describes are sent to a (non forked or forked) context.
  * Move async task logic out of target.py and into invoke() /
    _invoke_*().

process.py:
  * Services no longer need references to each other. planner.py handles
    sending module deps with one extra RPC.

services.py:
  * Return "init_child_result" key instead of simple "home_dir" key.
  * Get rid of dep propagation from ModuleDepService, it lives in
    planner.py now.

target.py:
  * Get rid of async task start logic, lives in planner.py now.
2018-06-09 22:11:26 +01:00
David Wilson 569c12a2d6 ansible: use PushFileService for module deps.
planner.py:
  * Rather than grant FileService access to a file for children, use
    PushFileService to trigger deduplicating send of the file through
    the hierarchy immediately.
  * Send the complete list of Ansible module imports to the target so
    runner.py knows which files and scripts must be loaded via
    PushFileService prior to detaching.

runner.py:
  * Teach NewStyleRunner to use the full module map to block until
    everything is loaded prior to detach().

target.py:
  * Delete old _get_file(), replace get_file() with get_small_file()
    which uses PushFileService instead.

Closes #186
2018-06-07 16:48:42 +01:00
David Wilson daa9cfd0a8 ansible: MITOGEN_DUMP_THREAD_STACKS for mux process too 2018-05-29 18:10:08 +01:00
David Wilson d9087c510b ansible: move FileService into mitogen.service. 2018-05-29 17:07:58 +01:00
David Wilson 30034877a5 issue #217: ansible: working, if extremely inefficient implementation 2018-05-13 01:47:11 +01:00
David Wilson 81b62d9a1a issue #217: ansible: beginnings of ModuleDepService. 2018-05-12 15:12:39 +01:00
David Wilson 6edb3f165d ansible: avoid a race during shutdown. 2018-04-28 22:08:35 +01:00
David Wilson 85e1f5f515 ansible: remove JobResultService, more compatible async jobs; closes #191.
And by "compatible" I mean "terrible". This does not implement async job
timeouts, but I'm not going to bother, upstream async implementation is
so buggy and inconsistent it resists even having its behaviour captured
in tests.
2018-04-20 17:02:48 +01:00
David Wilson 3613162bc0 ansible: enable forking when requested and for async jobs.
Closes #105.
References #155.

mitogen/service.py:
    Refactor services to support individually exposed methods with
    different security policies for each method.

    - @mitogen.service.expose() to expose a method and set its policy
    - @mitogen.service.arg_spec() to validate input.
    - Require basic service message format to be a tuple of
      `(method, kwargs)`, where kwargs is always a dict.
    - Update DeduplicatingService to match the new scheme.

ansible_mitogen/connection.py:
    - Rename 'method' to 'method_name' to disambiguate it from the
      service.call()'s method= argument.

ansible_mitogen/planner.py:
    - Generate an ID for every job, sync or not, and fetch job results
      from JobResultService rather than via the initiating function
      call's return value.
    - Planner subclasses now get to select whether their Runner should
      run in a forked process. The base implementation requests this if
      the 'mitogen_isolation_mode=fork' task variable is present.

ansible_mitogen/runner.py:
    Teach runners to deliver their result via JobResultService executing
    in their indirect parent mux process.

ansible_mitogen/plugins/actions/mitogen_async_status.py:
    Split the implementation up into methods, and more compatibly
    emulate Ansible's existing output.

ansible_mitogen/process.py:
    Mux processes now host JobResultService.

ansible_mitogen/services.py:
    Update existing services to the new mitogen.service scheme, and
    implement JobResultService:

    * listen() method for synchronous jobs. planner.invoke() registers a
      Sender with the service prior to invoking the job, then sleeps
      waiting for the service to write the job result to the
      corresponding Receiver.

    * Non-blocking get() method for implementing mitogen_async_status
      action.

    * Child-accessible push() method for delivering task results.

ansible_mitogen/target.py:
    New helpers for spawning a virginal subprocess on startup, from
    which asynchronous and mitogen_task_isolation=fork jobs are forked.
    Necessary to avoid a task inheriting potentially
    polluted/monkey-patched parent environment, since remaining jobs
    continue to run in the original child process.

docs/ansible.rst:
    Add/merge/remove some behaviours/risks.

tests/ansible/integration:
    New tests for forking/async.
2018-04-09 00:03:09 +01:00
David Wilson 0dd5e04eae issue #106: partially working BinaryRunner/Planner.
Refactor planner.py to look a lot more like runner.py. This 'structural
cutpaste' looks messy -- probably we can simplify this code, even though
it's pretty simple already.
2018-04-01 16:39:10 +01:00
David Wilson 1ff27ada49 Add maximum message size checks. Closes #151. 2018-03-29 18:54:55 +05:45
David Wilson dec3af375a issue #144: ansible: increase default pool size to 16. 2018-03-19 21:58:35 +05:45
David Wilson 19632473dc issue #144: ansible: use service.Pool with default size=1. 2018-03-19 21:58:35 +05:45
David Wilson 858b01e78b issue #150: add docstrings. 2018-03-19 21:58:35 +05:45
David Wilson 6940b23013 issue #150: ansible: mark worker/child sock as CLOEXEC. 2018-03-19 21:58:35 +05:45
David Wilson 86ede62241 issue #150: introduce separate connection multiplexer process
This is a work in progress.
2018-03-19 21:58:35 +05:45
David Wilson e36c1763bd issue #110: split process state out of strategy state
The strategy is reconstructed for every playbook that is included or
specified on the command line, therefore we can't store the global
Router there without losing all our SSH connections across playbooks.
2018-03-19 21:58:33 +05:45