Ansible模块设计为具有幂等性。这表示,在正确编写的playbook中,playbook及其任务可以运行多次而不会改变受管主机,除非需要进行更改使受管主机进入所需的状态。
但在时候,在任务确实更改系统时,可能需要运行进一步的任务。例如,更改服务配置文件时可能要求重新加载该服务以便使其更改的配置生效。
处理程序是响应由其他任务触发的通知的任务。仅当任务在受管主机上更改了某些内容时,任务才通知其处理程序。每个处理程序具有全局唯一的名称,在playbook中任务块的末尾触发。如果没有任务通过名称通知处理程序,处理程序就不会运行。如果一个或多个任务通知处理程序,处理程序就会在play中的所有其他任务完成后运行一次。因为处理程序就是任务,所以可以在处理程序中使用他们将用于任何其他任务的模块。通常而言,处理程序被用于重新引导主机和重启服务。
处理程序可视为非活动任务,只有在使用notify语句显式调用时才会被触发。在下列代码片段中,只有配置文件更新并且通知了该任务,restart apache处理程序才会重启Apache服务器:
---
- name: create user
gather_facts: yes
hosts: 192.168.240.40
tasks:
- name: ddd
user: # 创建用户
name: ddd
state: present
notify: # notify语句指出该任务需要触发一个处理程序
- restart firewalld.service
handlers: # handlers关键字表示处理程序任务列表的开头
- name: fireawalll # 重启防火墙
service:
name: firewalld.service
state: restarted
在上面的例子中,restart apache处理程序只有在template任务通知已发生更改时才会触发。一个任务可以在其notify部分中调用多个处理程序。Ansible将notify语句视为数组,并且迭代处理程序名称:
---
- name: create user
gather_facts: yes
hosts: 192.168.240.40
tasks:
- name: ddd
user:
name: ddd
state: present
notify:
- restart firewalld.service
- restart httpd
handlers:
- name: stopped fireawalll
service:
name: firewalld.service
state: restarted
- name: stopped httpd
service:
name: httpd
state: restarted
使用处理程序时需要牢记几个重要事项:
处理程序用于在任务对受管主机进行更改时执行额外操作。它们不应用作正常任务的替代。
Ansible评估任务的返回代码,从而确定任务是成功还是失败。通常而言,当任务失败时,Ansible将立即在该主机上中止play的其余部分并且跳过所有后续任务。
但有些时候,可能希望即使在任务失败时也继续执行play。例如,或许预期待定任务有可能会失败,并且希望通过有条件地运行某项其他任务来修复。
Ansible有多种功能可用于管理任务错误。
默认情况下,任务失败时play会中止。不过,可以通过忽略失败的任务来覆盖此行为。可以在任务中使用ignore_errors关键字来实现此目的。
下列代码片段演示了如何在任务中使用ignore_errors,以便在任务失败时也继续在主机上执行playbook。例如,如果notapkg软件包不存在,则yum模块将失败,但若将ignore_errors设为yes,则执行将继续。
---
- name: shibei text
hosts: 192.168.240.40
tasks:
- name: install httpd
yum:
name: httpd0
state: present
ignore_errors: yes #为yes如果失败则忽略此任务
通常而言,如果任务失败并且play在该主机上中止,则收到play中早前任务通知的处理程序将不会运行。如果在play中设置force_handlers: yes关键字,则即使play因为后续任务失败而中止也会调用被通知的处理程序。
处理程序会在任务报告changed结果时获得通知,而在任务报告ok或failed结果时不会获得通知。
下列代码片段演示了如何在play中使用force_handlers关键字,以便在任务失败时也强制执行相应的处理程序:
---
- name: shibei text
hosts: 192.168.240.40
force_handlers: yes # 任务失败后强制执行处理程序
tasks:
- name: install httpd
yum: #下载httpd
name: httpd
state: present
notify: #创建成功启动防火墙
- started firewalld
- name: create user
user:
namee: dd #创建用户失败
state: present
handlers: #强制执行启动防火墙
- name: started firewalld
service:
name: firewalld
state: started
oot@localhost ansible]# ansible-playbook shibai.yml
PLAY [shibei text] ************************************************************************
TASK [Gathering Facts] ********************************************************************
ok: [192.168.240.40]
TASK [install httpd] **********************************************************************
changed: [192.168.240.40]
TASK [createuser]************************************************************************
fatal: [192.168.240.40]: FAILED! => {"changed": false, "msg": "Unsupported parameters for (user) module: namee Supported parameters include: append, authorization, comment, create_home, expires, force, generate_ssh_key, group, groups, hidden, home, local, login_class, move_home, name, non_unique, password, password_lock, profile, remove, role, seuser, shell, skeleton, ssh_key_bits, ssh_key_comment, ssh_key_file, ssh_key_passphrase, ssh_key_type, state, system, uid, update_password"} #提示失败错误信息
RUNNING HANDLER [started firewalld] *******************************************************
ok: [192.168.240.40]
PLAY RECAP ********************************************************************************
192.168.240.40 : ok=3 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
可以在任务中使用failed_when关键字来指定表示任务已失败的条件。这通常与命令模块搭配使用,这些模块可能成功执行了某一命令,但命令的输出可能指示了失败。
例如,可以运行输出错误消息的脚本,并使用该消息定义任务的失败状态。下列代码片段演示了如何在任务中使用failed_when关键字:
---
- name: test
hosts: "192.168.240.40"
tasks:
- name: create user
command: /opt/test.sh # 执行受管主机上的脚本
register: liu # 注册变量到result
failed_when: "'already exists' in liu.stderr" # 已经存在报告失败
当任务对托管主机进行了更改时,会报告 changed 状态并通知处理程序。如果任务不需要进行更改,则会报告ok并且不通知处理程序。
changed_when关键字可用于控制任务在何时报告它已进行了更改。例如,下一示例中的shell模块将用于获取供后续任务使用的Kerberos凭据。它通常会在运行时始终报告changed。为抵制这种更改,应设置changed_when: false,以便它仅报告ok或failed。
- name: get Kerberos credentials as "admin"
shell: echo "{{ krb_admin_pass }}" | kinit -f admin
changed_when: false
以下示例使用shell模块,根据通过已注册变量收集的模块的输出来报告changed:
---
- name:
hosts: 192.168.240.40
tasks:
- name:
shell: echo "123321" |passwd --stdin liu
register: result
changed_when: "'successfully' not in result.stdout"
notify:
- print info
handlers:
- name: print info
debug:
msg: " yes "
[root@localhost ansible]# ansible-playbook tj.yml
PLAY [192.168.240.40] *********************************************************************
TASK [Gathering Facts] ********************************************************************
ok: [192.168.240.40]
TASK [shell] ******************************************************************************
changed: [192.168.240.40]
RUNNING HANDLER [print info] **************************************************************
ok: [192.168.240.40] => {
"msg": " yes "
}
PLAY RECAP ********************************************************************************
192.168.240.40 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在playbook中,块是对任务进行逻辑分组的子句,可用于控制任务的执行方式。例如,任务块可以含有when关键字,以将某一条件应用到多个任务
- name: block example
hosts: 172.16.103.129
tasks:
- name: installing and configuring Yum versionlock plugin
block:
- name: package needed by yum
yum:
name: yum-plugin-versionlock
state: present
- name: lock version of tadata
lineinfile:
dest: /etc/yum/pluginconf.d/versionlock.list
line: tzdata-2020j-1
state: present
when: ansible_distribution == "Redhat"
通过块,也可结合rescue和always语句来处理错误。如果块中的任何任务失败,则执行其rescue块中的任务来进行恢复。在block子句中的任务以及rescue子句中的任务(如果出现故障)运行之后,always子句中的任务运行。总结:
以下示例演示了如何在playbook中实施块。即使block子句中定义的任务失败,rescue和always子句中定义的任务也会执行。
block中的when条件也会应用到其rescue和always子句(若存在)
---
- name:
hosts: 192.168.240.40
tasks:
- name: test
block:
- name: passwd
shell: echo "123321" |passwd --stdin liu
state: present
rescue:
- name: create user
shell: echo "000000" |passwd --stdin liu
state: present
always: #block和rescue其中只需有一个执行,但always是一定会执行的
- name: restart httpd
service:
name: httpd
state: restarted
Files模块库包含的模块允许用户完成与Linux文件管理相关的大多数任务,如创建、复制、编辑和修改文件的权限和其他属性。
模块名称 | 模块说明 |
---|---|
blockinfile | 插入、更新或删除由可自定义标记线包围的多行文本块 |
copy | 将文件从本地或远程计算机复制到受管主机上的某个位置。 类似于file模块,copy模块还可以设置文件属性,包括SELinux上下文件。 |
fetch | 此模块的作用和copy模块类似,但以相反方式工作。此模块用于从远程计算机获取文件到控制节点, 并将它们存储在按主机名组织的文件树中。 |
file | 设置权限、所有权、SELinux上下文以及常规文件、符号链接、硬链接和目录的时间戳等属性。 此模块还可以创建或删除常规文件、符号链接、硬链接和目录。其他多个与文件相关的 模块支持与file模块相同的属性设置选项,包括copy模块。 |
lineinfile | 确保特定行位于某文件中,或使用反向引用正则表达式来替换现有行。 此模块主要在用户想要更改文件的某一行时使用。 |
stat | 检索文件的状态信息,类似于Linux中的stat命令。 |
synchronize | 围绕rsync命令的一个打包程序,可加快和简化常见任务。 synchronize模块无法提供对rsync命令的完整功能的访问权限,但确实最常见的调用更容易实施。 用户可能仍需通过run command模块直接调用rsync命令。 |
在受管主机上创建、复制、编辑和删除文件是用户可以使用Files模块库中的模块实施的常见任务。
以下示例显示了可以使用这些模块自动执行常见文件管理任务的方式。
使用file模块处理受管主机上的文件。其工作方式与touch命令类似,如果不存在则创建一个空文件,如果存在,则更新其修改时间。在本例中,除了处理文件之外,Ansible还确保将文件的所有者、组和权限设置为特定值。
---
- name: touch file
hosts: 192.168.240.40
tasks:
- name: file
file:
path: /opt/kk
owner: user1
group: user1
mode: 2012
state: touch
使用file模块还可以确保新的或现有的文件具有正确的权限和SELinux类型。
例如,以下文件保留了相对于用户主目录的默认SELinux上下文,这不是所需的上下文。
[root@localhost opt]# ls -Z kk
unconfined_u:object_r:usr_t:s0 kk
以下任务确保了anaconda-ks.cfg文件的SELinux上下文件类型属性是所需的samba_share_t类型。此行为与Linux中的chcon命令类似。
文件属性参数在多个文件管理模块中可用。运行ansible-doc file和ansible-doc copy命令以获取其他信息。
- name: SELinux type is set to samba_share_t
file:
path: /opt/kk
setype: samba_share_t
[root@localhost ~]# ls -Z kk #结果
unconfined_u:object_rsamba_share_ts0 kk
设置文件上下文时,file模块的行为与chcon类似。通过运行restorecon,可能会意外地撤消使用该模块所做的更改。使用file设置上下文后,用户可以使用system模块集合中的sefcontext来更新SELinux策略,如semanage fcontext。
- name: SELinux type is persistently set to samba_share_t
sefcontext:
target: /path/to/samba_file
setype: samba_share_t
state: present
注意:sefcontext模块更新SELinux策略中目标的默认上下文,但不更改现有文件的上下文。
在此示例中,copy模块用于将位于控制节点上的Ansible工作目录中的文件复制到选定的受管主机。
默认情况下,此模块假定设置了force: yes。这会强制该模块覆盖远程文件(如果存在但包含与正在复制的文件不同的内容)。如果设置force: no,则它仅会将该文件复制到受管主机(如果该文件尚不存在)。
---
- name: file
hosts: 192.168.240.40
tasks:
- name: copy
copy:
src: /etc/ansible/cctv
dest: /opt
要从受管主机检索文件,请使用fetch模块。这可用于在将参考系统分发给其他受管主机之前从参考系统中检查诸如SSH公钥之类的文件。
---
- name: file
hosts: 192.168.240.40
tasks:
- name: fetch
fetch:
src: /opt/lll
dest: /mnt
要将文本块添加到现有文件,请使用blockinfile模块:
---
- name: file
hosts: 192.168.240.40
tasks:
- name: fetch
lineinfile:
path: /opt/ooo
line: 'jjyy kk'
[root@localhost ansible]# ansible-playbook file.yml #执行
PLAY [file] *******************************************************************************
TASK [Gathering Facts] ********************************************************************
ok: [192.168.240.40]
TASK [fetch] ******************************************************************************
changed: [192.168.240.40]
PLAY RECAP ********************************************************************************
192.168.240.40 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost opt]# cat ooo #查看
dwqd
dwq
wqdx
jjyy kk
用户可以使用该模块的marker参数,帮助确保将正确的注释字符或文本用于相关文件。
要将文本块添加到现有文件,请使用blockinfile模块:
---
- name: file
hosts: 192.168.240.40
tasks:
- name: fetch
blockinfile:
path: /opt/ooo
block: 'dedededed'
[root@localhost ansible]# ansible-playbook file.yml #执行
PLAY [file] *******************************************************************************
TASK [Gathering Facts] ********************************************************************
ok: [192.168.240.40]
TASK [fetch] ******************************************************************************
changed: [192.168.240.40]
PLAY RECAP ********************************************************************************
192.168.240.40 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost opt]# cat ooo #查看结果
dwqd
dwq
wqdx
jjyy kk
# BEGIN ANSIBLE MANAGED BLOCK
dedededed
# END ANSIBLE MANAGED BLOCK
从受管主机中删除文件的基本示例是使用file模块和state: absent参数。state参数对于许多模块是可选的。一些模块也支持其他选项。
---
- name: file
hosts: 192.168.240.40
tasks:
- name: fetch
file:
dest: /opt/ooo
state: absent
stat模块检索文件的事实,类似于Linux中的stat命令。参数提供检索文件属性、确定文件检验和等功能。
stat模块返回一个包含文件状态数据的值的散列字典,允许用户使用单独的变量引用各条信息。
以下示例注册stat模块的结果,然后显示它检查的文件的MD5检验和。
- name: Verify the checksum of a file
stat:
path: /path/to/file
checksum_algorithm: md5
register: result
- debug
msg: "The checksum of the file is {{ result.stat.checksum }}"
有关stat模块返回的值的信息由ansible-doc记录,或者可以注册一个变量并显示其内容以查看可用内容:
---
- name: file
hosts: 192.168.240.40
tasks:
- name: fetch
stat:
path: /opt/kk
register: liu
- name:
debug:
var: liu
[root@localhost ansible]# ansible-playbook file.yml
PLAY [file] *******************************************************************************
TASK [Gathering Facts] ********************************************************************
ok: [192.168.240.40]
TASK [fetch] ******************************************************************************
ok: [192.168.240.40]
TASK [debug] ******************************************************************************
ok: [192.168.240.40] => {
"liu": {
"changed": false,
"failed": false,
"stat": {
"atime": 1627377090.7375915,
·····
"wusr": true,
"xgrp": true,
"xoth": false,
"xusr": true
}
}
}
PLAY RECAP ********************************************************************************
192.168.240.40 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
synchronize模块是一个围绕rsync工具的打包程序,它简化了playbook中的常见文件管理任务。rsync工具必须同时安装在本机和远程主机上。默认情况下,在使用synchronize模块时,“本地主机”是同步任务所源自的主机(通常是控制节点),而“目标主机”是synchronize连接到的主机。
有很多种方法可以使用synchronize模块及其许多参数,包括同步目录。运行ansible-doc synchronize命令查看其他参数和playbook示例。
以下示例将位于Ansible工作目录中的文件同步到受管主机:
---
- name: file
hosts: 192.168.240.40
tasks:
- name: fetch
synchronize:
src: /etc/ansible/qd.yml
dest: /opt/
[root@localhost ansible]# ansible-playbook file.yml
PLAY [file] *******************************************************************************
TASK [Gathering Facts] ********************************************************************
ok: [192.168.240.40]
TASK [fetch] ******************************************************************************
changed: [192.168.240.40]
PLAY RECAP ********************************************************************************
192.168.240.40 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0