How to exclude an host in Ansible Jinja2 template for-loop? - 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 %}

Related

"AnsibleError: template error while templating string: unexpected 'end of statement block'

I have a jinja2 template that looks like this:
token: {{ RANCHER_SERVER_TOKEN}}
server: https://{{ RANCHER_RKE2_SERVER }}:9345
{% endif %}{% if RANCHER_TLS_SAN is defined %}
tls-san:{% for item in RANCHER_TLS_SAN +%}
- {{ item }}{% endfor +%}
{% endif %}
{% if RANCHER_NODE_LABELS is defined %}
node-label:{% for item in RANCHER_NODE_LABELS +%}
- {{ item }}{% endfor +%}
{% endif %}
{% if RANCHER_NODE_TAINTS is defined %}
node-taint:{% for item in RANCHER_NODE_TAINTS +%}
- {{ item }}{% endfor +%}
{% endif %}
in my inventory group in group_vars I have this data structure
---
RANCHER_TLS_SAN:
- k3-crontroller-1.prometheus.internal
RANCHER_NODE_TAINTS:
- "CriticalAddonsOnly=true:NoExecute"
I test it through this link: https://ansible.sivel.net/test/
and it renders out great.
However I get this issue when running the playbook:
fatal: [k3-rancher-controller-1]: FAILED! => {"changed": false, "msg": "AnsibleError: template error while templating string: unexpected 'end of statement block'. String: {%if RANCHER_DOWNSTREAM_SERVER_AGENT_NODE is defined %}\ntoken: {{ RANCHER_SERVER_TOKEN }}\nserver: https://{{ RANCHER_RKE2_SERVER }}:9345\n{% endif %}{% if RANCHER_TLS_SAN is defined %}\ntls-san:{% for item in RANCHER_TLS_SAN +%}\n - {{ item }}{% endfor %}\n{% endif %}\n{% if RANCHER_NODE_LABELS is defined %}\nnode-label:{% for item in RANCHER_NODE_LABELS +%}\n - {{ item }}{% endfor %}\n{% endif %}\n{% if RANCHER_NODE_TAINTS is defined +%}\nnode-taint:{% for item in RANCHER_NODE_TAINTS +%}\n - {{ item }}{% endfor %}\n{% endif %}"}
My playbook looks like this:
---
- name: Create VM for Rancher Kubernetes Control Plane Nodes
hosts: master
gather_facts: no
become: yes
become_user: root
tasks:
- name: create directory /etc/rancher/rke2
file:
path: /etc/rancher/rke2
state: directory
- name: Create template and copy to Agent nodes
template:
src: playbooks/templates/config.j2
dest: /etc/rancher/rke2/config.yaml
I am using ansible 2.9.27.
Does anyone know what is going on?
Any help is much appreciated. Many thanks

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 concat vars to string

I've spent most of the day trying to solve this problem and have thus far failed. I am building some playbooks to automate functions in Splunk, and am attempting to convert a list of hosts from an inventory group E.G.
[search_head]
1.2.3.4
5.6.7.8
My expected (desired) result from the debug output of the play should be:
https://1.2.3.4:8089, https://5.6.7.8:8089
I am attempting to complete this by running the following playbook against a running host:
---
- name: Build search head list to initialize the captain
hosts: search_head
remote_user: ansible
vars:
inventory_file: ./inventory-ec2-single-site
search_head_uri: "{{ lookup('template', './bootstrap-sh-deployer.j2') }}"
pre_tasks:
- include_vars:
dir: 'group_vars'
extensions:
- yml
- yaml
tasks:
- name: dump array
debug:
msg: "{{ search_head_uri }}"`
With the template bootstrap-sh-deployer.j2:
{%- set search_head_uri = [] %}
{% for host in groups['search_head'] %}
{%- if search_head_uri.append("https://{{ host }}:8089") %}
{%- endif %}
{%- if not loop.last %}, {% endif -%}
{%- endfor %}
However, the current play returns search_head_uri: ", " which tells me that the loop is running, but {{ host }} is not resolving.
Once you open a Jinja2 expression or a statement you should use Jinja2 syntax. You cannot nest them (i.e. you can't use {{ }} inside {% %}).
{%- if search_head_uri.append("https://" + host + ":8089") %}
This worked - Combination of the answer above to fix jinja formatting and using hostvars to get to the ansible_nodename.
{%- set search_head_uri = [] %}
{% for host in groups['search_head'] %}
{{ "https://" + hostvars[host]['ansible_nodename'] + ":8089" }}
{%- 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)) }}"'

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([]) %}

Resources