Ansible nodes IPs as the one string - vagrant

I use Vagrant with Ansible. In my playbook I have the following variable:
seeds: '192.168.56.11,192.168.56.12'
192.168.56.11 and 192.168.56.12 here are IP addresses of multi-machine Vagrant configuration.
Can I do my configuration more flexible using Ansible i.e. can Ansible compose this string programmatically for me?

You can use Jinja2 to template out your variable from other variables.
So if we have a list of things like this:
seeds:
- 192.168.56.11
- 192.168.56.12
We can turn that into a comma delimited string by looping through it with something like this:
seeds_string: '{% for seed in seeds %} {{ seed }}{% if not loop.last %},{% endif %}{% endfor %}'
As for getting the IP addresses of hosts in your inventory we can access facts about other hosts than the one being configured by using the groups and hostvars magic variables.
So to get the IP addresses of all hosts in the inventory we could use something like:
{% for host in groups['all'] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
Combining this together we can then do something like this:
seeds: '{% for host in groups['all'] %} {{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}{% if not loop.last %},{% endif %}{% endfor %}'

Related

How to exclude an host in Ansible Jinja2 template for-loop?

I have a template named foo.yml.j2 used in an Ansible task to generate a foo.yml file:
{% for host in ansible_play_hosts_all %}
{{ host }},
{% endfor %}
Everything works fine except I need something like the following statement: For every host in ansible_play_hosts_all except for host==bar do this or that.
Is this achievable or the only way to do this is to categorize my hosts in different groups and use ansible_play_hosts_group?
You can use the reject filter to take your host out of the list so that it is not part of your loop:
{% for host in ansible_play_hosts_all | reject('==', 'bar') %}
{{ host }},
{% endfor %}
There are more options. The trivial one is using the condition in Jinja
{% for host in ansible_play_hosts_all %}
{% if host != 'bar' %}
{{ host }},
{% endif %}
{% endfor %}
Fit the format to your needs.
Example of a complete playbook for testing
- hosts: host_1,host_2,host_3
gather_facts: false
tasks:
- debug:
msg: |
{% for host in ansible_play_hosts_all %}
{% if host != 'host_2' %}
{{ host }},
{% endif %}
{% endfor %}
run_once: true
gives (abridged)
msg: |-
host_1,
host_3,
The next option is to remove blacklisted hosts from the loop, e.g.
blacklist: [host_2]
The template below gives the same result
{% for host in ansible_play_hosts_all|difference(blacklist) %}
{{ host }},
{% endfor %}

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 %}

refer variable in host file from jinja2

I am using jinja2 template for haproxy configuration and I have variable declared in inventory file. how do I refer this variable in template. i have paste below script but it is not working.
My Inventory:-
[as]
10.0.0.1 asRole=batch
10.0.0.2 asRole=batch
10.0.0.3 asRole=transaction
10.0.0.4 asRole=transaction
[hap]
10.0.0.6
[hap] is the ip for the haproxy and my ansible is to set the haproxy configuration on [hap] node based on the [as] node.
My Jinja2 tempalte:-
{% for host in groups['as'] %}
{% if "transaction" in "{{ asRole }} %}
server {{ hostvars[host]['inventory_hostname'] }} {{ host }}:{{ httpd_port }}check
{% endif %}
{% endfor %}
Br,
Tanmoy
Be careful with the asRole Var:
{% for host in groups['as'] %}
{% if "transaction" in asRole %}
server {{ hostvars[host]['inventory_hostname'] }} {{ host }}:{{ httpd_port }}check
{% endif %}
{% endfor %}

Ansible: get list of hosts in comma separated value

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 %}

How to set concatenated string variable in Ansible template based on a condition

I need to create a string in a template that can change between hosts, and it needs to be in the form of:
"cores": "0,1,2,3"
And the reason the string is "0,1,2,3" in this example is because the host has 4 processor cores.
So I got stuck with something which seems too convoluted to me and I'm not even sure how to use this core_count variable in my template file.
{% set core_count = '' %}
{% for i in range(ansible_processor_cores) %}
{% set core_count = core_count ~ i %}
{% if not loop.last %}
{% set core_count = core_count ~ ',' %}
{% endif %}
{% endfor %}
There are many handy lookup plugins in Ansible. Take sequence:
- hosts: localhost
gather_facts: yes
tasks:
- debug:
msg: '"cores": "{{ lookup("sequence","start=0 count="+(ansible_processor_cores|string)) }}"'

Resources