Commit Graph

421 Commits

Author SHA1 Message Date
David Wilson 70a735f23a ansible: tidy up service.py docstrings. 2018-04-09 03:00:31 +01:00
David Wilson 79b75aabae ansilbe: remove unused class variables 2018-04-09 02:37:17 +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 71057c78f9 ansible: rename helpers.py to target.py, to reflect its purpose 2018-04-08 19:34:03 +01:00
David Wilson 7fd88868a6 ansible: raise AnsibleConnectionFailure on connection failure; closes #183
Before:

    $ ANSIBLE_STRATEGY=mitogen ansible -i derp, derp -m setup
    An exception occurred during task execution. To see the full traceback, use -vvv. The error was:     (''.join(bits)[-300:],)
    derp | FAILED! => {
        "msg": "Unexpected failure during module execution.",
        "stdout": ""
    }

After:

    $ ANSIBLE_STRATEGY=mitogen ansible -i derp, derp -m setup
    derp | UNREACHABLE! => {
        "changed": false,
        "msg": "EOF on stream; last 300 bytes received: 'ssh: Could not resolve hostname derp: nodename nor servname provided, or not known\\r\\n'",
        "unreachable": true
    }
2018-04-05 20:14:14 +01:00
David Wilson 4a823c7a27 issue #164: missing cast() for _remote_file_exists(). 2018-04-05 19:35:03 +01:00
David Wilson d503956493 ansible: Remove duplicate casts already done in Connection 2018-04-05 02:55:27 +01:00
David Wilson 6aeb4e9f05 issue #164: precisely emulate Ansible's stdio behaviour.
* Use identical logic to select when stdout/stderr are merged, so
  'stdout', 'stdout_lines', 'stderr', 'stderr_lines' contain the same
  output before/after the extension.

* When stdout/stderr are merged, synthesize carriage returns just like
  the TTY layer.

* Mimic the SSH connection multiplexing message on stderr. Not really
  for user code, but so compare_output_test.sh needs fewer fixups.
2018-04-05 01:16:34 +01:00
David Wilson 26cc0f2724 issue #164: fix remote_tmp handling on <2.5 2018-04-04 20:19:46 +01:00
David Wilson e0381606af Ensure remote_tmp is respected everywhere.
Logic is still somewhat different from Ansible: we don't have to care
about sudo/non-sudo cases, etc.
2018-04-04 14:05:57 +01:00
David Wilson 0e648dbd53 ansible: tidy up planner.py. 2018-04-02 11:35:39 +01:00
David Wilson a731be32a2 ansible: use _ansible_shell_executable in ScriptRunner.
Now we match Ansible error output and exit status. Ansible:

    $ ansible localhost -e end=2 -m custom_binary_single_null
    localhost | FAILED! => {
        "changed": false,
        "module_stderr": "Shared connection to localhost closed.\r\n",
        "module_stdout": "/bin/sh: /Users/dmw/.ansible/tmp/ansible-tmp-1522661797.42-158833651208060/custom_binary_single_null: cannot execute binary file\r\n",
        "msg": "MODULE FAILURE",
        "rc": 126
    }

Mitogen now:

    localhost | FAILED! => {
        "changed": false,
        "module_stderr": "/bin/sh: /var/folders/gw/f6w3dgy16fsg5y4kdthbqycw0000gn/T/ansible_mitogenAYF8LM-binary: cannot execute binary file\n",
        "module_stdout": "",
        "msg": "MODULE FAILURE",
        "rc": 126
    }

Previously:

    localhost | FAILED! => {
        "changed": false,
        "module_stderr": "<type 'exceptions.OSError'>: [Errno 8] Exec format error",
        "module_stdout": "",
        "msg": "MODULE FAILURE",
        "rc": 1
    }
2018-04-02 10:37:23 +01:00
David Wilson 293567e9d5 ansible: fix low_level_execute_command regression. 2018-04-02 08:24:17 +00:00
David Wilson fe9bf1d81d ansible: match Ansible behaviour when script lacks interpreter line. 2018-04-02 08:08:14 +00:00
David Wilson 1fab6d9c25 ansible: permit execve() of temporary files on Linux. 2018-04-02 08:59:36 +01:00
David Wilson 047458a8b3 "examples": start adding structure to regression tests. 2018-04-02 08:12:39 +01:00
David Wilson 380ef7376d ansible: Add support for free strategy. 2018-04-02 00:01:28 +01:00
David Wilson 470d8399a3 ansible: document planner.Planner. 2018-04-01 22:31:45 +01:00
David Wilson 822502125d issue #106: 2.3.x compatible get_shebang-alike. 2018-04-01 22:04:05 +01:00
David Wilson e5723e4f5f ansible: fix _make_tmp_path() regression on 2.3.x.
Due to issue #177.
2018-04-01 21:59:59 +01:00
David Wilson a5e4a6f346 issue #106: move helpers.get_bytecode() into NewStyleRunner 2018-04-01 21:40:06 +01:00
David Wilson a98a51a328 issue #106: handle JSONARGS modules too. 2018-04-01 21:20:58 +01:00
David Wilson 8cc20856a8 issue #106: support custom new-style modules + 'reexec by default'
Rather than assume any structure about the Python code:

* Delete the exit_json/fail_json monkeypatches.
* Patch SystemExit rather than a magic monkeypatch-thrown exception
* Setup fake cStringIO stdin, stdout, stderr and return those along with
  SystemExit exit status
* Setup _ANSIBLE_ARGS as we used to, since we still want to override
  that with '{}' to prevent accidental import hangs, but also provide
  the same string via sys.stdin.
* Compile the module bytecode once and re-execute it for every
  invocation. May change this back again later, once some benchmarks are
  done.
* Remove the fixups stuff for now, it's handled by ^ above.

Should support any "somewhat new style" Python module, including those
that just give up and dump stuff to stdout directly.
2018-04-01 21:10:04 +01:00
David Wilson a954d54644 issue #106: support old-style too. 2018-04-01 19:01:18 +01:00
David Wilson 16b64392e2 issue #106: support WANT_JSON modules. 2018-04-01 18:19:34 +01:00
David Wilson df6daaf3c4 issue #106: working/semantically compatible binary support. 2018-04-01 16:39:10 +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 1a040cf5c0 issue #106: get FileService working. 2018-04-01 16:39:10 +01:00
David Wilson 6aac37e157 issue #106: allow any context to contact FileService.
Also fix privilege check for register command.
2018-04-01 16:39:10 +01:00
David Wilson 8fffb34752 issue #106: helpers.get_file(), command logging.
* Add helpers.get_file() that calls back up into FileService as
  necessary. This is a stopgap measure.

* Add logging to exec_args() to simplify debugging of binary runners.
2018-04-01 16:39:10 +01:00
David Wilson dbaca05ac8 issue #106: Runner module docstring 2018-04-01 16:39:10 +01:00
David Wilson 43e4f5009a issue #106: remove 2 needless Invocation attributes. 2018-04-01 16:39:10 +01:00
David Wilson 2470f486e1 issue 106: ansible: make the context name available
For use later to track/deduplicate streaming uploads to targets.
2018-04-01 16:39:10 +01:00
David Wilson c891ab078a issue #106: working old-style native module execution
Still abusing Python import mechanism, but one big step closer to
eliminating that.
2018-04-01 16:39:10 +01:00
David Wilson 34a37a0ba5 issue #106: ansible: rename and significant pad out runners.py
Aiming to have working NativeRunner and BinaryRunner to begin with.
2018-04-01 16:39:10 +01:00
David Wilson 98c15942f7 issue #177: fix bizarre syntax error in last commit. 2018-04-01 16:38:22 +01:00
David Wilson cf25437019 issue #177: populate Shell.tempdir global on creating a tempdir.
It looks a lot like multiple calls to _make_tmp_path() will result in
multiple temporary directories on the remote machine, only the last of
which will be cleaned up.

We must be bug-for-bug compatible for now, so ignore the problem in the
meantime.
2018-04-01 15:58:44 +01:00
David Wilson 6eed3aa1fa issue #177: fetch and cache HOME value during connection setup.
This ensures only 1 roundtrip is required for every invocation of
_remote_expand_user().
2018-04-01 15:57:46 +01:00
David Wilson 3dc90b7618 issue #106: import skeletal planner module. 2018-03-30 16:06:23 +05:45
David Wilson 28cd17cf56 issue #106: import skeletal new executor. 2018-03-30 15:55:38 +05:45
David Wilson 9067a7b173 ansible: Move setLevel() bits together. 2018-03-30 14:42:54 +05:45
Wesley Moore 3d5bbb9a63 Use become_pass for sudo password 2018-03-30 13:00:43 +11:00
David Wilson 36e1ae15fd issue #172: prevent 'No handlers..' error being printed. 2018-03-30 01:10:30 +05:45
David Wilson e0c4d6b348 ansible: Quick fix for #172. 2018-03-30 00:13:22 +05:45
David Wilson 1ff27ada49 Add maximum message size checks. Closes #151. 2018-03-29 18:54:55 +05:45
David Wilson d6f49a003b issue #106: ansible: beginnings of FileService. 2018-03-29 13:52:19 +05:45
David Wilson cd1683b924 ansible: split environment editing into a separate class. 2018-03-27 15:03:46 +05:45
David Wilson 198bec3320 issue #168: ansible: Mitogen must also ignore the extra arguments. 2018-03-26 11:51:19 +05:45
David Wilson 26051caf4c ansible: Pass through connection loader kwargs; closes #168 2018-03-26 11:44:37 +05:45
David Wilson 749eddac71 ansible: fix flake8 errors in helpers.py. 2018-03-26 11:43:06 +05:45
David Wilson 3e384db7c2 service: add basic security policy types. 2018-03-25 13:52:07 +05:45
David Wilson 1777b8f42e ansible: use DeduplicatingService for ContextService; closes #162. 2018-03-23 09:30:41 +05:45
David Wilson 9e514240a1 issue #156: always enable microsecond logging 2018-03-20 09:12:38 +05:45
David Wilson 4d96d0c1af issue #156: fix duplicate -vvvv logging 2018-03-19 23:48:08 +05:45
David Wilson c183f06dfb issue #152: respect the Ansible-selected interpreter for local connections too. 2018-03-19 21:58:35 +05:45
David Wilson 89b0faae2f Workaround for global state in yum_repository module; closes #154. 2018-03-19 21:58:35 +05:45
David Wilson 4d8ccab2ca ansible: docstring fixes 2018-03-19 21:58:35 +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 7a394dc73e ansible: allow establishment of duplicate SSH connections 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 4691ce0b95 issue #150: ansible: add basic Docker support. 2018-03-19 21:58:34 +05:45
David Wilson cd455e8c58 ansible: minor tidy up 2018-03-19 21:58:34 +05:45
David Wilson 3584084be6 issue #140: explicit Broker management, and guard against crap plug-ins.
Implement Connection.__del__, which is almost certainly going to trigger
more bugs down the line, because the state of the Connection instance is
not guranteed during __del__. Meanwhile, it is temporarily needed for
deployed-today Ansibles that have a buggy synchronize action that does
not call Connection.close().

A better approach to this would be to virtualize the guts of Connection,
and move its management to one central place where we can guarantee
resource destruction happens reliably, but that may entail another
Ansible monkey-patch to give us such a reliable hook.
2018-03-19 21:58:34 +05:45
David Wilson 88c198ea05 issue #141: copy Ansible's connect_timeout for sudo too. 2018-03-19 21:58:34 +05:45
Alex Willmer 1c20c61605 docs: Convert all URLs that support https://
Excluded: graphml XML namespaces, links to e.g. Fabric homepage

Fixes #128
2018-03-19 21:58:33 +05:45
David Wilson 7d12154a92 ansible: fix formatting 2018-03-19 21:58:33 +05:45
David Wilson 12c6e574fb ansible: disable host key checking for now
Need a better story (perhaps a callback function?) for handling this.
2018-03-19 21:58:33 +05:45
David Wilson 037bed895b issue #110: _transfer_data() must handle dicts and Unicode(!) 2018-03-19 21:58:33 +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
David Wilson d34025fae9 ansible: _transfer_data() must return remote_path.
Fixes DebOps bug.
2018-03-19 21:58:33 +05:45
David Wilson a9db27d424 ansible: instrument every ActionMixin override. 2018-03-19 21:58:33 +05:45
David Wilson 9b7991cd45 issue #118: log exceptions for emulated commands, fix AttributeError in helpers.py
Turns out Ansible can't be trusted to actually check the result
dictionary everywhere it expects one, so put the real exception text
into -vvv output too.
2018-03-19 21:58:33 +05:45
David Wilson 59dab72e29 ansible: log ansible_mitogen.* to -v too. 2018-03-19 21:58:33 +05:45
David Wilson 6bd4c5ead5 docs: Ansible logging update (#111) 2018-03-19 21:58:33 +05:45
David Wilson 016d47aa91 Log and track PIDs everywhere for Ansible. 2018-03-19 21:58:33 +05:45
David Wilson b63af1de85 ansible: implement _transfer_data for <2.4 template action 2018-03-19 21:58:33 +05:45
David Wilson 7ab1af043e ansible: redirect logging into display 'framework'. closes #111 2018-03-19 21:58:32 +05:45
David Wilson b527628b17 issue #109: do exactly what Ansible does
Could it be that some empty dict magically gets populated from somewhere
invisible?
2018-03-19 21:58:32 +05:45
David Wilson 485e489aa2 ansible: correct sys.path fixup. 2018-03-19 21:58:32 +05:45
David Wilson 3ddbf1a503 ansible: basic support for ssh_args 2018-03-19 21:58:32 +05:45
David Wilson da00437f1e ansible: Support ansible_ssh_private_key_file 2018-03-19 21:58:32 +05:45
David Wilson a87b665099 ansible: limited support for become_flags, more docs. 2018-03-19 21:58:32 +05:45
David Wilson e0382ab2db ansible: teach ActionModule to disappear for non-Mitogen Connections
Closes #103.
2018-03-19 21:58:32 +05:45
David Wilson bde6f888a0 ansible: restructure package to avoid yet more madness
Ansible's PluginLoader makes up bullshit when it imports a module
(mostly because it has to make up something), therefore we ended up with
duplicate copies of ansible_mitogen loaded: one under
ansible.plugins.*.mitogen, and one under the canonical namespace.

Which broke isinstance().
2018-03-19 21:58:32 +05:45
David Wilson 734fb75203 ansible: mixins.py docstrings. 2018-03-19 21:58:32 +05:45
David Wilson 7080751f13 ansible: support environment: too. 2018-03-19 21:58:32 +05:45
David Wilson 7cf2edc3a8 ansible: Support many more common playbook variables. 2018-03-19 21:58:32 +05:45
David Wilson eca7805cba ansible: one more cast() call.
Need a more general solution to littering the code with this crap.
2018-03-19 21:58:31 +05:45
David Wilson 3183dd4147 ansible: initial support for async jobs
Running in a thread to begin with, but this must change.
2018-03-19 21:58:31 +05:45
David Wilson f6d87faf37 tests: import ansible_helpers_test. 2018-03-19 21:58:31 +05:45
David Wilson 207159cf1a ansible: fix bug in apply_mode_spec(). 2018-03-19 21:58:31 +05:45
David Wilson ff617824a1 ansible: fix some flake8 errors
* Unused imports
* Undefined names in helpers.py
* Copyright header wrapping
2018-03-19 21:58:31 +05:45
David Wilson 76e739a0ba ansible: inverted sense of execute paramter 2018-03-19 21:58:31 +05:45
David Wilson 1b090a6c0a ansible: fix become:true with sudo:true 2018-03-19 21:58:31 +05:45
David Wilson 83f2862431 ansible: _remote_chmod() / _fixup_perms2() can be called sometimes.
It's used at least by the copy module, even though the result is still
mostly a no-op. _remote_chmod() doesn't accept octal mode, it accepts
symbolic mode. So implement a symbolic parser in helpers.py.
2018-03-19 21:58:31 +05:45
David Wilson f3315fc172 ansible: better emulate _low_level_execute_command()
Still needs a ton of work to emulate argument handling, shell selection,
and output emulation in every case. Unsurprisingly, Ansible documents
none of this.
2018-03-19 21:58:31 +05:45
David Wilson cccfebec74 ansible: correct temp file cleanup for template action. 2018-03-19 21:58:30 +05:45
David Wilson 5dc2cc0726 ansible: don't enable_debug_logging() for sudo 2018-03-19 21:58:30 +05:45
David Wilson b221eaaa10 ansible: log call timings 2018-03-19 21:58:30 +05:45
David Wilson 1e9fd63343 ansible: Ansible 2.4 compatibility. 2018-03-19 21:58:30 +05:45
David Wilson 03221ee9ab ansible: gracefully shut down the service thread at exit. 2018-03-19 21:58:30 +05:45
David Wilson 91116810a1 ansible: delete utils.py and promote cast() to mitogen.utils 2018-03-19 21:58:30 +05:45
David Wilson a075cc0242 ansible: document Strategy's implementation 2018-03-19 21:58:30 +05:45
David Wilson 18eaf14dca ansible: migrate logging variables into utils. 2018-03-19 21:58:30 +05:45
David Wilson 5d8cb0f5fb ansible: document the connection class. 2018-03-19 21:58:30 +05:45
David Wilson b7f563a6f0 ansible: remove old action subdirectory. 2018-03-19 21:58:30 +05:45
David Wilson 5f45c2d49a ansible: clean up, structure and document strategy module. 2018-03-19 21:58:30 +05:45
David Wilson 84e9d42e71 ansible: handle local connections and synchronize module too. 2018-03-19 21:58:29 +05:45
David Wilson 74468abf0a ansible: fix syntax error 2018-03-19 21:58:29 +05:45
David Wilson 6e7bb4fd13 ansible: support local connections too 2018-03-19 21:58:29 +05:45
David Wilson 57894b18e0 ansible: support class_only=True in wrapped loader 2018-03-19 21:58:29 +05:45
David Wilson 54a3777ff3 ansible: blacklist everything except our own namespaces
Farewell, pointless roundtrips, we hardly knew ye.
2018-03-19 21:58:29 +05:45
David Wilson 331f77ee2b ansible: generalized action module wrapping. 2018-03-19 21:58:29 +05:45
David Wilson d13ab9a022 ansible: remove hard-wired UNIX socket path. 2018-03-19 21:58:29 +05:45
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.
2018-03-19 21:58:29 +05:45
David Wilson 6059e0c1db ansible: support become:True and become_user 2018-03-19 21:58:29 +05:45
David Wilson ed09076bdd ansible: automatically configure connection plug-in. 2018-03-19 21:58:29 +05:45
David Wilson a35fcf44cc ansible: restructure to avoid intermediate imports 2018-03-19 21:58:29 +05:45