ansible: Support many more common playbook variables.

wip-fakessh-exit-status
David Wilson 7 years ago
parent eca7805cba
commit 7cf2edc3a8

@ -65,16 +65,44 @@ class Connection(ansible.plugins.connection.ConnectionBase):
#: hard-codes 'local' and 'ssh' as the only allowable connection types. #: hard-codes 'local' and 'ssh' as the only allowable connection types.
transport = None transport = None
#: Set to 'ansible_python_interpreter' by on_action_run().
python_path = None
#: Set to 'ansible_sudo_exe' by on_action_run().
sudo_path = None
#: Set to 'ansible_ssh_timeout' by on_action_run().
connect_timeout = None
def __init__(self, play_context, new_stdin, original_transport): def __init__(self, play_context, new_stdin, original_transport):
assert 'MITOGEN_LISTENER_PATH' in os.environ, ( assert 'MITOGEN_LISTENER_PATH' in os.environ, (
'The "mitogen" connection plug-in may only be instantiated ' 'The "mitogen" connection plug-in may only be instantiated '
'by the "mitogen" strategy plugin.' 'by the "mitogen" strategy plug-in.'
) )
self.original_transport = original_transport self.original_transport = original_transport
self.transport = original_transport self.transport = original_transport
super(Connection, self).__init__(play_context, new_stdin) super(Connection, self).__init__(play_context, new_stdin)
def on_action_run(self, task_vars):
"""
Invoked by ActionModuleMixin to indicate a new task is about to start
executing. We use the opportunity to grab relevant bits from the
task-specific data.
"""
self.connect_timeout = task_vars.get(
'ansible_ssh_timeout',
None
)
self.python_path = task_vars.get(
'ansible_python_interpreter',
'/usr/bin/python'
)
self.sudo_path = task_vars.get(
'ansible_sudo_exe',
'sudo'
)
@property @property
def connected(self): def connected(self):
return self.router is not None return self.router is not None
@ -102,8 +130,9 @@ class Connection(ansible.plugins.connection.ConnectionBase):
'username': self._play_context.remote_user, 'username': self._play_context.remote_user,
'password': self._play_context.password, 'password': self._play_context.password,
'port': self._play_context.port, 'port': self._play_context.port,
'python_path': '/usr/bin/python', 'python_path': self.python_path,
'ssh_path': self._play_context.ssh_executable, 'ssh_path': self._play_context.ssh_executable,
'connect_timeout': self.connect_timeout,
}) })
) )
@ -120,7 +149,8 @@ class Connection(ansible.plugins.connection.ConnectionBase):
'method': 'sudo', 'method': 'sudo',
'username': self._play_context.become_user, 'username': self._play_context.become_user,
'password': self._play_context.password, 'password': self._play_context.password,
'python_path': python_path or '/usr/bin/python', 'python_path': python_path or self.python_path,
'sudo_path': self.sudo_path,
'via': via, 'via': via,
})) }))

@ -68,6 +68,14 @@ def get_command_module_name(module_name):
class ActionModuleMixin(ansible.plugins.action.ActionBase): class ActionModuleMixin(ansible.plugins.action.ActionBase):
def run(self, tmp=None, task_vars=None):
"""
Override run() to notify the Connection of task-specific data, so it
has a chance to know e.g. the Python interpreter in use.
"""
self._connection.on_action_run(task_vars)
return super(ActionModuleMixin, self).run(tmp, task_vars)
def call(self, func, *args, **kwargs): def call(self, func, *args, **kwargs):
return self._connection.call(func, *args, **kwargs) return self._connection.call(func, *args, **kwargs)

@ -194,8 +194,7 @@ class StrategyModule(ansible.plugins.strategy.linear.StrategyModule):
""" """
def _setup_master(self): def _setup_master(self):
""" """
Construct a Router, Broker, mitogen.unix listener thread, and thread Construct a Router, Broker, and mitogen.unix listener
serving connection requests from worker processes.
""" """
self.router = mitogen.master.Router() self.router = mitogen.master.Router()
self.router.responder.whitelist_prefix('ansible') self.router.responder.whitelist_prefix('ansible')
@ -205,7 +204,8 @@ class StrategyModule(ansible.plugins.strategy.linear.StrategyModule):
def _setup_services(self): def _setup_services(self):
""" """
Construct a ContextService and a thread to service requests for it. Construct a ContextService and a thread to service requests for it
arriving from worker processes.
""" """
self.service = ContextService(self.router) self.service = ContextService(self.router)
self.service_thread = threading.Thread(target=self.service.run) self.service_thread = threading.Thread(target=self.service.run)
@ -262,4 +262,3 @@ class StrategyModule(ansible.plugins.strategy.linear.StrategyModule):
return self._run_with_master(iterator, play_context, result) return self._run_with_master(iterator, play_context, result)
finally: finally:
self._remove_wrappers() self._remove_wrappers()
self._setup_master()

@ -77,13 +77,14 @@ High Risk
file, the host machine could easily exhaust available RAM. This will be fixed file, the host machine could easily exhaust available RAM. This will be fixed
soon as it's likely to be tickled by common playbook use cases. soon as it's likely to be tickled by common playbook use cases.
* Situations may exist where the playbook's execution conditions are not
respected, however ``delegate_to``, ``connection: local``, ``become``,
``become_user``, and ``local_action`` have all been tested.
Medium Risk Medium Risk
~~~~~~~~~~~ ~~~~~~~~~~~
* The remote interpreter is temporarily hard-wired to ``/usr/bin/python``,
matching Ansible's default. The ``ansible_python_interpreter`` variable is
ignored.
* In some cases ``remote_tmp`` may not be respected. * In some cases ``remote_tmp`` may not be respected.
* Interaction with modules employing special action plugins is minimally * Interaction with modules employing special action plugins is minimally
@ -194,18 +195,26 @@ SSH Variables
This list will grow as more missing pieces are discovered. This list will grow as more missing pieces are discovered.
* remote_addr * ansible_python_interpreter
* remote_user * ansible_ssh_timeout
* ssh_port * ansible_host, ansible_ssh_host
* ssh_path * ansible_user, ansible_ssh_user
* ansible_port, ssh_port
* ansible_ssh_executable, ssh_executable
* password (default: assume passwordless) * password (default: assume passwordless)
Sudo Variables Sudo Variables
-------------- --------------
* username (default: root) * ansible_python_interpreter
* password (default: assume passwordless) * ansible_sudo_exe, ansible_become_exe
* ansible_sudo_user, ansible_become_user (default: root)
* ansible_sudo_pass, ansible_become_pass (default: assume passwordless)
Unsupported:
* sudo_flags
Debugging Debugging

@ -503,7 +503,7 @@ Router Class
**Context Factories** **Context Factories**
.. method:: local (remote_name=None, python_path=None, debug=False, profiling=False, via=None) .. method:: local (remote_name=None, python_path=None, debug=False, connect_timeout=None, profiling=False, via=None)
Arrange for a context to be constructed on the local machine, as an Arrange for a context to be constructed on the local machine, as an
immediate subprocess of the current process. The associated stream immediate subprocess of the current process. The associated stream
@ -525,6 +525,10 @@ Router Class
:py:meth:`enable_debug` has been called, but may be used :py:meth:`enable_debug` has been called, but may be used
selectively otherwise. selectively otherwise.
:param float connect_timeout:
Fractional seconds to wait for the subprocess to indicate it is
healthy. Defaults to 30 seconds.
:param bool profiling: :param bool profiling:
If ``True``, arrange for profiling (:py:data:`profiling`) to be If ``True``, arrange for profiling (:py:data:`profiling`) to be
enabled in the new context. Automatically ``True`` when enabled in the new context. Automatically ``True`` when

@ -269,6 +269,9 @@ class Stream(mitogen.core.Stream):
#: The path to the remote Python interpreter. #: The path to the remote Python interpreter.
python_path = 'python2.7' python_path = 'python2.7'
#: Maximum time to wait for a connection attempt.
connect_timeout = 30.0
#: True to cause context to write verbose /tmp/mitogen.<pid>.log. #: True to cause context to write verbose /tmp/mitogen.<pid>.log.
debug = False debug = False
@ -280,13 +283,14 @@ class Stream(mitogen.core.Stream):
self.sent_modules = set(['mitogen', 'mitogen.core']) self.sent_modules = set(['mitogen', 'mitogen.core'])
def construct(self, remote_name=None, python_path=None, debug=False, def construct(self, remote_name=None, python_path=None, debug=False,
profiling=False, **kwargs): connect_timeout=None, profiling=False, **kwargs):
"""Get the named context running on the local machine, creating it if """Get the named context running on the local machine, creating it if
it does not exist.""" it does not exist."""
super(Stream, self).construct(**kwargs) super(Stream, self).construct(**kwargs)
if python_path: if python_path:
self.python_path = python_path self.python_path = python_path
if connect_timeout:
self.connect_timeout = connect_timeout
if remote_name is None: if remote_name is None:
remote_name = '%s@%s:%d' remote_name = '%s@%s:%d'
remote_name %= (getpass.getuser(), socket.gethostname(), os.getpid()) remote_name %= (getpass.getuser(), socket.gethostname(), os.getpid())
@ -381,7 +385,8 @@ class Stream(mitogen.core.Stream):
discard_until(self.receive_side.fd, 'EC1\n', time.time() + 10.0) discard_until(self.receive_side.fd, 'EC1\n', time.time() + 10.0)
def _connect_bootstrap(self): def _connect_bootstrap(self):
discard_until(self.receive_side.fd, 'EC0\n', time.time() + 10.0) deadline = time.time() + self.connect_timeout
discard_until(self.receive_side.fd, 'EC0\n', deadline)
self._ec0_received() self._ec0_received()

Loading…
Cancel
Save