I am having an issue sorting IPs via Jinja2 and Ansible. Here are my variables and jinja2 code for ansible templates.
roles/DNS/vars/main.yml:
---
DC1:
srv1:
ip: 10.2.110.3
srv2:
ip: 10.2.110.11
srv3:
ip: 10.2.110.19
srv4:
ip: 10.2.110.24
DC2:
srv5:
ip: 172.26.158.3
srv6:
ip: 172.26.158.11
srv7:
ip: 172.26.158.19
srv8:
ip: 172.26.158.24
roles/DNS/templates/db.example.com.j2:
$TTL 86400
@ IN SOA example.com. root.example.com. (
2014051001 ; serial
3600 ; refresh
1800 ; retry
604800 ; expire
86400 ; minimum
)
; Name server
IN NS dns01.example.com.
; Name server A record
dns01.example.com. IN A 10.2.110.92
; 10.2.110.0/24 A records in this Domain
{% for hostname, dnsattr in DC1.iteritems() %}
{{hostname}}.example.com. IN A {{dnsattr.ip}}
; 172.26.158.0/24 A records in this Domain
{% for hostname, dnsattr in DC2.iteritems() %}
{{hostname}}.example.com. IN A {{dnsattr.ip}}
roles/DNS/tasks/main.yml:
- name: Update DNS zone file db.example.com
template:
src: db.example.com.j2
dest: "/tmp/db.example.com"
with_items: "{{DC1,DC2}}"
- name: Restart DNS Server
service:
name: named
state: restarted
The DNS zone files get created correctly, but the IPs are not numerically sorted. I have tried using the following with no luck:
Sorts on hostname alphabetically
{% for hostname, dnsattr in center.iteritems() | sort %}
Does not find the attribute dnsattr
{% for hostname, dnsattr in center.iteritems() | sort(attribute='dnsattr.ip') %}
Does not find the attribute ip
{% for hostname, dnsattr in center.iteritems() | sort(attribute='ip') %}
To have the IPs numerically sorted you could implement and use your own filter plugin (btw I'd be interested in any other solution):
In ansible.cfg
add filter_plugins = path/to/filter_plugins
.
In path/to/filter_plugins/ip_filters.py
:
#!/usr/bin/python
def ip_sort(ip1, ip2):
# Sort on the last number
return int(ip1.split('.')[-1]) - int(ip2.split('.')[-1])
class FilterModule(object):
def filters(self):
return {
'sort_ip_filter': self.sort_ip_filter,
}
def sort_ip_filter(self, ip_list):
return sorted(ip_list, cmp=ip_sort)
Then, in Ansible:
- name: "Sort ips"
debug:
msg: vars='{{ my_ips | sort_ip_filter }}'
I would also use the ipaddr
filter to ensure the format is right:
- name: "Sort ips"
debug:
msg: vars='{{ my_ips | ipaddr | sort_ip_filter }}'
I don't see any docs pointing this out, I just used logic to figure this out, after realizing a conversion back and forth between IP and int exists.
(Note: method 1 works for me in Ansible 2.9.1, the docs say method 2 has worked since ansible 2.4.x)
Say we have 2 files: inventory.ini and playbook.yml
inventory.ini
[kube_nodes]
10.0.0.12
10.0.0.60
10.0.0.3
playbook.yml
---
- name: method 1
hosts: localhost
connection: local
gather_facts: False
tasks:
- name: Unsorted IP ordering
debug:
msg: "{{ groups.kube_nodes }}"
- name: Ascending IP ordering
debug:
msg: "{{ groups.kube_nodes | list | ipaddr('int') | sort | ipaddr }}"
- name: Decending IP ordering
debug:
msg: "{{ groups.kube_nodes | list | ipaddr('int') | sort(reverse=true) | ipaddr }}"
Then we can use
Bash# ansible-playbook playbook.yml -i inventory.ini
and see
Unsorted IP ordering = 10.0.0.12, 10.0.0.60, 10.0.0.3
Ascending IP ordering = 10.0.0.3, 10.0.0.12, 10.0.0.60
Decendind IP ordering = 10.0.0.60, 10.0.0.12, 10.0.0.3
Alternatively, you may be able to make use of: specifying order of hosts at the play level: https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html#hosts-and-users
- name: method 2
hosts: all
order: sorted #reverse_sorted, inventory, reverse_inventory, shuffle
connection: local
gather_facts: False
tasks:
- debug: var=inventory_hostname
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With