Run a remote command from a template *file*

I need to run a few lines of shell on a remote system, and I find YAML more than awkward to use for this and would prefer to put this into a foo.sh.j2 file instead.

Now I could do the dance:

  • stat to test if a remote directory exists
  • create a remote temporary path if said directory does not exist
  • run the template module with foo.sh.j2 into the remote temporary path if said directory does not exist
  • run sh path/foo.sh with the command module if said directory does not exist, creating said directory
  • remove the remote temporary path if said directory did not exist

This is quite the overhead for something that ideally does get executed only once.

What I am really looking for is something like:

ansible.builtin.shell:
  cmd_from_template: foo.sh.j2
  creates: /path/to/said/directory

The foo.sh.j2 file needs to be evaluated locally, as is normal for templates; this is not a request to do that remotely.

You can use the template lookup to build a string from a template using the template lookup:

- name: run shell command from template
  ansible.builtin.shell:
    cmd: '{{ lookup("template", "foo.sh.j2") }}'
    creates: /path/to/said/directory

Please keep in mind this could be dangerous if the template is from an untrusted source, that may be a moot point if it’s stored in the same way as the playbook but if sourced elsewhere this could lead to an injection attack.

Ah, like that; yes, that should work, I’ll play with it around a bit before I check it as solution, thanks.

The template module evaluates on the control node but using inventory context of the target node, generates the result and transfers it to the remote node for storage which also lets you specify permissions and file attributes. You can then call the “shell” or “command” module as necessary to execute your generated script. It’s two tasks in this fashion, but it depends on what level of detail you want to achieve.

Regardless of which method, you still need the additional “file” module task to delete the file on the target node.

I also assume you’re using the ssh connection type for all this. If you’re using something else, then this may not apply.