Accessing the host names in the ansible_hosts file in a loop in Ansbile ?

I’m trying to automate zookeeper install using Ansible. I want to add a bunch of lines to my cfg file. Following is an example where there are 5 nodes. zoo1, zoo2, zoo3 etc the hosts that I’ve in my ansible_hosts file.

I want to implement it out with with_items but cannot figure it out. Any idea how to access the host name in the ansible_hosts file in a loop ?

PS : Cross posting here for better coverage. http://stackoverflow.com/questions/24249492/accessing-the-host-names-in-the-ansible-hosts-file-in-a-loop-in-ansbile

initLimit=5
syncLimit=2
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
server.4=zoo4:2888:3888
server.5=zoo5:2888:3888

Say you put your zookeeper nodes in a group ‘zookeeper’, you can access/loop them with

with_items: groups[‘zookeeper’]

where {{ item }} will get the hostname as defined in your inventory

HTH,

Serge

Great ! thanks.
Now what if I want to put a different value 1,2,3 … to a file /tmp/zookeeper/myid ?

The my id file already exists but I want to an auto increment number which is different for each machine?

Thanks.

​sounds like nesting lookup plugins​; anible suppport for that is limited
though
have a look at with_nested

This is what I’ve and it work. It’s not clean though. I’m sure there is a better way. Because this work for 4 servers but won’t work for a N without me changing the line - [“1”,“2”,“3”,“4”]

  • name: Add server.number=hostname:2888:3888 the server configuration to config file zoo.cfg

lineinfile: dest={{zk_root_dir}}/zookeeper-3.4.6/conf/zoo.cfg line=“server.{{ item.0}}={{ item.1 }}:2888:3888”

with_together:

  • [“1”,“2”,“3”,“4”] #FIXME - this is a hack that needs to be fixed later

  • groups[‘zookeeper’]

Now I’ve another problem.

If I want to write the server id to myid file then it writes it 4 times.

  • name: Add server.number=hostname:2888:3888 the server configuration to config file zoo.cfg

lineinfile: dest={{zk_root_dir}}/zookeeper-3.4.6/conf/zoo.cfg line=“server.{{ item.0}}={{ item.1 }}:2888:3888”

lineinfile: dest={{zk_tmp_dir}}/myid line=“{{ item.0}}”

with_together:

  • [“1”,“2”,“3”,“4”] #FIXME - this is a hack that needs to be fixed later

  • groups[‘zookeeper’]

In my /tmp/myid file I get

1

2

3

4

but I want to have 1 in host1:myid, 2 in host2:myid, 3 in host3:myid and 4 in host4:myid

Any ideas ?

Separate your tasks keeping the same loop construct for both tasks and at the second task (the one that creates ‘/tmp/myid’) add a conditional to run it only on the host of the current loop iteration: As you can see, I have replaced your hack for the id list with another hack, so that your id list is dynamically expanded as you add more hosts in the ‘zookeeper’ group. If you don’ t like hacks, there is a better way to handle this. Just add a ‘server_id’ host variable for each host, and then your tasks would be like this:

Error. in the second example, ‘with_together’ should be ‘with_items’.

Stupid me… If you use a ‘server_id’ variable you do not need to loop for the second task. Just do:

Jinja2 has a special variable called “loop.index” that it seems you can use here, and then it’s just the template module.

Keep it simple and don’t put extra logic in your playbook.

BTW, accessing the loop index works only in the template module. It does not work in ansible’s loops with lookup plugins. This is an inconsistency. It should be possible in both cases. That, as well as back referencing to the iterators in nested loops are things that come natural to people trying to construct loops, but, unfortunately, are not available. Well, in that particular case, using a “server_id” inventory variable as I suggested is as simple as using “loop.index” and even better, because you can remove, add or reorder hosts in the group without causing a change to the server id of each host.

" It should be possible in both cases."

No, it shouldn’t. Ansible play books don’t use Jinja2 for loops - nor should Jinja2 be used in Ansible for logic.

In this case, the user needs to produce a configuration file, so using a template is exactly what is needed.

Your server_id solution is suboptimal and requires manual maintaince of that file when it could be automatically generated.

You say “do not” and “should not” in a quite generalized manner, but you don’t give any reason. In contrast, I give specific reasons for this: consistency in available variables between loops in templates and “with_" loops, as well as adding more possibilities for the "with_” loops. As you are expanding your deployments to more use cases (especially in the clustering domain) you will eventually need to construct task loops that allow you to do such basic things as accessing the loop index and back referencing to iterators. Templates will not always help you do what you want if that is to run task loops. Of course, you can always come up with hachish, time consuming, “return to bash/python/whatever” techniques, using one template task to create an one-time script that actually does the loop you want, a second task that runs that script and a third task that removes that script. All this could be avoided by just giving a little more power on “with_*” loops. I agree. Deployments should be data-driven (one of Ansible’s basic principles and yours of course) with direct mapping between your data and the desirable setup. Changing server ids in an ad-hoc manner through an indirect manipulation of a list of hosts could be highly dangerous in clustering/distributed environments (e.g. could lead to split brains, lost quorum or other unpredictable inconsistencies). I would not recommend that…

" As you are expanding your deployments to more use cases (especially in the clustering domain) you will eventually need to construct task loops that allow you to do such basic things as accessing the loop index and back referencing to iterators"

This is also a general statement without a reason, FWIW.

This is very much a niche use case. Not really interested.

I have already given reasons and specific examples. Maybe you have not read my other posts carefully. I have also made a patch with a commit message that analyzes the case with “with_nested”. You rejected that on the grounds that it seemed ‘too complex’ to you. I opened a discussion at ansible-dev where I proved that this “too complex” argument was in fact incorrect: the syntax to access the iterators is already there and used by all ‘with_nested’ tasks at the end of the nested loop. You have not participated in that discussion… The general pattern for accessing loop iterators at any time is this: Run a task loop on a specific host, iterating over data structures for each host in a group of hosts. If you cannot understand that definition, there are clear examples, as I said, that will help you understand. Moreover, at least 3 other users (beside me) have openly said that they tried the obvious (access the iterators before the end of the nested loop) and came to ask about this in this list: - - - Let’ s see the facts about my solution: - Does it allow to construct task loops over complex data that cannot be done otherwise? Yes. - Have other people tried to make such loops and failed? Yes - Has anyone suggested a better solution for that usage pattern? No - Does it introduce a new syntax to judge it as ‘too complex’ ? No - Does it introduce a new variable to judge it as ‘too complex’ ? No - Does it need implementation? No, there is a PR for it already. - Are people forced to use it or know about it? No

“Maybe you have not read my other posts carefully.”

“You have not participated in that discussion…”

I am increasingly tired of the pointed tone in these posts.

Consider this a warning.