Ansible常用Filter

Ansible 常用Filter

Ansible中的過濾器來自Jinja2,用於在模板表達式中轉換數據。在寫playbook的時候,偶爾需要對變量進行處理,比如在一段json文件中查找某些值進行循環,又比如獲取了一段地址但是需要對它進行切分取basename,又比如直接從對一段url進行切分處理,等等等等,在Ansible內部實現了許多Filter對上述的這些場景都提供了比較健全的Filter,這裏列出一些常用的Filter,更全面的可以查看ansible的官方文檔,和jinja2的文檔,地址都已在參考文檔章節中給出,

示例json文件

// 示例字符串
// $ cat domain_definition.json
{
        "domain": {
            "cluster": [
                {
                    "name": "cluster1"
                },
                {
                    "name": "cluster2"
                }
            ],
            "server": [
                {
                    "name": "server11",
                    "cluster": "cluster1",
                    "port": "8080"
                },
                {
                    "name": "server12",
                    "cluster": "cluster1",
                    "port": "8090"
                },
                {
                    "name": "server21",
                    "cluster": "cluster2",
                    "port": "9080"
                },
                {
                    "name": "server22",
                    "cluster": "cluster2",
                    "port": "9090"
                }
            ],
            "library": [
                {
                    "name": "lib1",
                    "target": "cluster1"
                },
                {
                    "name": "lib2",
                    "target": "cluster2"
                }
            ]
        }
}

from_json

from_json filter從json格式變量中加載成字典變量


# 查看playbook內容,從加載json文件
$ cat from_json.yml
- hosts: 192.168.240.33
  gather_facts: no # 本次playbook 不收集fact信息
  tasks:
    - name: from_json filter test
      debug:
        var:  domain_definition
  vars:
    domain_definition: "{{ lookup('file','/home/ansible/ADT/domain_definition.json') | from_json  }}"
    
# 執行
$ ansible-playbook from_json.yml

PLAY [192.168.240.33] ***********************************************************************************************************************************************

TASK [from_json filter test] ****************************************************************************************************************************************
ok: [192.168.240.33] => {
    "domain_definition": {
        "domain": {
            "cluster": [
                {
                    "name": "cluster1"
                },
                {
                    "name": "cluster2"
                }
            ],
            "library": [
                {
                    "name": "lib1",
                    "target": "cluster1"
                },
                {
                    "name": "lib2",
                    "target": "cluster2"
                }
            ],
            "server": [
                {
                    "cluster": "cluster1",
                    "name": "server11",
                    "port": "8080"
                },
                {
                    "cluster": "cluster1",
                    "name": "server12",
                    "port": "8090"
                },
                {
                    "cluster": "cluster2",
                    "name": "server21",
                    "port": "9080"
                },
                {
                    "cluster": "cluster2",
                    "name": "server22",
                    "port": "9090"
                }
            ]
        }
    }
}

PLAY RECAP **********************************************************************************************************************************************************
192.168.240.33             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

json query filter

json查詢過濾器,測試的playbook如下,#註釋部分表示對應task的輸出信息

$ cat json_query.yml
---

- hosts: 192.168.240.33
  gather_facts: no
  vars:
    domain_definition: "{{ lookup('file','/home/ansible/ADT/domain_definition.json') | from_json  }}"
  tasks:
    - name: "Display all cluster names"
      debug:
        var:  item
      loop: "{{ domain_definition | json_query('domain.cluster[*].name') }}"

#TASK [Display all cluster names] ************************************************************************************************************************************
#ok: [192.168.240.33] => (item=cluster1) => {
#    "ansible_loop_var": "item",
#    "item": "cluster1"
#}
#ok: [192.168.240.33] => (item=cluster2) => {
#    "ansible_loop_var": "item",
#    "item": "cluster2"
#}


    - name: "Display all server names"
      debug:
        var: item
      loop: "{{ domain_definition | json_query('domain.server[*].name') }}"

#TASK [Display all server names] *************************************************************************************************************************************
#ok: [192.168.240.33] => (item=server11) => {
#    "ansible_loop_var": "item",
#    "item": "server11"
#}
#ok: [192.168.240.33] => (item=server12) => {
#    "ansible_loop_var": "item",
#    "item": "server12"
#}
#ok: [192.168.240.33] => (item=server21) => {
#    "ansible_loop_var": "item",
#    "item": "server21"
#}
#ok: [192.168.240.33] => (item=server22) => {
#    "ansible_loop_var": "item",
#    "item": "server22"
#}
#


    - name: "Display all server ports and names from cluster1"
      debug:
        var: item
      loop: "{{ domain_definition | json_query(server_name_cluster1_query) }}"
      vars:
        server_name_cluster1_query: "domain.server[?cluster=='cluster1'].port"

#TASK [Display all server ports and names from cluster1] *************************************************************************************************************
#ok: [192.168.240.33] => (item=8080) => {
#    "ansible_loop_var": "item",
#    "item": "8080"
#}
#ok: [192.168.240.33] => (item=8090) => {
#    "ansible_loop_var": "item",
#    "item": "8090"
#}


    - name: "Display all ports from cluster1 as a string"
      debug:
        msg: "{{ domain_definition | json_query('domain.server[?cluster==`cluster1`].port') | join(', ') }}"

#TASK [Display all ports from cluster1 as a string] ******************************************************************************************************************
#ok: [192.168.240.33] => {
#    "msg": "8080, 8090"
#}


    - name: "Display all server ports and names from cluster1"
      debug:
        var: item
      loop: "{{ domain_definition | json_query(server_name_cluster1_query) }}"
      vars:
        server_name_cluster1_query: "domain.server[?cluster=='cluster2'].{name: name, port: port}"



#TASK [Display all server ports and names from cluster1] *************************************************************************************************************
#ok: [192.168.240.33] => (item={u'name': u'server21', u'port': u'9080'}) => {
#    "ansible_loop_var": "item",
#    "item": {
#        "name": "server21",
#        "port": "9080"
#    }
#}
#ok: [192.168.240.33] => (item={u'name': u'server22', u'port': u'9090'}) => {
#    "ansible_loop_var": "item",
#    "item": {
#        "name": "server22",
#        "port": "9090"
#    }
#}


list filters

列表過濾器

# 求列表最小值
$ ansible 192.168.240.33 -m debug -a 'msg="{{ [1,2,3,4] | min }}"'
192.168.240.33 | SUCCESS => {
    "msg": "1"
}
# 求列表最大值
$ ansible 192.168.240.33 -m debug -a 'msg="{{ [1,2,3,4] | max }}"'
192.168.240.33 | SUCCESS => {
    "msg": "4"
}
# 將列表展開,這個在某些場景下非常有用
$ ansible 192.168.240.33 -m debug -a 'msg="{{ [1,2,[3,4]] | flatten }}"'
192.168.240.33 | SUCCESS => {
    "msg": [
        1,
        2,
        3,
        4
    ]
}

# 也可以指定展開多少層
$ ansible 192.168.240.33 -m debug -a 'msg="{{ [1,2,[3,[4]]] | flatten(levels=1) }}"'
192.168.240.33 | SUCCESS => {
    "msg": [
        1,
        2,
        3,
        [
            4
        ]
    ]
}

# 對列表去重
$ ansible 192.168.240.33 -m debug -a 'msg="{{ [1,2,3,3,3,4,5,5]| unique }}"'
192.168.240.33 | SUCCESS => {
    "msg": [
        1,
        2,
        3,
        4,
        5
    ]
}

# 對比兩個列表去除不同的值
$ ansible 192.168.240.33 -m debug -a 'msg="{{ [1,2,3,3,3,4,5,5]| difference([1,2,3]) }}"'
192.168.240.33 | SUCCESS => {
    "msg": [
        4,
        5
    ]
}

random number filter

隨機數生成器

# 60以內隨機生成一個整數
$ ansible 192.168.240.33 -m debug -a 'msg="{{ 60 | random }}"'
192.168.240.33 | SUCCESS => {
    "msg": "1"
}

$ ansible 192.168.240.33 -m debug -a 'msg="{{ 60 | random }}"'
192.168.240.33 | SUCCESS => {
    "msg": "21"
}

# 從列表中隨機選擇一個數字
$ ansible 192.168.240.33 -m debug -a 'msg="{{ [1,2,4,5] | random }}"'
192.168.240.33 | SUCCESS => {
    "msg": "5"
}

$ ansible 192.168.240.33 -m debug -a 'msg="{{ [1,2,4,5] | random }}"'
192.168.240.33 | SUCCESS => {
    "msg": "2"
}

IP address filter

ip地址過濾器,此filter需要安裝netaddr模塊,安裝方法如下pip install netaddr,否則會報錯,報錯信息如下:

fatal: [192.168.240.33]: FAILED! => {"msg": "The ipaddr filter requires python's netaddr be installed on the ansible controller"}

示例:

{{ '192.0.2.1/24' | ipaddr('address') }}

Hashing filters

hash過濾器

# 示例playbook
$ cat hash_filter.yml
---
- hosts: 192.168.240.33
  gather_facts: no
  vars:
    str: 'string'
  tasks:
    - debug:
        msg: "{{ str | hash('md5') }}"

# 執行結果
$ ansible-playbook hash_filter.yml

PLAY [192.168.240.33] *******************************************************************************************************************

TASK [debug] ****************************************************************************************************************************
ok: [192.168.240.33] => {
    "msg": "b45cffe084dd3d20d928bee85e7b0f21"
}

PLAY RECAP ******************************************************************************************************************************
192.168.240.33             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

URL Split Filter

url切分過濾器

$ cat url_split_filter.yml
---
- hosts: 192.168.240.33
  gather_facts: no
  vars:
    url: 'http://user:[email protected]:9000/dir/index.html?query=term#fragment'
  tasks:
    - name: "get url hostname"
      debug:
        msg: "{{ url | urlsplit('hostname')  }}"
        
# ==> "msg": "www.acme.com"

    - name: "get url netloc"
      debug:
        msg: "{{ url | urlsplit('netloc')  }}"
# ==> "user:[email protected]:9000"
    - name: "get url path"
      debug:
        msg: "{{ url | urlsplit('path')  }}"

# ==> "msg": "/dir/index.html"
    - name: "get url port"
      debug:
        msg: "{{ url | urlsplit('port')  }}"

# ==> "msg": "9000"

    - name: "get url scheme"
      debug:
        msg: "{{ url | urlsplit('scheme')  }}"

# ==> "msg": "http"

    - name: "get url query"
      debug:
        msg: "{{ url | urlsplit('query') }}"

# ==> "msg": "query=term"

path Filter

路徑filter

# 獲取basename
$ ansible 192.168.240.33 -m debug -a 'msg={{  "/home/archforce/ADT/hosts.ini" | basename }}'
192.168.240.33 | SUCCESS => {
    "msg": "hosts.ini"
}

# 獲取目錄
$ ansible 192.168.240.33 -m debug -a 'msg={{  "/home/archforce/ADT/hosts.ini" | dirname }}'
192.168.240.33 | SUCCESS => {
    "msg": "/home/archforce/ADT"
}

# 獲取絕對路徑
$ ansible 192.168.240.33 -m debug -a 'msg={{  "./hosts.ini" | realpath }}'
192.168.240.33 | SUCCESS => {
    "msg": "/home/ansible/ADT/hosts.ini"
}

Debug Filters

用於debug的filter

$ ansible 192.168.240.33 -m debug -a 'msg={{  "hello world" | type_debug }}'
192.168.240.33 | SUCCESS => {
    "msg": "str"
}

Debug Filters

用於debug的filter

$ ansible 192.168.240.33 -m debug -a 'msg={{  "hello world" | type_debug }}'
192.168.240.33 | SUCCESS => {
    "msg": "str"
}

參考文檔

  • Ansible 官方文檔:https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#filters-for-formatting-data
  • jinja2官方文檔:https://jinja.palletsprojects.com/en/2.10.x/templates/#builtin-filters
  • ip address filter官方文檔:https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters_ipaddr.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章