Conditional if the variable exists and does not exist - if-statement

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

Related

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

How to reference a foreign key in html django

{% for cred in allcreds %}
{% if cred.datasource.name == '...' %}
<h4>{{ cred.datasource }}</h4>
{% endif %}
{% endfor %}
In this case I check the datasource name in the conditional. Then it prints out the datasource. I want to have the datasource in the conditional.
I assume if you print out {{ cred.protocoldatasource }} it will output nothing, because your "relation" protocoldatasource does not exist.
The available foreign-keys that your model ProtocolUserCredentials has are: protocol, data_source, user, protocol_user.
So if you do
{% if cred.data_source.name == 'Demonstration Protocol, ...' %}
or any other of the mentioned relations you can access your related models.
Also note that {% if foo = 'bar' %} is invalid, you'll need to have == in the if-statement.

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

Ansible Template with Jinja formatting

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

Change variable in Ansible template based on group

I've got an Ansible inventory file a bit like this:
[es-masters]
host1.my-network.com
[es-slaves]
host2.my-network.com
host3.my-network.com
[es:children]
es-masters
es-slaves
I also have a Jinja2 template file that needs a certain value set to "true" if a host belongs to the "es-masters" group.
I'm sure that there's a simple way of doing it but after some Googling and reading the documentation, I've drawn a blank.
I'm looking for something simple and programmatic like this to go in the Jinja2 template:
{% if hostvars[host][group] == "es-masters" %}
node_master=true
{% else %}
node_master=false
{% endif %}
Any ideas?
You do it the other way around.
You check if the identifier (hostname or IP or whatever is in your inventory) is in the defined group. Not if the group is in the hostvars.
{% if ansible_fqdn in groups['es-masters'] %}
node_master=true
{% else %}
node_master=false
{% endif %}
But, what you better should do is this:
Provide default in template
# role_name/templates/template.j2
node_master={{ role_name_node_master | default(true) }}
Than override in group_vars
# group_vars/es-masters.yml
role_name_node_master: false
If your inventory does not identify hosts with ansible_fqdn, ansible_hostname, etc., you can also use group_names to check if the current host has "es-masters" as one of its groups.
{% if 'es-masters' in group_names %}
node_master=true
{% else %}
node_master=false
{% endif %}
See https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#accessing-information-about-other-hosts-with-magic-variables
To avoid error with non existing group you should check first if the group exists:
{% if 'es-masters' in group_names and ansible_fqdn in groups['es-masters'] %}
node_master=true
{% else %}
node_master=false
{% endif %}
{% if ansible_fqdn in groups['es-masters'] %}
{% set node_master=true %}
{% else %}
{% set node_master=false %}
{% endif %}
maybe like this? change the var which named node_master, rather than use a txt