ansible / ansible-runner

A tool and python library that helps when interfacing with Ansible directly or as part of another system whether that be through a container image interface, as a standalone tool, or as a Python module that can be imported. The goal is to provide a stable and consistent interface abstraction to Ansible.
Other
954 stars 352 forks source link

How do i specify extravars to be read from a file when running ad-hoc with `.run()`? #1240

Closed nautics889 closed 1 year ago

nautics889 commented 1 year ago

Ansible provides feature when extra variables can be loaded from file. So, let's suppose, i have some_file.yaml and i want to display variable from the file using shell module. That's going to be something like this:

(venv) nautics@DESKTOP-09RDHU4:~/workspace/ansible_sandbox$ ansible localhost -m ansible.builtin.shell -e "@some_file.yaml" -a 'echo "{{ foobar }}"'
[WARNING]: No inventory was parsed, only implicit localhost is available
localhost | CHANGED | rc=0 >>
test variable

How can i make exactly the same in a context of Python?

I tried to make something like below passing "@some_file.yaml" as an extravars, but it's failing:

>>> ansible_runner.run(host_pattern='localhost', module='ansible.builtin.shell', module_args="echo '{{ foobar }}'", extravars='@some_file.yaml')
[WARNING]: No inventory was parsed, only implicit localhost is available
usage: ansible [-h] [--version] [-v] [-b] [--become-method BECOME_METHOD]
...
Some actions do not make sense in Ad-Hoc (include, meta, etc)
ERROR! Invalid extra vars data supplied. '@/tmp/tmp7j7lw95h/env/extravars' could not be made into a dictionary
<ansible_runner.runner.Runner object at 0x7f6344dee980>

According to the log, runner tries to read data from some temporary file: /tmp/tmp7j7lw95h/env/extravars. Is this correct behavior?

Futhermore, according to docstring of .run() method the argument extravars can be dict and only dict instance.


I've found there was a similar issue (https://github.com/ansible/ansible-runner/issues/303) and related PR was merged long time ago, but i'm still not following how would i set extra variables to be read from a file. I've also tried to use full path like extravars="/full/path/to/some_file.yaml" — same.


WAIDW?

muety commented 1 year ago

Passing a full file path (like /tmp/some_file.yml) as the extravars argument worked for me.

But the implementation of this is super weird. Instead of directly passing that string as a process argument, the file path is written to env/extravars (now containing a plain string instead of YAML data) and then read from there. I also tried using the cmdline argument, but even there, a env/cmdline file is created.

There seems to be no way to not do a filesystem round trip, which is super annoying, because it seems inefficient and could cause race conditions when trying to run multiple Ansible processes in parallel.


Futhermore, according to docstring of .run() method the argument extravars can be dict and only dict instance.

Yep, docs are wrong here. Got confused by this as well.

nautics889 commented 1 year ago

@muety thank you and apologies for late reply.

The option with full path worked for me as well.

I guess the issue can be closed for now, perharps it should be mentioned somewhen if somebody wants to refactor current implemention of handling of extravars.