Laolees's Blog

Ansible 从入门到放弃

字数统计: 5.9k阅读时长: 25 min
2019/04/23 Share

ansible

Handler字段

handler字段定义的任务可以被tasknotify字段引用,用于该task如果执行的结果为changed(即在远端服务器上完成了实际操作),则被引用的handler执行;反之,则不执行。

handler一般情况都是在所有task执行完之后,若被引用才执行。
若果想让task执行完之后立刻执行引用的handler,可以用meta: flush_handlers字段。

变量

变量通过vars字段定义,可以同时定义多个键值对形式的变量,引用变量的格式。还可以将变量分成不同属性,分类引用。如果有大量变量,可以单独使用一个yml文件统一存放变量,通过vars_files字段直接引用这个变量文件。

  1. 内置变量:ansible-playbook每次执行是都会先收集远程主机的信息,保存到大量的变量中,这些变量我们也可以使用。ansible test10 -m setup返回json格式的所有收集到的变量。我们还能够在远端主机中写入一些自定义的信息,这些信息也可以被setup模块收集到。这些信息通常以json或者INI格式被定义在/etc/ansible/facts.d/目录下的.fact文件中。

    1
    2
    3
    [testmsg]
    msg1=This is the first custom test message
    msg2=This is the second custom test message
    1
    2
    3
    4
    5
    6
    {
    "testmsg":{
    "msg1":"Thsi is the first custom test message",
    "msg2":"This is the second custom test message"
    }
    }
    1
    通过`ansible test10 0m setup -a "filter=ansible_local"`获取自定义信息。
  2. debug用于输出调试信息,引用在远程主机收集的变量信息anbile_memory_mb.real,yaml通用的变量引用方式。

    1
    2
    3
    4
    5
    6
    7
    8
    - hosts: host_all
    vars:
    testvar: value of test variable
    tasks:
    - name: debug demo
    debug:
    var: testvar
    msg: "Value of testvar is : {{testvar}}"
    1
    获取远程主机的这些变量不止为了用于输出,我们可以对这些数值进行判断,是否符合我们的要				求,然后执行下一步动作。
  3. 注册变量:使用register接收task执行完返回的变量即为注册变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ---
    - hosts: host_all
    tasks:
    - name: test shell
    shell: "echo test > /var/testshellfile"
    register: testvar
    - name: shell module return values
    debug:
    msg: "{{testvar.cmd}}" # 调用task执行后的注册变量
  1. 交互式接收标准输入并写入变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    ---
    - hosts: host10
    tasks:
    vars_prompt:
    - name: "your_name"
    prompt: "Input username"
    def1: admin
    default: def1 # 没有输入使用默认值
    - name: "your_pass"
    prompt: "Input your password"
    private: no
    confirm: yes # 提示用户输入两遍密码
    encrypt: "sha512_crypt" # 使用sha512算法对输入的值进行哈希,使用该功能需要先安装passlib库:pip install passlib
    tasks:
    - name: create user
    user:
    name: "{{your_name}}"
    password: "{{your_pass}}"
    - name: output vars
    debug:
    msg: Your name is {{your_name}},You are {{your_age}} years old.
  1. 外部变量:在playbook中引用未定义的变量,可以在执行playbook时指定ansible-playbook cmdvar.yml --extra-vars "key=value"

    通过json格式传入稍微复杂一点的变量。

    1
    ansible-playbook cmdvar.yml -e '{"countlist":["one","two","three"]}'

    在play中如果要引用列表变量终中的指定值时,有如下两种语法:

    1
    2
    {{contlist[0]}} 
    {{contlist.0}}
  2. ansible/hosts文件配置主机变量或者主机组变量。

    1
    2
    3
    4
    5
    6
    [testB]
    test10 ansible_host=172.17.9.10
    test11 ansible_host=172.17.9.11
    [testB:vars]
    testB_group_var1='group var test'
    testB_group_var2='grup var test2'
  3. set_fact模块定义变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ---
    - hosts:
    remote_user: root
    vars:
    testva1: test1_string
    tasks:
    - shell: "echo test2_string"
    register: shellreturn
    - set_fact:
    testsf1: "{testvar1}"
    testsf2: "{{shellreturn.stdout}}" # 将注册变量赋值给testsf2
    - debug:
    msg: "{{testsf1}} {{testsf2}}"

    set_fact变量类似“全局”变量,跟每一个play执行之前都会执行”[Gathering Facts]”的默认任务所收集的fact内置变量一样,这个全局变量可以在之后的所有play中被引用。注册变量也是“全局变量”。

  4. hostvars引用其他主机的fact变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ---
    - name: "play 1: Gather facts of test10"
    hosts: test10
    remote_user: root

    - name: "play2: Get facts of test10 when operation on test20"
    hosts: test20
    remote_user: root
    tasts:
    - debug:
    msg: "{{hostvars.test10.ansible_eth0.ipv4}}"
    # "{{hostvars['test10'].ansible_eth0.ipv4}}"

    如果A主机引用B主机的facts,前提是ansible已经收集到B主机的facts才能供A使用,还记不记得每 个play都要执行的默认task”[[Gathering Facts]”,上面我们定义的play1中没有任何task,但是ansible依然会执行默认的收集facts的task,如果将play1删掉,则报错。还可以使用收集注册变量、hosts中的主机变量、组变量…
    默认是不允许跨主机引用vars: [“key1”:”value1”]这种在剧本中定义的主机变量,但是可以使用set_fact字段将其变为全局变量,就可以被hostvars引用了。即通过set_fact结合hostvars的方式,实现跨play获取其他主机中的变量信息的功能。

  5. 内置变量

    • 以列表形式返回当前play中所有的主机名;
    • 以列表的形式返回hosts中定义的所有主机清单,返回指定组;
    • 返回主机所在组名称;
  6. vars_files引入变量文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ---
    - hosts: group1
    remote_user: root
    vars_files:
    - /root/test/test/bar
    tasks:
    - debug:
    msg: "{{ testvar1 }}, {{ testvar2 }}"
    - lineinfile:
    path: "/root/test/test/bar"
    line: "testvar: ccc"
    - debug:
    msg: "{{ testvar1 }}, {{ testvar2 }}, {{ testvar3 }}"

    执行的结果是变量并没有被打印出来,原因是在变量文件写入之后并没有再次读取变量文件。有什么办法可以动态加载变量文件呢,include_varsinclude_vars还可以通过name字段将整个文件的变量赋值给另一个变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    ---
    - hosts: group1
    remote_user: root
    vars_files:
    - /root/test/test/bar
    tasks:
    - debug:
    msg: "{{ testvar1 }}, {{ testvar2 }}"
    - lineinfile:
    path: "/root/test/test/bar"
    line: "testvar: ccc"
    - include_vars:
    file: /root/test/test/bar
    # dir: /root/test/
    # file_matching: ["^var.*",test.yaml] # 只加载指定的变量文件
    # ignore_files: ["^var_.*",varfile.yaml] # 从上述匹配到的中排除指定变量文件
    name: varfile
    - debug:
    msg: "{{ varfile.testvar1 }}"

    include_vars除了可以引入变量文件外,还可以直接使用dir引入目录下所有以.yaml .yml .json结尾的所有文件变量,当然也可以通过正则表达式加载指定变量文件,而且是递归加载,depth:1指定递归深度,要求子目录符合上述要求,否则报错。

    如果我么你想值本次任务加入了哪些变量文件,通过如下方法:

    1
    2
    3
    4
    5
    6
    tasks:
    - include_vars:
    dir: /root/test/test/
    register: return_val
    - debug:
    msg: "{{ return_val.ansible_included_var_files}}"

    使用上述方式还可以加载一个没有缩进和换行的json文件,以可读格式输出。

标签tag

如果只想执行playbook的某些task时,或者执行不执行哪些任务时,可以给task打tag,task的tag继承hosts的tag,他们都可以拥有多个tag。只需要在执行的时候ansible-playbook --tags=tag1 testtag.yml加上该参数就好了。ansible预置的5种特殊的tag:

  • always
  • never
  • tagged
  • untagged
  • all
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
---
- hosts: node02
vars:
nginx:
conf80: /etc/nginx/conf.d/80.conf
conf8080: /etc/nginx/conf.d/8080.conf
vars_files:
- /ansible/nginx_vars.yml
remote_user: root
tasks:
- name: Modify the configuration
tags:
- t1
lineinfile:
path=/etc/nginx/conf.d/test.com.conf
regexp="listen(.*)8080(.*)"
line="listen\1 8080\2"
backrefs=yes
backup=yes
notify:
restart nginx
- meta: flush_handlers

- name: create config file
tags: tag1,tag2
file:
path: '{{ nginx.conf80 }}'
state: file

handlers:
- name: restart nginx
service:
name=nginx
state=restarted
- name: stoped nginx
service:
name: nginx
state: restart

循环(with_item)

反手就是一个demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
- hosts: test10
tasts:
- name: "copy files to test10"
copy:
src={{ item.src }}
dest={{ item.dest }}
with_items;
- { src: '/etc/ansible/roles/etcd/templates/ca-config.json.j2' , dest: '/etc/kubernetes/pki/cfssl/ca-config.json'}
- {src: '/etc/ansible/roles/etcd/templates/ca-csr.json.j2' , dest: '/etc/kubernetes/pki/cfssl/ca-csr.json'}
- {src: '/etc/ansible/roles/etcd/templates/client.json.j2' , dest: '/etc/kubernetes/pki/cfssl/client.json'}
- {src: '/etc/ansible/roles/etcd/templates/member1.json.j2' , dest: '/etc/kubernetes/pki/cfssl/member1.json'}
- {src: '/etc/ansible/roles/etcd/templates/server.json.j2' , dest: '/etc/kubernetes/pki/cfssl/server.json'}
- {src: '/etc/ansible/roles/etcd/templates/kubeletonce.service.j2' , dest: '/usr/lib/systemd/system/kubeletonce.service'}
  1. 循环执行shell模块的返回值会追加放到“results”这个返回值中,所以我们也可以通过“results“关键字获取每次执行后的返回值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ---
    - hosts: test10
    tasks:
    - name: "play 1"
    shell: "{{item}}"
    with_items:
    - "ls /opt"
    - "ls /home"
    register: returnvalue
    - debug:
    msg: "{{item.stdout}}"
    with_items: "{{returnvalue.results}}"
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ---
    - hosts: test10
    tasks:
    - shell: "{{item}}"
    with_items:
    - "ls /opt"
    - "ls /home"
    - debug:
    msg:
    "{% for i in returnvalue.results %}
    {{ i.stdout }}
    {% endfor %}"

    上面的例子使用的是jinja2语言中的for循环语法,jinja2是一种模板语言,jinja2是一个基于python的模板引擎。

  1. with_items

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    # 第一种语法格式
    - hosts: node10
    vars:
    certdir: "/etc/kubernetes/pki/"
    tasks:
    - shell: "{{item}}"
    with_items:
    - "cat {{certdir}}ca.crt"
    - "cat {{certdir}}ca.key"
    # 第二种语法格式
    with_items: [ {{certdir}}ca.crt, {{certdir}}ca.key ]

    - hosts: group1
    remote_user: root
    gather_facts: no
    vars:
    - cert:
    - "/etc/kubernetes/pki/"
    - "/root/cfssl/"
    tasks:
    - shell: "ls {{ item }}"
    register: returnvar
    with_items:
    - "{{ cert }}"
    - debug:
    msg: "{{ item }}"
    with_items:
    - "{{ returnvar.results }}"
  1. with_list

    1
    2
    3
    4
    5
    6
    7
    8
    9
    - hosts: node01
    remote_user: root
    gather_facts: no
    tasks:
    - debug:
    msg: "{{item}}"
    with_list:
    - [ 1, 2, 3 ]
    - [ a, b ]

    执行结果:

    1545130892990

    with_list改成with_itms的结果:

    1545130942726

    可以看得出来with_items是将所有元素放在一个平面当中挨个循环,而with_list只会循环最外层列表。

  2. with_flattened

    1
    2
    3
    4
    5
    6
    7
    8
    - hosts: group1
    remote_user: root
    tasks:
    - debug:
    msg: "{{ item }}"
    with_flattened:
    - [ 1, 2, 3 ]
    - [ a, b ]

    效果和with_items是完全一样的。

  3. with_tagether

    1
    2
    3
    4
    5
    6
    7
    8
    - hosts: group1
    remote_user: root
    tasks:
    - debug:
    msg: "{{ item }}"
    with_together:
    - [ 1, 2, 3 ]
    - [ a, b ]

    执行结果:

    1545131438550

  4. with_cartesian

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ---
    - hosts: group1
    remote_user: root
    tasks:
    - name: "recursion create directory"
    file:
    state: directory
    path: "~/test/test/{{ item.0 }}/{{ item.1 }}"
    with_cartesion:
    - [ a, b, c ]
    - [ test1, test2 ]

    1545133040672

  5. with_nested

    效果同上!

  6. with_indexed_items

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ---
    - hosts: node01
    remote_user: root
    tasks:
    - name "show items index"
    debug:
    msg: "{{ item }}"
    with_indexed_items:
    - [ test1, test2 ]
    - [ test3, [ test4, test5 ]]
    - [ test6 ]

    with_indexed_items不会像with_flattened一样将嵌套列表完全扁平化,知识扁平化首层嵌套,第二层的嵌套列表依然当做一个整体元素被打印出来。

  7. 设定循环起始点和步长

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ---
    - hosts: group1
    remote_user: root
    tasks:
    - name: "create directory on oushu"
    file:
    state: directory
    path: "/root/test/test{{ item }}"
    with_sequence:
    start=2
    end=6
    stride=2

    with_sequence还可以指定stride为负数,即end小于start。还可以格式化字符串format。

  8. with_random_choice

    1
    2
    3
    4
    with_random_chice:
    - 1
    - 2
    - 3

    随机返回一个列表。

  9. with_dirt

    1
     
  10. with_subelements

  11. with_file(针对ansible主机)

    循环查看文件内容。

  12. with_filelob(针对ansible主机)

    1
    2
    3
    with_filelob:
    - /test/test*
    - /etc/systemd/system/*.???????

    在指定目录中匹配文件名(不匹配目录)。

条件判断when

1
-
比较运算符 含义
== 比较两个对象是否相等,相等为真
!= 比较两个对象是否不等,不等为真
> 比较两个值的大小,右边小为真
< 比较两个值的大小,左边小为真
>= 比较两个值的大小,如果右边的值小或者左右相等,则为真
<= 比较连个值的大小,如果左边的值小或者左右相等,则为真
逻辑运算符 含义
and 逻辑与,同时为真,返回真
or 逻辑或,任意一个为真,返回真
not 取反
() 将一组操作包装在一起
  1. 写一个判断shell指令是否真确执行的剧本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ---
    - hosts: group1
    remote_user: root
    tasks:
    - name: "task: 1"
    shell: "ls /root/testabc"
    register: return
    ignore_errors: true
    - name: "task: 2"
    debug:
    msg: "Command Execution Successful"
    when: retuen.rc == 0
    - name: "task: 3"
    debug:
    msg: "Command Execution Failed"
    when: retuen.rc != 0
  2. 条件判断与tests

    1
    2
    3
    4
    5
    6
    vars: 
    - testvar: "/root/test.config"
    task:
    - debug:
    msg: "file is exists"
    when: not testvar is exists # 这里同样支持逻辑运算符

    tests测试文件是否存在的时候,也是只针对ansible主机路径,与目标主机没有关系。

    判断变量的一些tests:
    defined:判断变量是否已经定义,已经定义则返回真
    undefind:判断变量是否已经定义,未定义则返回真
    none:不判断变量值是否为空,如果变量已经定义,但变量值为空,则返回真

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    - hosts: group1
    remote_user: root
    vars:
    testvar: "test"
    testvar1:
    tasks:
    - debug:
    msg: "Variable is defined"
    when: testvar is defined
    - debug:
    msg: "Variable is undefined"
    when: testvar1 is undefined
    - debug:
    msg: "Varibale is none"
    when: testvar1 is none
  3. 判断执行结果的tests

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    ---
    - hosts: group1
    remote_user: root
    vars:
    doshell: "yes"
    tasks:
    - shell: "cat /root/testabc"
    register: returnmsg
    ignore_errors: true
    - debug:
    msg: "Success"
    when: returnmsg is success
    - debug:
    msg: "Failed"
    when: returnmsg is failure
    - debug:
    msg: "Changed"
    when: returnmsg is change
    - debug:
    msg: "Skip"
    when: returnmsg is skip
  4. 判断路径的tests

    代码就不写了,相对简单。

    file:判断路径是否是一个文件,则为真
    directory:判断路径是否是一个目录,则为真
    link:判断路径是否是一个连接文件,则为真
    mount:判断路径是否是一个挂载点,则为真

    注:上述test是2.6版本中的,在2.5之前某些test需要加上is_前缀

  5. 判断字符串的tests

    lower:字符串为纯小写,则为真
    upper:字符串为纯大写,则为真

    这个也是相对简单,字符串可以放在变量中来测试

  6. 判断整除的tests

    even:判断数值是否为偶数,是偶数则为真
    odd:判断数值是否为技术,是奇数则为真
    divisibleby(num):判断是否可以整除指定的数值,如果除以指定的值以后余数为0,则返回真

    subset:判断一个list是不是另一个list的子集,是另一个list的子集时返回真
    superset:判断一个list是不是另一个list的父集,是另一个list的父集时返回真
    string:潘帆对象是否是一个字符串,是字符串则返回真

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    ---
    - hosts: group1
    remote_user: root
    vars:
    a:
    - 2
    - 5
    b: [ 1,2,3,4,5 ]
    tasks:
    - debug:
    msg: "A is subset of B"
    when: a is subset(b)
    - debug:
    msg: "B is superset of A"
    when: b is superset(a)

异常处理block

1
2
3
4
5
6
7
8
9
---
- hosts: group1
remote_user: root
tasks:
- block:
- shell: 'ls /foo'
rescue:
- debug:
msg: "Error"

rescue字段会处理同级block字段中的异常,如果block中没有报错则不执行rescue中的步骤。
block当中只有单个任务时,看起来和failed没有什么区别,但是block还是有优势的,blockrescue中均可以由多个任务。
rescue同级别的还有always字段,一看就知道是block字段中的任务无论成功还是失败都将执行always中任务。

  1. filed_when

    当符合条件判断则退出剧本。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ---
    - hosts:
    remote_user: root
    - debug:
    msg: "I execute normally"
    - shell: "echo 'This is string for testing error'"
    register: return_value
    failed_when: '"error" in return_value.stdout'
    - debug:
    msg: "i never execute,Bucause the playbook has stopped"
  2. changed_when

    faled_when是将符合条件的任务设置为failed状态,那么changed_when就是将符合条件的任务设置为changed状态。除了上述功能外,满足条件让对应的任务永远不能是changed状态。chagne_when=true。changed_when还可以配合handler使用,

过滤器

跟字符串操作相关的过滤器

字符串相关 含义
upper 转换纯大写[列表适用]
lower 转换纯小写[列表适用]
reverse 将字符创翻转
first 返回第一个字符,[列表适用]
last 返回最后一个字符,[列表适用]
length 返回字符创长度,与count等效,[列表适用]
list 将字符串转换成列表,每个字符串为元素
shuffle 将字符创转换成列表,并打乱顺序,[列表适用]
数字相关 含义
int() 转换字整型数字,小括号可设置默认值int(default=6)
float() 浮点型小数,小括号内可以直接写默认值
abs 返回绝对值
round() 四舍五入,小括号内可以执行保留小数点后几位
random() 返回一个随机数`10 random(start=5,step=3)`
列表相关 含义
min 返回列表中的最大值
max 返回列表中的最小值
sort(reverse=true) 升序排列,降序(reverse=true)
sum 返回纯数字非嵌套列表中的所有数字的和
flatten(levels=1) “拉平”嵌套列表,小括号可指定拉平几层嵌套
join() 将列表中的元素合并成一个字符串,小括号可指定元素之间的间隔
random() 从列表中随机返回一个元素,小括号指定随机种子
union() `list1 union(list2)`返回两个列表的并集
intersect() 返回两个列表的交集
difference() `list1 difference(list2)`返回存在于list1但不存在list2中的元素
symmetric_difference() 返回两个列表的并集,且不包含交集
1
{"logs":[{"domainName":"asia1.cdn.test.com","files":[{"dateFrom":"2018-09-05-0000","dateTo":"2018-09-05-2359","logUrl":"http://log.testcd.com/log/zsy/asia1.cdn.test.com/2018-09-05-0000-2330_asia1.cdn.test.com.all.log.gz?wskey=XXXXX5a","fileSize":254,"fileName":"2018-09-05-0000-2330_asia1.cdn.test.com.all.log.gz","fileMd5":"error"}]},{"domainName":"image1.cdn.test.com","files":[{"dateFrom":"2018-09-05-2200","dateTo":"2018-09-05-2259","logUrl":"http://log.testcd.com/log/zsy/image1.cdn.test.com/2018-09-05-2200-2230_image1.cdn.test.com.cn.log.gz?wskey=XXXXX1c","fileSize":10509,"fileName":"2018-09-05-2200-2230_image1.cdn.test.com.cn.log.gz","fileMd5":"error"},{"dateFrom":"2018-09-05-2300","dateTo":"2018-09-05-2359","logUrl":"http://log.testcd.com/log/zsy/image1.cdn.test.com/2018-09-05-2300-2330_image1.cdn.test.com.cn.log.gz?wskey=XXXXXfe","fileSize":5637,"fileName":"2018-09-05-2300-2330_image1.cdn.test.com.cn.log.gz","fileMd5":"error"}]}]}

一个没有缩进的json文件,返回数据总所有的logUrl:

1
2
3
4
5
6
7
8
9
---
- hosts: group1
remote_user: root
vars_files:
- /root/test/test/test1.json
tasks:
- debug:
msg: "{{ item }}"
with_items: "{{ logs | json_query('files[*].logUrl') }}"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
---
- hosts: test70
  remote_user: root
  gather_facts: no
  tasks:
  ######################################################################
  #在调用shell模块时,如果引用某些变量时需要添加引号,则可以使用quote过滤器代替引号
  #示例如下,先看示例,后面会有注解
  - shell: "echo {{teststr | quote}} > /testdir/testfile"
    vars:
      teststr: "a\nb\nc"
  #上例中shell模块的写法与如下写法完全等效
  #shell: "echo '{{teststr}}' > /testdir/testfile"
  #没错,如你所见,quote过滤器能够代替引号
  #上例中,如果不对{{teststr}}添加引号,则会报错,因为teststr变量中包含"\n"转义符
  ######################################################################
  #ternary过滤器可以实现三元运算的效果 示例如下
  #如下示例表示如果name变量的值是John,那么对应的值则为Mr,否则则为Ms
  #简便的实现类似if else对变量赋值的效果
  - debug: 
      msg: "{{ (name == 'John') | ternary('Mr','Ms') }}"
    vars:
      name: "John"
  ######################################################################
  #basename过滤器可以获取到一个路径字符串中的文件名
  - debug:
      msg: "{{teststr | basename}}"
    vars:
      teststr: "/testdir/ansible/testfile"
  ######################################################################
  #获取到一个windows路径字符串中的文件名,2.0版本以后的ansible可用
  - debug:
      msg: "{{teststr | win_basename}}"
    vars:
      teststr: 'D:\study\zsythink'
  ######################################################################
  #dirname过滤器可以获取到一个路径字符串中的路径名
  - debug:
      msg: "{{teststr | dirname}}"
    vars:
      teststr: "/testdir/ansible/testfile"
  ######################################################################
  #获取到一个windows路径字符串中的文件名,2.0版本以后的ansible可用
  - debug:
      msg: "{{teststr | win_dirname}}"
    vars:
      teststr: 'D:\study\zsythink'
  ######################################################################
  #将一个windows路径字符串中的盘符和路径分开,2.0版本以后的ansible可用
  - debug:
      msg: "{{teststr | win_splitdrive}}"
    vars:
      teststr: 'D:\study\zsythink'
  #可以配合之前总结的过滤器一起使用,比如只获取到盘符,示例如下
  #msg: "{{teststr | win_splitdrive | first}}"
  #可以配合之前总结的过滤器一起使用,比如只获取到路径,示例如下
  #msg: "{{teststr | win_splitdrive | last}}"
  ######################################################################
  #realpath过滤器可以获取软链接文件所指向的真正文件
  - debug:
      msg: "{{ path | realpath }}"
    vars:
      path: "/testdir/ansible/testsoft"
  ######################################################################
  #relpath过滤器可以获取到path对于“指定路径”来说的“相对路径”
  - debug:
      msg: "{{ path | relpath('/testdir/testdir') }}"
    vars:
      path: "/testdir/ansible"
  ######################################################################
  #splitext过滤器可以将带有文件名后缀的路径从“.后缀”部分分开
  - debug:
      msg: "{{ path | splitext }}"
    vars:
      path: "/etc/nginx/conf.d/test.conf"
  #可以配置之前总结的过滤器,获取到文件后缀
  #msg: "{{ path | splitext | last}}"
  #可以配置之前总结的过滤器,获取到文件前缀名
  #msg: "{{ path | splitext | first | basename}}"
  ######################################################################
  #to_uuid过滤器能够为对应的字符串生成uuid
  - debug:
      msg: "{{ teststr | to_uuid }}"
    vars:
      teststr: "This is a test statement" 
  ######################################################################
  #bool过滤器可以根据字符串的内容返回bool值true或者false
  #字符串的内容为yes、1、True、true则返回布尔值true,字符串内容为其他内容则返回false
  - debug:
      msg: "{{ teststr | bool }}"
    vars:
      teststr: "1"
  #当和用户交互时,有可能需要用户从两个选项中选择一个,比如是否继续,
  #这时,将用户输入的字符串通过bool过滤器处理后得出布尔值,从而进行判断,比如如下用法
  #- debug:
  #    msg: "output when bool is true"
  #  when: some_string_user_input | bool
  ######################################################################
  #map过滤器可以从列表中获取到每个元素所共有的某个属性的值,并将这些值组成一个列表
  #当列表中嵌套了列表,不能越级获取属性的值,也就是说只能获取直接子元素的共有属性值。
  - vars:
      users:
      - name: tom
        age: 18
        hobby:
        - Skateboard
        - VideoGame
      - name: jerry
        age: 20
        hobby:
        - Music
    debug:
      msg: "{{ users | map(attribute='name') | list }}"
  #也可以组成一个字符串,用指定的字符隔开,比如分号
  #msg: "{{ users | map(attribute='name') | join(';') }}"
  ######################################################################
  #与python中的用法相同,两个日期类型相减能够算出两个日期间的时间差
  #下例中,我们使用to_datatime过滤器将字符串类型转换成了日期了类型,并且算出了时间差
  - debug:
      msg: '{{ ("2016-08-14 20:00:12"| to_datetime) - ("2012-12-25 19:00:00" | to_datetime) }}'
  #默认情况下,to_datatime转换的字符串的格式必须是“%Y-%m-%d %H:%M:%S”
  #如果对应的字符串不是这种格式,则需要在to_datetime中指定与字符串相同的时间格式,才能正确的转换为时间类型
  - debug:
      msg: '{{ ("20160814"| to_datetime("%Y%m%d")) - ("2012-12-25 19:00:00" | to_datetime) }}'
  #如下方法可以获取到两个日期之间一共相差多少秒
  - debug:
      msg: '{{ ( ("20160814"| to_datetime("%Y%m%d")) - ("20121225" | to_datetime("%Y%m%d")) ).total_seconds() }}'
  #如下方法可以获取到两个日期“时间位”相差多少秒,注意:日期位不会纳入对比计算范围
  #也就是说,下例中的2016-08-14和2012-12-25不会纳入计算范围
  #只是计算20:00:12与08:30:00相差多少秒
  #如果想要算出连带日期的秒数差则使用total_seconds()
  - debug:
      msg: '{{ ( ("2016-08-14 20:00:12"| to_datetime) - ("2012-12-25 08:30:00" | to_datetime) ).seconds }}'
  #如下方法可以获取到两个日期“日期位”相差多少天,注意:时间位不会纳入对比计算范围
  - debug:
      msg: '{{ ( ("2016-08-14 20:00:12"| to_datetime) - ("2012-12-25 08:30:00" | to_datetime) ).days }}'
  ######################################################################
  #使用base64编码方式对字符串进行编码
  - debug:
      msg: "{{ 'hello' | b64encode }}"
  #使用base64编码方式对字符串进行解码
  - debug:
      msg: "{{ 'aGVsbG8=' | b64decode }}"
  #######################################################################
  #使用sha1算法对字符串进行哈希
  - debug:
      msg: "{{ '123456' | hash('sha1') }}"
  #使用md5算法对字符串进行哈希
  - debug:
      msg: "{{ '123456' | hash('md5') }}"
  #获取到字符串的校验和,与md5哈希值一致
  - debug:
      msg: "{{ '123456' | checksum }}"
  #使用blowfish算法对字符串进行哈希,注:部分系统支持
  - debug:
      msg: "{{ '123456' | hash('blowfish') }}"
  #使用sha256算法对字符串进行哈希,哈希过程中会生成随机"盐",以便无法直接对比出原值
  - debug:
      msg: "{{ '123456' | password_hash('sha256') }}"
  #使用sha256算法对字符串进行哈希,并使用指定的字符串作为"盐"
  - debug:
      msg: "{{ '123456' | password_hash('sha256','mysalt') }}"
  #使用sha512算法对字符串进行哈希,哈希过程中会生成随机"盐",以便无法直接对比出原值
  - debug:
      msg: "{{ '123123' | password_hash('sha512') }}"
  #使用sha512算法对字符串进行哈希,并使用指定的字符串作为"盐"
  - debug:
      msg: "{{ '123123' | password_hash('sha512','ebzL.U5cjaHe55KK') }}"
  #如下方法可以幂等的为每个主机的密码生成对应哈希串
  #有了之前总结的过滤器用法作为基础,你一定已经看懂了
  - debug:
      msg: "{{ '123123' | password_hash('sha512', 65534|random(seed=inventory_hostname)|string) }}"
CATALOG
  1. 1. Handler字段
  2. 2. 变量
  3. 3. 标签tag
  4. 4. 循环(with_item)
  5. 5. 条件判断when
  6. 6. 异常处理block
  7. 7. 过滤器