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' %}
Related
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'']'
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
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 %}
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 %}
A newbie django template question, hope to get some pointers.
I'm passing back a dictionary to render to html for a page. The structure of the dictionary is like the following:
dic:{
"names":["name1", "name2", "name3"],
"names1":{
"addresses":["address1","address2","address3"],
"key2":[......]
......
}
"name2":{......}
}
How do I access the inner dictionaries? The only way to know the keys for those inner dictionaries is from the list, but I was unable to iterate through values pointed by key "names" and use that value as a key to get the other dictionary. I have looked into writing customer filters/tags but not sure exactly how to proceed.
Use items, from django docs:
{% for key, value in data.items %}
{{ key }}: {{ value }}
{% endfor %}
I tested it with your example:
In template:
<ul>
{% for l1_key, l1_value in dic.items %}
<li>{{ l1_key }}:
<ul>
{% for l2_key, l2_value in l1_value.items %}
<li>{{ l2_key }}: {{ l2_value }}</li>
{% empty %}
<li>{{ l1_value }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
This will output something like:
- name2:
- address: [1, 2, 3]
- names:
- ['name1', 'name2', 'name3']
- names1:
- key2: [1, 2]
- addresses: ['address1', 'address2', 'address3']
items return a list of tuples formed by (key, value)
I used this dic (fix minor problems in your example):
dic = {
"names":["name1", "name2", "name3"],
"names1":{
"addresses":["address1","address2","address3"],
"key2":[1,2]
},
"name2":{'address':[1,2,3]}
}