Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort IPs via Jinja2 template

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') %}
like image 697
stovie1000 Avatar asked Jun 26 '17 23:06

stovie1000


2 Answers

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 }}'
like image 165
pfm Avatar answered Sep 27 '22 18:09

pfm


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
like image 34
neokyle Avatar answered Sep 27 '22 16:09

neokyle