Commit 7cf2edc3 authored by David Wilson's avatar David Wilson

ansible: Support many more common playbook variables.

parent eca7805c
......@@ -65,16 +65,44 @@ class Connection(ansible.plugins.connection.ConnectionBase):
#: hard-codes 'local' and 'ssh' as the only allowable connection types.
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):
assert 'MITOGEN_LISTENER_PATH' in os.environ, (
'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.transport = original_transport
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
def connected(self):
return self.router is not None
......@@ -102,8 +130,9 @@ class Connection(ansible.plugins.connection.ConnectionBase):
'username': self._play_context.remote_user,
'password': self._play_context.password,
'port': self._play_context.port,
'python_path': '/usr/bin/python',
'python_path': self.python_path,
'ssh_path': self._play_context.ssh_executable,
'connect_timeout': self.connect_timeout,
})
)
......@@ -120,7 +149,8 @@ class Connection(ansible.plugins.connection.ConnectionBase):
'method': 'sudo',
'username': self._play_context.become_user,
'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,
}))
......
......@@ -68,6 +68,14 @@ def get_command_module_name(module_name):
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):
return self._connection.call(func, *args, **kwargs)
......
......@@ -194,8 +194,7 @@ class StrategyModule(ansible.plugins.strategy.linear.StrategyModule):
"""
def _setup_master(self):
"""
Construct a Router, Broker, mitogen.unix listener thread, and thread
serving connection requests from worker processes.
Construct a Router, Broker, and mitogen.unix listener
"""
self.router = mitogen.master.Router()
self.router.responder.whitelist_prefix('ansible')
......@@ -205,7 +204,8 @@ class StrategyModule(ansible.plugins.strategy.linear.StrategyModule):
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_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)
finally:
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
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
~~~~~~~~~~~
* 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.
* 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.
* remote_addr
* remote_user
* ssh_port
* ssh_path
* ansible_python_interpreter
* ansible_ssh_timeout
* ansible_host, ansible_ssh_host
* ansible_user, ansible_ssh_user
* ansible_port, ssh_port
* ansible_ssh_executable, ssh_executable
* password (default: assume passwordless)
Sudo Variables
--------------
* username (default: root)
* password (default: assume passwordless)
* ansible_python_interpreter
* 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
......
......@@ -503,7 +503,7 @@ Router Class
**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
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
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:
If ``True``, arrange for profiling (:py:data:`profiling`) to be
enabled in the new context. Automatically ``True`` when
......
......@@ -269,6 +269,9 @@ class Stream(mitogen.core.Stream):
#: The path to the remote Python interpreter.
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.
debug = False
......@@ -280,13 +283,14 @@ class Stream(mitogen.core.Stream):
self.sent_modules = set(['mitogen', 'mitogen.core'])
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
it does not exist."""
super(Stream, self).construct(**kwargs)
if python_path:
self.python_path = python_path
if connect_timeout:
self.connect_timeout = connect_timeout
if remote_name is None:
remote_name = '%s@%s:%d'
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)
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()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment