5-playbook拓展

ansible

Handlers

首先我们设定以这个场景。
想要将test3主机中/home/test.txt文件中的我们现在学习XXX修改为我们现在学习ansible,并打印修改后的结果。
test.txt文本

1
2
3
4
5
6
7
1
2
3
我们现在学习XXX
3
2
1

编写的playbook为

1
2
3
4
5
6
7
8
9
10
--- 
- hosts : test3
tasks :
- name: 修改test3主机中/home/test.txt文件中的`我们现在学习XXX`修改为`我们现在学习ansible`
lineinfile :
path : /home/test.txt
regexp : "我们现在学习XXX"
line : "我们现在学习ansible"
- name : 将/home/test.txt中的内容输出到/home/test1.txt
shell: cat /home/test.txt > /home/test1.txt

执行结果
可以看出两个任务都执行成功了。
如果要再执行一次该playbook呢。
执行结果
task1因为文件状态与playbook中的状态是一致的,所以为绿的;但是task2为黄色,虽然也执行成功,最后的状态与我们的设定是一致的,但是相当于白执行了一次。在该例子中对结果或者过程影响不大,但是当我们需要修改某个服务的配置文件并进行重启服务时,就会对想先关的业务造成影响。
handlers可以对这种问题进行解决,简单来说handlers就是另一种tasks,handlers中的任务会被tasks中的任务进行调用。例如task1调用handler1,当task1执行状态为黄色时,handler1才会被执行,当task1执行状态为绿色,即task1没有被真正被执行时,handlers不会被执行。
对上面的palybook进行修改,notify执指向handlers中的任务(即handlers中任务的name)。

1
2
3
4
5
6
7
8
9
10
11
12
--- 
- hosts : test3
tasks :
- name: 修改test3主机中/home/test.txt文件中的`我们现在学习XXX`修改为`我们现在学习ansible`
lineinfile :
path : /home/test.txt
regexp : "我们现在学习XXX"
line : "我们现在学习ansible"
notify : 重定向输出
handlers :
- name : 重定向输出
shell: cat /home/test.txt > /home/test1.txt

然后我们对/home/test.txt进行还原,然后重新执行playbook。
重新执行
可以看出task和handler都执行了。
再执行一边。
重新执行2
可以看到只有task被执行了,handler没有被执行。

Handlers进阶

notify调用多个handler

1
2
3
notify : 
- testhandlers1
- testhandlers2

mate模块 (mate:flush_handlers)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
- hosts : test3
tasks :
- name : testtask1
command : ls /home/
notify : testhandlers2
- name : testtask2
command : ls /home/
notify : testhandlers1
handlers :
- name : testhandlers1
command : ls /home/yyg
- name : testhandlers2
command : ls /home/yyg

多个handler
默认情况下handler执行的顺序与handler在playbook的handlers模块定义的顺序是相同的,与”handler被notify”的顺序无关。所有task执行完毕后,才会执行各个handler,并不是执行完某个task后,立即执行对应的handler。若要执行完task后马上执行对应handler,则需要使用mate模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
- hosts : test3
tasks :
- name : testtask1
command : ls /home/
notify : testhandlers2
- meta : flush_handlers
- name : testtask2
command : ls /home/
notify : testhandlers1
handlers :
- name : testhandlers1
command : ls /home/yyg
- name : testhandlers2
command : ls /home/yyg

mate
在testtask1和testtask2之间有一个mate任务,meta任务能够影响ansible内部运行方式,meta : flush_handlers表示立即执行之前的task所对应handler,mate之前有多个notify调用时,被调用的handler的执行顺序还是与handlers模块的顺序一致。

listen模块

使用listen对handler进行“分组”,使用notify调用该组时将会调用该组下的成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
---
- hosts : test3
tasks :
- name : test1
command : ls /home
notify : listenTest
handlers :
- name : handler1
listen : listenTest
command : ls /home/yyg
- name : handler2
listen : listenTest
command : ls /home/yyg

listen

变量

playbook中的变量名以英文大小写字母开头,中间可以包含下划线和数字。
在Inventory文件中以=来为变量赋值,在playbook或者变量配置文件中以:来为变量赋值。

playbook变量

  1. 运行playbook时指定额外的变量

    1
    2
    ansible-playbook test.yml -e "newVar=test"  #指定额外的变量
    ansible-playbook test.yml -e "@newVar.yml" #指定变量配置文件
  2. playbook中定义变量
    使用vars来进行定义变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ---
    - hosts : test3
    vars :
    var1 : test1
    var2 : test2
    #- var1 : test1 这样定义也是可以的
    #- var2 : test2
    tasks :
    - name : 变量测试
    debug :
    msg : var1={{var1}} var2={{var2}}

    debug模块的msg参数可以自定义输出;而var参数可以直接输出变量信息,且不需要使用两个括号进行引起

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ---
    - hosts : test3
    vars :
    - var1 : test1
    tasks :
    - name : 变量测试
    debug :
    var :
    var1

    也可以在playbook中引用变量文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #palybook文件
    ---
    - hosts : test3
    vars_files :
    - vars.yml
    - vars.yml
    tasks :
    - name : 变量文件测试
    debug :
    msg : "{{var1}}"
    1
    2
    ---
    var1 : test

    在使用的方式引用变量{{var1}}时,当{{var1}}处于开头位置需要加上引号,当{{var1}}前有字符串时则可以不加双引号。
    除了使用来进行引用变量,还可以使用=来引用变量,使用=来引用变量时可以不用考虑加不加双引号。

    1
    2
    3
    4
    5
    6
    7
    8
    ---
    - hosts : test3
    vars :
    var1 : test1
    tasks :
    - name : 变量测试
    debug :
    msg = {{var1}}

    在playbook中还可以以类似”属性”的方式定义变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ---
    - hosts : test3
    vars :
    people :
    name : xiaoming
    age : 20
    tasks :
    - name : 变量测试
    debug :
    msg : 名字为{{people.name}},年龄为{{people.age}}

注册变量

注册变量就是将操作的结果,包括标准输出和标准错误输出,保存到变量中。在同一个yml中操作同一台主机时,前一个play定义了register变量,后面的同一台主机中也可以调用到该register变量。

1
2
3
4
5
6
7
8
9
--- 
- hosts : test3
tasks:
- name : registerTest
command : hostname
register : hostname
- name : 输出注册变量信息
debug :
msg : "{{hostname}}"

注册变量
这时就可以使用类似这样的方式引用详细的值

Facts(收集系统信息)

运行playbook之前,ansible默认会先抓取playbook指定的所有主机的系统信息,这些信息就成为facts。
playbook执行结果开头
facts信息包含远程主机的CPU、IP、磁盘空间、操作系统信息等等。可以根据这些信息来判断是否进行下一步任务,或者将这些信息写入到某个配置中。
这些信息可以使用setup模块来获取

1
ansible test3 -m setup

对于使用不到这些信息的playbook来说收集facts的过程是可以跳过的。

1
2
3
---
- hosts : test3
gather_facts : no

facts变量

定义远程主机的facts变量,需要在远程主机的/etc/ansible/facts.d目录下创建INI风格的xxx.fact文件。

1
2
3
4
#/etc/ansible/facts.d/test.fact文件
[test]
user=test
pwd=/etc/ansible/facts.d

facts变量
filter=ansible_local 表示将ansible_local(本地facts)从所有facts中过滤出来,也可以使用*local类似这样的通配符进行匹配。
setup收集的本地fact变量是从/etc/ansible/facts.d目录下的文件中收集,当我们的facts变量文件是在远程主机的其他目录下时,需要指定文件路径

1
2
#当facts变量文件是在/tmp目录下
ansible test3 -m setup -a 'fact_path=/tmp'

通过set_fact定义变量

可以使用set_fact模块在tesk中定义变量。在同一个yml中操作同一台主机时,前一个play定义了set_fact变量,后面的同一台主机中也可以调用到该set_fact变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
- hosts : test3
tasks :
- name : set_fact测试
set_fact :
test_var : "testvar"
- name : 测试输出
debug :
msg : "{{test_var}}"
- hosts : test3
tasks :
- name : 测试set_fact变量
debug :
msg : 输出上一个play中的test_var= {{test_var}}

set_fact

提示用户输入信息并写入到变量

实现交互式输入信息,并将信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
- hosts: test3
remote_user: root
vars_prompt:
- name: "your_name" #输入的值存入的变量
prompt: "What is your name" #输入提示
private: no #表示显示输入
- name: "your_age"
prompt: "How old are you"
private: no
tasks:
- name: output vars
debug:
msg: Your name is {{your_name}},You are {{your_age}} years old.

交互输入
这样在输入值的时候就可以看到输入的确切的值,若是不想显示则将private设置为yes(默认选项)。

内置变量

ansible_version

内置变量ansible_version可以获取到ansible的版本号

1
ansible test3 -m debug -a "msg={{ansible_version}}"

ansible_version

hostvars

hostvars可以在操作A主机时获取到B主机的信息。

  • 收集facts信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ---
    - hosts : test4
    name : play1 hostsname is test4

    - hosts : test3
    name : play2 hostsname is test3
    tasks :
    - debug :
    msg : hostvars['test4'].ansible_hostname:{{hostvars['test4'].ansible_hostname}}

    hostvars1
    play1并没有task,但是这并不代表play1是没有用的,正是运行过play1收集了test4的facts信息,在play2中才可以使用fast4的facts信息。

  • 收集注册变量、主机变量、组变量
    收集注册变量时,不需要像收集facts信息一样需要事先进行收集,同样的也可以收集在主机清单中配置的主机变量与组变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ---
    - hosts : test4
    tasks :
    - shell : "echo this is test4 "
    register : testvar
    - hosts : test3
    tasks :
    - debug :
    msg : "{{hostvars.test4.testvar}}"

    hostvars2

  • 收集定义变量
    在play中使用vars定义的变量是无法被hostvars收集的,但是可以通过set_fact进行定义,这样变量就可以像facts信息一样被收集。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ---
    - hosts : test4
    tasks :
    - set_fact :
    testvar : testvalue
    - hosts : test3
    tasks :
    - debug :
    msg : "{{hostvars.test4.testvar}}"

    hostvars3

inventory_hostname

inventory_hostname可以获取到被操作主机的主机名(并不是linux的主机名,而是在ansible管理端主机清单中的主机名)。如果配置清单中只是IP那么inventory_hostname获取到的则是IP。

1
2
#/home/ansible/hosts文件
testtest ansible_host=192.168.27.7
1
2
3
4
5
6
7
8
9
10
11
12
--- 
- hosts : testtest
tasks :
- name : 输出主机清单中的主机名
debug :
msg : "{{inventory_hostname}}"
- name : 定义操作主机的linux主机名
command : hostname
register : hostname
- name : 输出操作的主机的linux主机名
debug :
msg : "{{hostname.stdout}}"

inventory_hostname

inventory_hostname_short

与inventory_hostname类似,inventory_hostname_short返回的则是简短名称(主机清单主机名称“.”分割的第一段名称)

1
2
3
4
#/home/ansible/hosts文件
[test]
test.test3 ansible_host=192.168.27.7
192.168.27.8
1
ansible test -i /home/ansible/hosts -m debug -a "msg={{inventory_hostname_short}}"

inventory_hostname_short

play_hosts

plsy_hosts可以获取到当前play操作的所有主机的主机列表名称。

1
2
3
4
5
6
7
8
9
10
11
12
--- 
- hosts : test3
name : play1
tasks :
- debug :
msg : "{{play_hosts}}"

- hosts : test3 test4
name : play2
tasks :
- debug :
msg : "{{play_hosts}}"

play_hosts

groups

groups可以获取到主机清单中所有的组信息。

1
2
3
4
#/home/ansible/hosts文件
test4 ansible_host=192.168.27.8
[test]
test3 ansible_host=192.168.27.7
1
ansible test3 -i /home/ansible/hosts -m debug -a 'msg="{{groups}}"'

groups1
当然可以获取指定组的信息。

1
2
ansible test3 -i /home/ansible/hosts -m debug -a 'msg="{{groups.test}}"'
ansible test3 -i /home/ansible/hosts -m debug -a 'msg="{{groups.ungrouped}}"' #后去未分组的主机

group_names

获取当前操作主机在主机清单中的分组名。

1
2
3
4
5
#/home/ansible/hosts文件
[allhosts:children]
test
[test]
test3 ansible_host=192.168.27.7
1
ansible test3 -i /home/ansible/hosts -m debug -a 'msg="{{group_names}}"'

group_names
因为test3属于test分组,而test分组又属于allhosts分组。

inventory_dir

该变量可以获取到使用的inventory文件的位置。
inventory_dir