Linux – Executing commands on the Ansible host from a handler

ansiblelinux

I am trying to implement the following scenario in Ansible (v1.9.1):

  1. Ansible connects to remote host and uses su to become root.
  2. Ansible host fetches remote configuration file that it is about to clobber.
  3. Ansible host stores adds the just-fetched file to a Git repository that contains the destination directory using git add ....
  4. 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 as execute.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 parameter ansible_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 for localhost (if any) unmodified, define another alias with the execute connection type and then use delegate_to: instead of local_action: in the task definitions.