Ansible: get list of hosts in comma separated value - ansible

I have the following loop in a template:
{% for host in groups['dbnodes'] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
the issue is that it gives the output in list of ip's and I need it in comma separated value. Any idea how to achieve that?
the answer I get look like this:
10.0.0.190
10.0.0.117
10.0.0.151
but I need it like this:
10.0.0.190,10.0.0.117,10.0.0.151

A quick fix to your Jinja2 template:
{% for host in groups['dbnodes'] -%}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}{% if not loop.last %},{% endif %}
{%- endfor %}

Related

Ansible: Remove last comma in nested loop?

I have the following in a jinja2 template. Essentially I'm looping through a dictionary, picking out the name and if it doesn't start with "sh", I'm adding it to this config. However, I would like to have the server comma separated.
servers = {% for item in list_search_peers.json['entry'] %}{% if not item.name.startswith('sh-') %}{{ item.name }}{% endif %}{% endfor %}
Normally i would do something like:
servers = {% for item in list_search_peers.json['entry'] %}{% if not item.name.startswith('sh-') %}{{ item.name }}{% if not loop.last %},{% endif %}{% endif %}{% endfor %}`
However loop.last won't work because I am filtering out one of the values.
My output is:
servers = x.x.x.x:8089,y.y.y.y:8089,
But i want it without the last ,:
servers = x.x.x.x:8089,y.y.y.y:8089
I was trying {% set } to set a variable but had no luck there.
Filter the list first. For example
- set_fact:
my_list: "{{ list_search_peers.json.entry|
rejectattr('name', 'match', '^sh-(.*)$')|
list }}"
then use it in the template
servers = {% for item in my_list %}{{ item.name }}{% if not loop.last %},{% endif %}{% endfor %}

How to trim last character when using ansible jinja loop

My template like as blow
{% if hostvars[inventory_hostname].local_zk_server_id is defined %}
zookeeperServers={% for host in {{ groups[{{ target_hosts }}] %}}
"{{ hostvars[host].inventory_hostname }}:2181,"
{% endfor %}
{% endif %}
output ishost1:2181,host2:2181,host3:2181,
How to trim last comma
There are several possible gotchas in your above template regarding variables access. Moreover, rather than trimming the last character in your string, the best solution is probably not to write it. Here is a better solution IMO in my below example fixing all the problems I'm referring to:
{% set zookeeperServers=[] %}
{% if hostvars[inventory_hostname].local_zk_server_id is defined %}
{% for host in groups[target_hosts] %}
{% zookeeperServers.append(hostvars[host].inventory_hostname + ":2181") %}
{% endfor %}
zookeeperServers="{{ zookeeperServers | join(',') }}"
{% endif %}

How can I use AWS tags in a template?

I know that it is possible to loop over lists in a Jinja2 template like this:
{% for host in vars['play_hosts'] %}
"{{ host }}"{% if not loop.last %},{% endif %}
{% endfor %}
(Example stolen from this question.)
How can I use AWS tag based values like "the IPs of all hosts with value 'dev' in tag 'Environment'" instead of vars['play_hosts']?
I found out myself that it is only a matter of using the right group. All ec2 instances with the same tag can be found in a group and can be addressed by using e.g. groups['tag_Environment_dev']. So the example from the question would look like this:
{% for host in groups['tag_Environment_dev'] %}
"{{ host }}"{% if not loop.last %},{% endif %}
{% endfor %}

Ansible/Jinja: condition with an undefined statement

I need to iterate over all hosts and generate config file for hosts that are not contained in group somegroup:
{% for host in groups.all if host not in groups['somegroup'] %}
But if somegroup does not exist, it fails (argument of type 'StrictUndefined' is not iterable).
How do I write this correctly to avoid two different for cycles:
{% if groups['somegroup'] is defined %}
{% for host in groups.all if host not in groups['somegroup'] %}
...
{% endfor %}
{% else %}
{% for host in groups.all %}
...
{% endfor %}
{% endif %}
I think you're looking for the default filter:
{% for host in groups.all if host not in groups['somegroup'] | default([]) %}

Multiple groups when iterating in a template file

This article from Ansible.com shows how you can iterate over a group inside of a template file: https://support.ansible.com/hc/en-us/articles/201957887-How-to-loop-over-a-list-of-hosts-in-a-group-inside-of-a-template-
It shows the following code:
{% for host in groups['db_servers'] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
It works beautifully, but the servers I want to iterate over are defined by being in multiple groups. So imagine that I want to iterate over all of the servers that are in BOTH the db_servers and qa groups. How can I do this?
I tried to specify the intersection of the group in the same manner I do in my playbook, but that doesn't work. So, when I try:
{% for host in groups['db_servers:&qa'] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
I get the following error:
fatal: [54.173.247.115] => {'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'dict object' has no attribute 'db_servers:&qa'", 'failed': True}
Any suggestions on how to iterate over multiple groups in a template file?
Ansible has the intersect filter. See Set Theory Filters.
{% for host in groups['db_servers'] | intersect(groups['qa']) %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
You could wrap your loop in another for the two server groups:
{% for svrs in ['db_servers', 'qa'] %}
{% for host in groups[svrs] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
{% endfor %}

Resources