Reputation: 395
I'm developing custom Ansible module to control Vagrant controlled multiple VM nodes on multiple VM servers following guide https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_general.html. As far as I understand, Ansible iterates over all specified target hosts and executes run_module
on them, allowing to module.run_command
on each host.
But I need to know on which host I am executing current command. I can add remote_host={{ inventory_hostname }}
to MODULE_ARGS
(-a
option of ansible
) and then access it as module.params['remote_host']
but it is not very convenient. Is there other way to get hostname directly from Ansible module Python code?
Upvotes: 4
Views: 3314
Reputation: 395
Investigated the issue, searched in Internet, docs (it is really not very good if you are extending Ansible and not just using) and Ansible source code and found answer by myself.
Exactly from module - it is impossible. Modules are executed on remote hosts and have no access to such information. But to perform this plugins could be used, action plugins to be precise. Basic info about them is available at https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html.
Action plugins are like wrappers to modules execution and in contrast to them are executed on control host, not on remote ones.
For example such demo plugin will append some info about execution environment to my custom vagrant
module output (but in this example module does not matter, it could be any, we are discussing only execution environment info):
#!/usr/bin/python3
from ansible.plugins.action import ActionBase
class ActionModule(ActionBase):
def run(self, tmp=None, task_vars=None):
super(ActionModule, self).run(tmp, task_vars)
module_args = self._task.args.copy()
module_return = self._execute_module(module_name='vagrant',
module_args=module_args,
task_vars=task_vars,
tmp=tmp)
module_return['ansible_facts']['inventory_file'] = str(task_vars['inventory_file'])
module_return['ansible_facts']['inventory_hostname'] = str(task_vars['inventory_hostname'])
module_return['ansible_facts']['groups'] = str(task_vars['groups'])
return module_return
This is demo code, here desired info is just printed. If it is needed to use it in module then module_args
should be updated before _execute_module
call.
If you use Ansible command ansible 192.168.3.2 -m vagrant -a '...' -u vbox --ask-pass -i hosts
(-a
arguments are specific to my custom module, does not matter to question and omitted) output will be as follows:
192.168.3.2 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python",
"groups": "{'all': ['192.168.3.1', '192.168.3.2', '192.168.3.3', '192.168.3.5', '192.168.3.6', '192.168.3.7', '192.168.3.11', '192.168.3.12', '192.168.3.21', '192.168.3.22', '192.168.3.23', '192.168.3.24', '192.168.3.31', '192.168.3.32', '192.168.3.33', '192.168.3.34', '192.168.3.35', '192.168.3.36', '192.168.3.37', '192.168.3.38', '192.168.3.39', '192.168.3.30', '192.168.3.51', '192.168.3.52', '192.168.3.61', '192.168.3.62', '192.168.3.71', '192.168.3.72'], 'ungrouped': [], 'ci_vm_servers': ['192.168.3.1', '192.168.3.2', '192.168.3.3', '192.168.3.5', '192.168.3.6', '192.168.3.7'], 'ci_vm_nodes': ['192.168.3.11', '192.168.3.12', '192.168.3.21', '192.168.3.22', '192.168.3.23', '192.168.3.24', '192.168.3.31', '192.168.3.32', '192.168.3.33', '192.168.3.34', '192.168.3.35', '192.168.3.36', '192.168.3.37', '192.168.3.38', '192.168.3.39', '192.168.3.30', '192.168.3.51', '192.168.3.52', '192.168.3.61', '192.168.3.62', '192.168.3.71', '192.168.3.72']}",
"inventory_file": "/home/dvinokurov/work/Avigdor-ansible/tools/ansible/hosts",
"inventory_hostname": "192.168.3.2"
},
"changed": true,
"command": "up",
"message": "OK",
"node_index": "2",
"original_message": "Execute \"up\"",
"remote_host": "192.168.3.2"
}
Most important here are inventory_file
, inventory_hostname
(exactly for what question was) and groups
, they are exactly those execution environment info that we passed in plugin code. groups
dictionary for example is just parsed inventory file info, I've got exactly two groups there (ci_vm_servers
and ci_vm_nodes
) and two groups are created by Ansible and are special (all
and ungrouped
).
Notice - Ansible should be aware of paths both to your custom modules and plugins. For that I used environment variable ANSIBLE_LIBRARY
for my modules and ANSIBLE_ACTION_PLUGINS
for my action plugins.
Upvotes: 4