通过Jinja2模板对IP地址进行排序

7

我在使用Jinja2和Ansible时遇到了一个IP排序问题。以下是我用于ansible模板的变量和jinja2代码。

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

DNS区域文件已正确创建,但IP地址未按数字顺序排序。我尝试使用以下方法,但没有成功:
按主机名字母表顺序排序
{% for hostname, dnsattr in center.iteritems() | sort %}

找不到属性dnsattr

{% for hostname, dnsattr in center.iteritems() | sort(attribute='dnsattr.ip') %}

找不到属性ip。
{% for hostname, dnsattr in center.iteritems() | sort(attribute='ip') %}

main.yml 格式不正确 - 重复 ip 属性,db.example.com.j2 使用未定义的 center 变量。而您表示“DNS区域文件已正确创建”。真的吗? - Konstantin Suvorov
嗨Konstantin,抱歉。我在帖子中错误地粘贴了main.yml数据。我已经编辑了发布的数据以正确反映我的开发环境。排序问题仍然存在。 - stovie1000
模板中center变量怎么样? - Konstantin Suvorov
又是一个复制粘贴的问题。现在数据和变量应该是正确的了。 - stovie1000
你能否重构输入数据,使其成为一个列表?例如[{host: 'srv1',ip:'10.2.110.3'}, etc.] - Konstantin Suvorov
模板中有两个for循环。为什么需要在任务中使用with_items - Chris Lam
2个回答

1
要想按数字顺序排列IP,您可以实现并使用自己的过滤器插件(顺便说一句,我对任何其他解决方案都很感兴趣):
在ansible.cfg中添加filter_plugins = path/to/filter_plugins。
在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)

然后,在Ansible中:
- name: "Sort ips"
  debug:
    msg: vars='{{ my_ips | sort_ip_filter }}'

我还会使用ipaddr过滤器来确保格式正确:
- name: "Sort ips"
  debug:
    msg: vars='{{ my_ips | ipaddr | sort_ip_filter }}'

谢谢大家!反馈很棒。 - stovie1000
Chris,你说得对,因为我只创建一个文件,所以我不需要with_items。Konstantin,我已将我的main.yml文件格式更改为列表,这样做后,我不再需要sort函数,因为文件会按升序读取。Nicolas,我将尝试使用你的Jinja过滤器对原始的main.yml文件进行排序,以便练习创建和添加自定义Jinja过滤器。 - stovie1000

1
我看不到任何文档指出这一点,我只是根据逻辑推断出来的,在意识到 IP 和 int 之间存在转换时进行了前后转换。
(注:在 Ansible 2.9.1 中,方法 1 对我有效,文档说自 ansible 2.4.x 起方法 2 就有效了。)
假设我们有两个文件:inventory.ini 和 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 }}"

然后我们可以使用Bash# ansible-playbook playbook.yml -i inventory.ini命令,并查看未排序的IP顺序= 10.0.0.12、10.0.0.60、10.0.0.3,升序排列的IP顺序= 10.0.0.3、10.0.0.12、10.0.0.60,降序排列的IP顺序= 10.0.0.60、10.0.0.12、10.0.0.3。

或者,您可以利用:在play级别指定主机顺序: 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

我也发现这个问答很有用 https://dev59.com/CFgQ5IYBdhLWcg3wnFLJ sm4rk0在2.2++中的答案对我特别有启发。 - neokyle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接