issue #106: ansible: rename and significant pad out runners.py

Aiming to have working NativeRunner and BinaryRunner to begin with.
pull/193/head
David Wilson 6 years ago
parent 98c15942f7
commit 34a37a0ba5

@ -31,7 +31,7 @@ import json
import os
import tempfile
import ansible_mitogen.helpers
import ansible_mitogen.helpers # TODO: circular import
try:
from shlex import quote as shlex_quote
@ -43,23 +43,6 @@ import ansible.module_utils.basic
ansible.module_utils.basic._ANSIBLE_ARGS = '{}'
class Exit(Exception):
"""
Raised when a module exits with success.
"""
def __init__(self, dct):
self.dct = dct
class ModuleError(Exception):
"""
Raised when a module voluntarily indicates failure via .fail_json().
"""
def __init__(self, msg, dct):
Exception.__init__(self, msg)
self.dct = dct
class TemporaryEnvironment(object):
def __init__(self, env=None):
self.original = os.environ.copy()
@ -71,44 +54,41 @@ class TemporaryEnvironment(object):
os.environ.update(self.original)
class MethodOverrides(object):
@staticmethod
def exit_json(self, **kwargs):
"""
Replace AnsibleModule.exit_json() with something that doesn't try to
kill the process or JSON-encode the result dictionary. Instead, cause
Exit to be raised, with a `dct` attribute containing the successful
result dictionary.
"""
self.add_path_info(kwargs)
kwargs.setdefault('changed', False)
class NativeModuleExit(Exception):
"""
Capture the result of a call to `.exit_json()` or `.fail_json()` by a
native Ansible module.
"""
def __init__(self, ansible_module, **kwargs):
ansible_module.add_path_info(kwargs)
kwargs.setdefault('invocation', {
'module_args': self.params
'module_args': ansible_module.params
})
kwargs = ansible.module_utils.basic.remove_values(
ansible_module.do_cleanup_files()
self.dct = ansible.module_utils.basic.remove_values(
kwargs,
self.no_log_values,
)
self.do_cleanup_files()
raise Exit(kwargs)
class NativeMethodOverrides(object):
@staticmethod
def exit_json(self, **kwargs):
"""
Raise exit_json() output as the `.dct` attribute of a
:class:`NativeModuleExit` exception`.
"""
kwargs.setdefault('changed', False)
return NativeModuleExit(self, **kwargs)
@staticmethod
def fail_json(self, **kwargs):
"""
Replace AnsibleModule.fail_json() with something that raises
ModuleError, which includes a `dct` attribute.
Raise fail_json() output as the `.dct` attribute of a
:class:`NativeModuleExit` exception`.
"""
self.add_path_info(kwargs)
kwargs.setdefault('failed', True)
kwargs.setdefault('invocation', {
'module_args': self.params
})
kwargs = ansible.module_utils.basic.remove_values(
kwargs,
self.no_log_values,
)
self.do_cleanup_files()
raise ModuleError(kwargs.get('msg'), kwargs)
return NativeModuleExit(self, **kwargs)
klass = ansible.module_utils.basic.AnsibleModule
@ -119,14 +99,16 @@ class MethodOverrides(object):
self.klass.fail_json = self.fail_json
def revert(self):
"""
Restore prior state.
"""
self.klass.exit_json = self._original_exit_json
self.klass.fail_json = self._original_fail_json
class ModuleArguments(object):
class NativeModuleArguments(object):
"""
Patch the ansible.module_utils.basic global arguments variable on
construction, and revert the changes on call to :meth:`revert`.
Patch ansible.module_utils.basic argument globals.
"""
def __init__(self, args):
self.original = ansible.module_utils.basic._ANSIBLE_ARGS
@ -135,29 +117,44 @@ class ModuleArguments(object):
})
def revert(self):
"""
Restore prior state.
"""
ansible.module_utils.basic._ANSIBLE_ARGS = self._original_args
class Runner(object):
def __init__(self, module, raw_params=None, args=None, env=None,
runner_params=None):
"""
Ansible module runner. After instantiation (with kwargs supplied by the
corresponding Planner), `.run()` is invoked, upon which `setup()`,
`_run()`, and `revert()` are invoked, with the return value of `_run()`
returned by `run()`.
Subclasses may override `_run`()` and extend `setup()` and `revert()`.
"""
def __init__(self, module, raw_params=None, args=None, env=None):
if args is None:
args = {}
if raw_params is not None:
args['_raw_params'] = raw_params
if runner_params is None:
runner_params = {}
self.module = module
self.raw_params = raw_params
self.args = args
self.env = env
self.runner_params = runner_params
def setup(self):
"""
Prepare the current process for running a module. The base
implementation simply prepares the environment.
"""
self._env = TemporaryEnvironment(self.env)
def revert(self):
"""
Revert any changes made to the process after running a module. The base
implementation simply restores the original environment.
"""
self._env.revert()
def _run(self):
@ -169,6 +166,9 @@ class Runner(object):
module. This monkey-patches the Ansible libraries in various places to
prevent it from trying to kill the process on completion, and to
prevent it from reading sys.stdin.
:returns:
Module result dictionary.
"""
self.setup()
try:
@ -177,37 +177,53 @@ class Runner(object):
self.revert()
class PythonRunner(object):
class NativeRunner(object):
"""
Execute a new-style Ansible module, where Module Replacer-related tricks
aren't required.
"""
def setup(self):
super(PythonRunner, self).setup()
self._overrides = MethodOverrides()
self._args = ModuleArguments(self.args)
super(NativeRunner, self).setup()
self._overrides = NativeMethodOverrides()
self._args = NativeModuleArguments(self.args)
def revert(self):
super(PythonRunner, self).revert()
super(NativeRunner, self).revert()
self._args.revert()
self._overrides.revert()
def module_fixups(mod):
"""
Apply fixups for known problems with mainline Ansible modules.
"""
if mod.__name__ == 'ansible.modules.packaging.os.yum_repository':
# https://github.com/dw/mitogen/issues/154
mod.YumRepo.repofile = mod.configparser.RawConfigParser()
def _run(self):
try:
mod = __import__(self.module, {}, {}, [''])
self.module_fixups(mod)
# Ansible modules begin execution on import. Thus the above
# __import__ will cause either Exit or ModuleError to be raised. If
# we reach the line below, the module did not execute and must
# already have been imported for a previous invocation, so we need
# to invoke main explicitly.
mod.main()
except (Exit, ModuleError), e:
return json.dumps(e.dct)
except NativeModuleExit, e:
return e.dct
assert False, "Module returned no result."
return {
'failed': True,
'msg': 'ansible_mitogen: module did not exit normally.'
}
class BinaryRunner(object):
def __init__(self, path, **kwargs):
super(BinaryRunner, self).__init__(**kwargs)
self.path = path
def setup(self):
super(BinaryRunner, self).setup()
self._setup_binary()
@ -261,9 +277,12 @@ class BinaryRunner(object):
super(BinaryRunner, self).revert()
def _run(self):
rc, stdout, stderr = ansible_mitogen.helpers.exec_args(
args=[self.bin_fp.name, self.args_fp.name],
)
try:
rc, stdout, stderr = ansible_mitogen.helpers.exec_args(
args=[self.bin_fp.name, self.args_fp.name],
)
except Exception, e:
return
# ...
assert 0
Loading…
Cancel
Save