Jinja2 in Ansible Playbook - ansible

how can i loop in an ansible playbook over gathered facts?
I tried:
...
haproxy_backends:
- name: 'backend'
servers:
{% for host in groups['app-servers'] %}
- name: "{{ hostvars[host]['ansible_hostname'] }}"
ip: "{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}"
{% endfor %}
But this doesn't work, it results in a Syntax Error. Is it even possible to use jinja in a playbook?
I use a ansible galaxy role (info.haproxy) and i don't want to change the provided templates.

No you can't do this.
This has to be done in a template, something like :
template/haproxy.cfg.j2 :
...
{% for host in groups['app-servers'] %}
backend {{ hostvars[host]['ansible_hostname'] }}
server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}:1234 check inter 5000 slowstart 2m
{% endfor %}
...
and use :
tasks:
- name: Deploy haproxy config
template: src=templatepath/haproxy.cfg.j2 dest=/etc/haproxy/haproxy.cfg
You get the idea, YMMV.
Good luck.

Related

Not able to use for loop in Ansible

- name: checking whether symbolic link created or not
{% for item in ['/opt/lsf/bin/bsh','/opt/praveen'] %}
{{ item }}:
debug:
msg: "{{ item }}"
{% endfor %}
Please let me know if anything is wrong in this
Resolved Using Ansible:
You need to create a Playbook.yaml :
---
- hosts: all
become: yes # ask ansible to be a super user (working like sudo )
roles:
- template-module
also Create a role for templates:
In you main.yaml put this code:
- name: checking whether symbolic link created or not
template:
src: test.j2
dest: /tmp/test.yaml
and in you jinaj2 "test.j2" template put this ;
{% for item in ['/opt/lsf/bin/bsh','/opt/praveen'] %}
{{ item }}:
debug:
msg: "{{ item }}"
{% endfor %}
This can hel you to resolve your issue.

Ansible Jinja2 template for loop

I have two linux servers:
- server1: ip: 10.241.55.6, hostname: server1
- server2: ip: 10.242.55.7, hostname: server2
I have created an ansible inventory file named servers with the content bellow:
[IC]
10.241.55.6
10.241.55.7
Now I have created this jinja2 inventory template file: test.j2 with this content:
[IC]
{% for hostip in groups['IC'] %}
{% if hostip == ansible_default_ipv4.address %}
{{ ansible_default_ipv4.address }} default_hostname={{ ansible_nodename }}
{{ ansible_default_ipv4.address }} default_hostname={{ ansible_nodename }}
{% endif %}
{% endfor %}
And I'm running this ansible playbook:
---
- name: Generate portal inventory file
hosts: all
tasks:
- name: Generate inventory
delegate_to: localhost
template:
src: inventory/test.j2
dest: inventory/test
The command is: ansible-playbook -i inventory/servers generate-inventory.yml
The final goal is that ansible connects to each of the servers from the inventory files and then based on the jinja2 inventory template, it creates a new inventory file with this format:
[IC]
10.241.55.6 default_hostname=hostname_of_the_server_with_that_ip
and so on...
The issue here with the for loop is that all the entries are with the same server ip (while I should have an entry for each of the servers with their respective hostnames):
[IC]
10.241.55.6 default_hostname=server1
10.241.55.6 default_hostname=server2
What I'm missing here? Also if there is any other better way to achieve this please let me know.
You're using the same variable twice in the template...
{{ ansible_default_ipv4.address }} default_hostname={{ ansible_nodename }}
{{ ansible_default_ipv4.address }} default_hostname={{ ansible_nodename }}
...so of course you're getting two identical lines. It sounds like you want to access the per-host value of this variable, which means you need to access it via hostvars.
Maybe something like this:
[IC]
{% for host in groups['IC'] %}
{{ hostvars[host].ansible_default_ipv4.address }} default_hostname={{ hostvars[host].ansible_nodename }}
{% endfor %}

Creating text file from jinja template with inputs from csv file

I'm trying to create a text file which goes through the CSV file and populates variables into specific fields.
playbook.yml:
- hosts: localhost
tasks:
- name: "Reading user information"
read_csv:
path: /home/test/vlans.csv
delimiter: ','
register: vlans
- debug: var=vlans
- name: Creating VLANs configuration
template:
src: vlan.conf.j2
dest: /tmp/vlan.conf
Jinja2 Template vlan.conf.j2:
{% for item in vlans %}
!
vlan {{ item.VLAN }}
name {{ item.Description }}
vn-segment {{ item.VNI }}
interface nve1
member vni {{ item.VNI }}
{% endfor %}
and this is a test vlans.csv file:
Tenant,VRF ,VLAN,VNI,Subnet,Description,Good to go
Test,,5,20005,,LAB-Checkpoint-FW-Mgmt,Yes
Test,,208,20208,,LAB-DMZ,Yes Test,,209,20209,,LAB-CSR-MGMT,Yes
Test,10000,210,20210,192.168.12.1/28,LAB-VRF-to-FW,Yes
Prod,,761,20761,,PROD-CORE,Yes
Prod,105,840,20840,172.18.33.1/24,Backups,Yes
Prod,,841,20841,,Transport,Yes
I want to end up with file like in jinja2 template and not repeating line "interface nve 1"
In your question, interface nve1 is inside a loop. It will repeat multiple times in the resulting vlan.conf file.
Use multiple loops in the jinja template to decide what is repeated and what isn't:
{% for item in vlans.list %}
vlan {{ item.VLAN }}
name {{ item.Description }}
vn-segment {{ item.VNI }}
{% endfor %}
interface nve1
{% for item in vlans.list %}
member vni {{ item.VNI }}
{% endfor %}
Note that I've referred to vlans.list in the start of the loops instead of vlans. This is correct as per documentation, but different to the example in the question so it may need adjusting.

ansible - get host by variable

I would like to filter hosts by a variable set on them. For example:
I have a group of hosts, one is master, the rest are slaves. On the master the variable replica_type: master is set. I would now like to get the master server dynamically.
My working aproach is:
- set_fact:
master_server_string: >-
{% for server in groups.my_servers %}
{% if hostvars[server]['replica_type']=='master' -%}
{{ server }}
{% endif %}
{% endfor %}
- set_fact:
master_server: "{{ master_server_string|trim }}"
Is there a way to perform the same with a filter (or at least in a single task)?
e.g. something like
"{{ server for server in groups.my_servers if hostvars[server]['replica_type'] == 'master' }}"
I believe you are looking for the group_by module.
https://docs.ansible.com/ansible/latest/modules/group_by_module.html
- group_by:
key: {{ replica_type }}
You can pull a value out of a group of hosts by a property by looping the group and checking for a matching value like this too:
- set_fact:
master_server: "{{ item }}"
with_items: "{{ groups.my_servers }}"
when: hostvars[item].replica_type == 'master'

Vague deprecation error when running ansible playbook

My playbook contains vars that are passed to a role. When I run it, I get [DEPRECATION WARNING]: Skipping task due to undefined Error, in the future this will be a fatal error..
Here's what I have:
---
- hosts: hadoopL0X
become: yes
become_method: sudo
vars:
logrotate_scripts:
- name: "{{ item }}"
with_items:
- zookeeper
- sa
path: "/var/log{{ item }}/{{ item }}.log "
options:
- daily
- rotate 3
- missingok
- compress
- notifempty
roles:
- log-rotation
...
The role is as such:
log-rotation/tasks/main.yml
---
- name: Setup logrotate.d scripts
template:
src: logrotate.d.j2
dest: "{{ logrotate_conf_dir }}{{ item }}"
with_items: "{{ logrotate_scripts }}"
...
log-rotation/defaults/main.yml
---
logrotate_conf_dir: "/etc/logrotate.d/"
logrotate_scripts: []
...
log-rotation/templates/logrotate.d.j2
# {{ ansible_managed }}
"{{ item.path }}" {
{% if item.options is defined -%}
{% for option in item.options -%}
{{ option }}
{% endfor -%}
{% endif %}
{%- if item.scripts is defined -%}
{%- for name, script in item.scripts.iteritems() -%}
{{ name }}
{{ script }}
endscript
{% endfor -%}
{% endif -%}
}
Any help would be much appreciated!
with_items can only be used with tasks, it cannot be used when defining variables, and because of that item isn't defined. It also looks like that the service variable isn't defined as well.

Resources