Hostvars in lookup for delegated task

Hi,

I wrote a lookup plugin to get some data from the already-existing ansible variables, so it needs access to “groups” and “hostvars” to find the right combination of data to return. In particular, my lookup plugin returns a server name, which I want to use in a delegated task, so I have something like the following:

`

  • name: Do something on another host
    shell: …
    delegate_to: “{{ lookup(‘my_lookup’, item) }}”
    with_items: some_list
    `

That was my first attempt, I then realized I could use my lookup in the ‘with’ clause (as “with_my_lookup”) but got the same result.

The task fails with the following trace:

`
Traceback (most recent call last):
File “/usr/bin/ansible-playbook”, line 86, in
sys.exit(cli.run())
File “/usr/lib/python2.6/site-packages/ansible/cli/playbook.py”, line 150, in run
results = pbex.run()
File “/usr/lib/python2.6/site-packages/ansible/executor/playbook_executor.py”, line 140, in run
result = self._tqm.run(play=play)
File “/usr/lib/python2.6/site-packages/ansible/executor/task_queue_manager.py”, line 238, in run
play_return = strategy.run(iterator, play_context)
File “/usr/lib/python2.6/site-packages/ansible/plugins/strategy/linear.py”, line 229, in run
task_vars = self._variable_manager.get_vars(loader=self._loader, play=iterator._play, host=host, task=task)
File “/usr/lib/python2.6/site-packages/ansible/vars/init.py”, line 341, in get_vars
all_vars[‘ansible_delegated_vars’] = self._get_delegated_vars(loader, play, task, all_vars)
File “/usr/lib/python2.6/site-packages/ansible/vars/init.py”, line 417, in _get_delegated_vars
items = lookup_loader.get(task.loop, loader=loader, templar=templar).run(terms=loop_terms, variables=vars_copy)
File “/project/ansible/lookup_plugins/my_lookup.py”, line 11, in run
if ip in variables[‘hostvars’][server][‘ansible_all_ipv4_addresses’]:
KeyError: ‘hostvars’

That looks like it is running the task while getting the variables, so I’m a little confused. I have the feeling my run() method is not properly implemented and it is causing this to fail. Any help?

`

Just to avoid confusion: I just reverted some changes and found the stack trace I pasted before comes when I use “with_my_lookup” instead of with_items. When I use with_items and do the lookup in the delegate_to line, I get a slightly different trace (not that it gives any more details, but I wanted to clarify):

Traceback (most recent call last): File "/usr/bin/ansible-playbook", line 84, in <module> sys.exit(cli.run()) File "/usr/lib/python2.6/site-packages/ansible/cli/playbook.py", line 149, in run results = pbex.run() File "/usr/lib/python2.6/site-packages/ansible/executor/playbook_executor.py", line 149, in run result = self._tqm.run(play=play) File "/usr/lib/python2.6/site-packages/ansible/executor/task_queue_manager.py", line 249, in run play_return = strategy.run(iterator, play_context) File "/usr/lib/python2.6/site-packages/ansible/plugins/strategy/linear.py", line 216, in run task_vars = self._variable_manager.get_vars(loader=self._loader, play=iterator._play, host=host, task=task) File "/usr/lib/python2.6/site-packages/ansible/vars/__init__.py", line 342, in get_vars all_vars['ansible_delegated_vars'] = self._get_delegated_vars(loader, play, task, all_vars) File "/usr/lib/python2.6/site-packages/ansible/vars/__init__.py", line 429, in _get_delegated_vars delegated_host_name = templar.template(task.delegate_to, fail_on_undefined=False) File "/usr/lib/python2.6/site-packages/ansible/template/__init__.py", line 321, in template result = self._do_template(variable, preserve_trailing_newlines=preserve_trailing_newlines, escape_backslashes=escape_backslashes, fail_on_undefined=fail_on_undefined, overrides=overrides) File "/usr/lib/python2.6/site-packages/ansible/template/__init__.py", line 473, in _do_template res = j2_concat(rf) File "<template>", line 9, in root File "/usr/lib64/python2.6/site-packages/jinja2/runtime.py", line 179, in call return __obj(*args, **kwargs) File "/usr/lib/python2.6/site-packages/ansible/template/__init__.py", line 400, in _lookup ran = instance.run(loop_terms, variables=self._available_variables, **kwargs) File "/project/ansible/lookup_plugins/my_lookup.py", line 11, in run if ip in variables['hostvars'][server]['ansible_all_ipv4_addresses']:

Hey,

Can I ask what you are trying to acheive?

I have a feeling you might not need a lookup plugin if you are just needing to get at groups and host vars in your playbooks.

You can do stuff like

"{{groups['dbservers']}}"

for example.

Hope this helps.

Jon

Hi, sure you can ask!

This is my use case:

The system I’m trying to deploy works with host aliases, for example “node1-customer1.example.com
Those aliases are bound to VIP on physical servers, e.g. “server1.example.com”. In the general case, I may have several customer hosts pointing to different VIPs on the same physical machine. The rules governing the need of host aliases or the use of VIPs instead of CNAME entries are, as the saying goes, “above my paygrade”.

It was decided when the project started that we would use the “real” server names in the Ansible inventory, with a group for each customer, and will keep the host names used by this particular customer on a configuration file
So, when I need to shut the system down for this customer, I loop over its host aliases, for each host I find the server name, and then delegate the stop process to that server name. Lacking the imagination required to come up with a better solution, what the lookup plugin does is this:

from ansible.plugins.lookup import LookupBase import socket class LookupModule(LookupBase): def run(self, terms, variables=None, **kwargs): ret_list = [] for host in terms: ip = socket.gethostbyname(host) for server in variables['groups']['all']: if ip in variables['hostvars'][server]['ansible_all_ipv4_addresses']: ret_list.append(server) break return ret_list

I’m willing to throw it away if there is a better way to handle it :slight_smile:

Regards

After a group meeting we decided to solve the problem by removing the mapping altogether, so the original problem no longer exists.
Still, should I keep in mind that “hostvars” is not accessible from lookups if the task is delegated? It seems to be on purpose, although it would be nice to know why.

Regards