Ansible Jinja template variable hostgroup - templates

I use this template to get list of IPs in hostgroups named [web]
{% for h in groups['web'] %}
ssh -i ~/ansible_users_keys/{{ new_user_name_global }}_id_rsa {{ new_user_name_global }}#{{ hostvars[h].ansible_nodename }}
{% endfor %}
Could someone prompt me which variable should I use instead [web] in case if I run this command?
ansible-playbook -i hosts server.yml --limit web
Thanks in advance

'ansible_play_batch' is variablle that has the list of hostnames that apply to the current play.
{% for h in ansible_play_batch %}
ssh -i ~/ansible_users_keys/{{ new_user_name_global }}_id_rsa {{ new_user_name_global }}#{{ hostvars[h].ansible_host }}
{% endfor %}

Related

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

AnsibleUndefinedVariable in template

i hope you guys can help me.
I want to copy following template with ansible:
IFACE_EXTERNAL="{{ ansible_default_ipv4.interface }}"
IP_EXTERNAL="{{ ansible_default_ipv4.address }}"
IFACE6_EXTERNAL="{{ ansible_default_ipv6.interface }}"
IP6_EXTERNAL="{{ ansible_default_ipv6.address }}"
{% if ansible_interfaces[2] is defined %}
{% set count = 2 %}
{% for iface in ansible_interfaces %}
{% if "tun0" in iface %}
IFACE_INTERNAL_1="{{ iface }}"
{% endif %}
{% if "ens" in iface %}
IFACE_INTERNAL_{{count}}="{{ iface }}"
{% set count = count + 1 %}
{% endif %}
{% if hostvars[inventory_hostname]['ansible_%s'|format(iface)]['ipv4'] is defined %}
IP_INTERNAL_{{loop.index}}="{{ hostvars[inventory_hostname]['ansible_%s'|format(iface)]['ipv4']['address'] }}"
{% endif %}
{% endfor %}
{% endif %}
Now, if i copy this template with ansible, i get following error: "AnsibleUndefinedVariable: 'dict object' has no attribute 'interface'".
I tried for an hour but don't get a solution.
Does anyone know where the error is?
You wrote a very complicated jinja template. Now, live and suffer with it.
It's really bad idea to have a complicated access patterns into dynamic variables within jinja, as you have 0 (zero) debug tools there.
The proper way is to have all computation to be done at ansible level:
tasks:
- debug: var=some_var1
- debug: var=some_var2
- template:
src: foo.j2
dest: foo
vars:
some_var1: '{{...}}'
some_var2: '{{...}}'
By using external (ansible) vars you can debug them. If you use computation in Jinja you need to be 100% sure data are there. How can you be sure that facts are there, if default set of network variables is dependent on where there is default gateway or not on the target system?
To avoid such errors you must use something similar to {{ ansible_default_ipv6.interface | default('foo') }} as there is no guarantee that ansible_default_ipv6 object has the interface attribute.
If you do not do this, you will get templating errors. The other option is to use if conditions like '{% if interface' in ansible_default_ipv6 %}....

flask url conflicting with href

In my HTML code i have the following jinja template code:
{% for site in sites %}
{{ site.site_name }}
{% endfor %}
The issue is: let's assume that {{ site.site_link }} = www.domainname.com, so whenever the link is clicked it supposed to direct the user to the domainname page. but, it leads to :
http://127.0.0.1:5000/www.domainname.com
which is a 404..Any idea why is this happening and how to fix it?
I don't know if this is relevant, but, I am using flask Blueprints.
You need to put http:// in front of it, like href="http://........"
{% for site in sites %}
{{ site.site_name }}
{% endfor %}

Ansible: compose list of facts in jinja template

I am setting up a cluster service with Ansible 1.9.2 and need to configure a JSON config file with a list of cluster servers to join.
Currently, I have this working as below. It produces correct, if ugly, output.
{
...
"join": [
{% for host in groups['cluster'] %}
"{{ hostvars[host]['ansible_default_ipv4']['address'] }}{% if not loop.last %}, {% endif %}
{% endfor %}
],
...
}
Is it possible for Ansible to create a list of specific host facts, or for Jinja to compose a list dynamically? I would hope for something I can leave in my template like this:
{
...
"join": {{ list_of_cluster_ips|to_nice_json }},
...
}
I tried some Jinja magic at the top of the template file to generate the list as below:
{% set list_of_cluster_ips = [] %}
{% for host in groups['cluster'] %}
{% do list_of_cluster_ips.append(host) %}
{% endfor %}
{
...
"join": {{ list_of_cluster_ips|to_nice_json }},
...
}
But Ansible doesn't support the 'do' function of Jinja and fails with fatal: [cluster-1] => {'msg': "AnsibleError: file: <template>, line number: 3, error: Encountered unknown tag 'do'. Jinja was looking for the following tags: 'endfor' or 'else'. The innermost block that needs to be closed is 'for'.", 'failed': True}.
Is there a way for Ansible to generate the list that can be used in the template?
Try this:
{%- set list_of_cluster_ips = [] %}
{%- for host in groups['cluster'] %}
{%- if list_of_cluster_ips.append(hostvars[host]['ansible_default_ipv4']['address']) %}
{%- endif %}
{%- endfor %}
{
...
"join": {{ list_of_cluster_ips|to_nice_json }},
...
}

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