I am trying to implement the following scenario in Ansible (v1.9.1):
- Ansible connects to remote host and uses
su
to becomeroot
. - Ansible host fetches remote configuration file that it is about to clobber.
- Ansible host stores adds the just-fetched file to a Git repository that contains the destination directory using
git add ...
. - Ansible host commits the just-fetched file using
git commit ...
and an appropriate commit message.
Now, (1) is fully supported since v1.9.0.1 and (2) is made very easy with the fetch module – by default it even stores the files under a host-specific sub-directory.
However, I have not been able to figure out (3) and (4). Ideally, I would like Ansible to just execute a local command as the user that started it in the first place. I could create a wrapper shell script to do that, but that seems quite contrary to the Ansible way of doing things.
Most posts on the Internet suggest using the local_action
module. local_action
, however, seems to be completely overkill for my purpose – it tries to access the host with proper privilege escalation. As a result it fails:
fatal: [host00 -> 127.0.0.1] => Internal Error: this module does not support running commands via su
This is what my handler looks like currently:
- name: stage-archive-file
become: false
su: false
local_action: command git -C {{ playbook_dir }} add storage/archive
notify: commit-archive-file
local_action
seems to completely ignore my attempts to make it not use su
, although I am not sure if this is something related to this specific module or to the su
method in general.
Is there a simpler way to just execute a command from the ansible process? Alternatively, is it possible to somehow get local_action
to work?
There seems to be a related Ansible issue that may be preventing local_action
from working correctly in this case. Apparently local_action
and delegate_to
retain some connection settings from the "parent" task, even if those are completely invalid for the delegated host.
Best Answer
While I expect that the root cause of this problem will be fixed in a future Ansible version, I rolled out my own solution. Basically I modified/hacked a stripped-down connection plugin for Ansible that simply executes a command on the host. The process was as follows:
In the playbook directory create a subdirectory named
connection_plugins
.Copy the
local.py
connection plugin from the Ansible installation (e.g./usr/lib/python2.7/site-packages/ansible/runner/connection_plugins/local.py
) to the newly created subdirectory with a different name such asexecute.py
.Edit
connection_plugins/execute.py
and remove the code sections that relate to the privilege escalation methods.Add an entry for
localhost
in the inventory file with the parameteransible_connection=execute
.The last step would need to be modified if
local_action
should indeed use a privilege escalation method for some tasks. In that case it is possible to leave the entry forlocalhost
(if any) unmodified, define another alias with theexecute
connection type and then usedelegate_to:
instead oflocal_action:
in the task definitions.