Ansible Template with Jinja formatting - templates

I have a playbook that runs a few commands on network devices and pulls the results into separate lists, and then using Template + a .j2 file outputs it all into a seperate file. The template looks like:
{% for i in ips %}
IP: {{ i }}
{% endfor %}
{% for j in intf %}
Intf: {{ j }}
{% for k in br_list %}
BR: {{ k }}
{% endfor %}
My output looks like this:
IP: 127.0.0.1
IP: 127.0.0.2
IP: 127.0.0.3
IP: 127.0.0.4
Intf: Vlan1
Intf: Vlan2
Intf: Vlan3
Intf: Vlan4
BR: False
BR: False
BR: False
BR: False
What I want is for the output to be tabulated like this:
IP Intf BR
127.0.0.1 Vlan1 False
127.0.0.2 Vlan2 False
127.0.0.3 Vlan3 False
127.0.0.4 Vlan4 False
Any nested loops I tried returns duplicates of each list. Is this possible with Ansible/Jinja?

Use zip filter:
{% for i in ips | zip(intf, br_list) %}
{{ "%-10s" | format(i[0]) }}{{ "%-10s" | format(i[1]) }}{{ "%-10s" | format(i[2]) }}
{% endfor %}
"%-10s" | format(i[0]) is to get 10 spaces padding on the right side.
You can even use nested loop:
{% for i in l1 | zip(l2,l3) %}
{% for j in i %}
{{ "%-10s" | format(j) }}
{%- endfor %}
{% endfor %}

Related

Apply if-else statement on a dictionary using django-templates

In a django - webapp I am classifying between two classes of images i.e. Ants and Bees
I have returned the dictionary to the templates(index.html)
context={
'ant':("%.2f" % predictions[0]),
'bee': ("%.2f" % predictions[1]),
}
when applying this
{% for key , value in pred.items %}
<p>{{key}}: {{value}}%</p>
{% endfor %}
i got this which is pretty much what i wanted to display now i want to display the one with greater probability how do i do it ?
I cannot access elements of the dictionary inside if else statement , though i tried doing this
{% for key, value in pred.items %}
{% if value.0 > value.1 %}
<p>Result : {{value.0}}</p>
{% elif value.0 < value.1 %}
<p>Result: {{key}}</p>
{% endif %}
{% endfor %}
Since your data structure does not look very dynamic and flexible, you could do it the following static way:
Result:
{% if pred.ant > pred.bee %}
Ant: {{ pred.ant }}
{% elif pred.ant < pred.bee %}
Bee: {{ pred.bee }}
{% else %}
Ant: {{ pred.ant }}
Bee: {{ pred.bee }}
{% endif %}

regex expression in jinja2

I have a jinja2 script with a for loop, I just want to see if there is any way I can use regex checks in an if statement.
So the script looks like:
{% for key, value in notes.items() -%}
if {{ value }} starts with http or https
then ~*^/{{ key }}(\?.*)?$ {{ value }};
otherwise
~*^/{{ key }}(\?.*)?$ /{{ value }};
{% endfor %}
Is that somewhow writable???
For example,
- hosts: localhost
gather_facts: false
vars:
_dict:
k1: v1
k2: https://example.com
k3: http://example.com
tasks:
- debug:
msg: |
{% for key, value in _dict.items() -%}
{% if value is regex('^(http|https).*$') %}
~*^/{{ key }}(\?.*)?$ {{ value }};
{% else %}
~*^/{{ key }}(\?.*)?$ /{{ value }};
{% endif %}
{% endfor %}
gives
msg: |-
~*^/k1(\?.*)?$ /v1;
~*^/k2(\?.*)?$ https://example.com;
~*^/k3(\?.*)?$ http://example.com;
Notes
Q: "No test named 'regex' found."
See Testing strings. The test match gives the same result
- debug:
msg: |
{% for key, value in _dict.items() -%}
{% if value is match('(http|https)') %}
~*^/{{ key }}(\?.*)?$ {{ value }};
{% else %}
~*^/{{ key }}(\?.*)?$ /{{ value }};
{% endif %}
{% endfor %}
Q: "The same result with 'match' and 'search'."
A: Test the first 4 characters of the value
{% if value[:4] == 'http' %}

Ansible: Filter one IP belong to which net ipaddr

At first I wrote a simple filter to decide in which environment an ip belongs to:
vars:
testip0: 10.160.30.20
testip1: 10.190.2.25
ip_range_live: 10.160.0.0/22
ip_range_qa: 10.170.0/22
ip_range_devel: 10.180.0.0/22
filter:
datacenter:
"{% if ansible_default_ipv4.address | ipaddr(ip_range_live) %}live
{% elif ansible_default_ipv4.address | ipaddr(ip_range_qa) %}qa
{% elif ansible_default_ipv4.address | ipaddr(ip_range_devel) %}devel
{% else %}INVALID{% endif %}"
(formatted for better readability)
This works fine!
But now the problemis comming ...
Now we got a new ip-range for live
ip_range_live: [ 10.160.0.0/22, 10.190.0.0/22 ]
But the ansible ipaddr filter can't work with a list (on the right side)
Any idea?
For example,
- debug:
msg: "ip: {{ item }} ranges: {{ list_of_ranges }}"
loop:
- 10.160.30.20
- 10.190.2.25
vars:
ranges:
live: [10.160.0.0/22, 10.190.0.0/22]
qa: [10.170.0/22]
devel: [10.180.0.0/22]
list_of_ranges_str: |-
{% for k,v in ranges.items() %}
{% for i in v %}
{% if item|ansible.utils.ipaddr(i) %}{{ k }}{% endif %}
{% endfor %}
{% endfor %}
list_of_ranges: "{{ (list_of_ranges_str|length > 0)|
ternary(list_of_ranges_str.split('\n')|unique,
'INVALID') }}"
gives
msg: 'ip: 10.160.30.20 ranges: INVALID'
msg: 'ip: 10.190.2.25 ranges: [''live'']'

Conditional if the variable exists and does not exist

I have a YAML data like this :
peers:
eth1:
hostname: host-01
state: Idle
eth2:
hostname: host-02
state: Established
eth3:
hostname: host-03
state: Established
ping_to:
host-02: success
host-03: success
with jinja2,Ii want to define something like this:
{% for key, value in peers.iteritems() %}
{% for key2, value2 in ping.iteritems() %}
{% if value.hostname is exist in key2 %}
ping is success
{% elif value.hostname is not exist key2 %}
ping not found
{% endif %}
{% endfor %}
{% endfor %}
So basically if the hostname value is in one of the ping keys, then it is a success. If not, then fail. how to say it if the hostname exists or does not exist?
You actually do not need that nested loop, you could simply assert that the hostname value is a key in the ping_to dictionnary:
{% for interface_name, interface_value in peers.items() %}
{%- if ping_to[interface_value.hostname] is defined -%}
ping is success
{%- else -%}
ping is not found
{%- endif %}
{% endfor %}
Another, simpler way, would be to use the default filter, to have an alternative output when the key is indeed not defined.
{% for interface_name, interface_value in peers.items() -%}
ping is {{ ping_to[interface_value.hostname] | default('not found') }}
{% endfor %}
Both those snippets would give:
ping is success
ping is success
ping is not found

condition template in ansible

I have this template (set_ip.j2):
{% if '{{ansible_env.SSH_CONNECTION.split(' ')[2]}}' == '{{ ip_ssh }}' %}
address = {{ ip_db }}
name='db1'
{% endif %}
but this condition not work! I want address and name set by this value in the config file.
Never ever use nested expressions in Jinja2:
{% if ansible_env.SSH_CONNECTION.split(' ')[2] == ip_ssh %}
address = {{ ip_db }}
name='db1'
{% endif %}