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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章