条件判断、任务失败、文件管理
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
条件判断
在Ansible中,条件判断的关键字是"when"
---
#~/test.yml
- hosts: node2
tasks:
- debug:
msg: "system release is CentOS"
when:
ansible_distribution == "CentOS"
[root@node1 ~]# ansible-playbook playbook/test1.yml
PLAY [node2] ************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************
ok: [node2]
TASK [debug] ************************************************************************************************************************
ok: [node2] => {
"msg": "system release is CentOS"
}
PLAY RECAP **************************************************************************************************************************
node2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
如上所示,使用when关键字指明条件,条件是ansible_distribution的值为CentOS,我们可以发现,ansible_distribution就是facts信息中的一个key,通过ansible_distribution可以获取到目标主机系统的发行版。在使用when关键字时,我们并没有为ansible_distribution添加"{{ }}",在when关键字中引用变量时,变量名不需要加"{{ }}",上例playbook表示如果ansible_distribution的值是CentOS,则调用debug模块输出"system release is CentOS"这句话,如果值不是CentOS,则不满足条件,不会调用debug模块,使用when关键字为任务指定条件,条件成立则执行任务,条件不成立则不执行任务
在ansible也可以使用比较运算符
| 比较运算符 | 含义 |
|---|---|
| == | 比较两个对象是否相等,相等为真 |
| != | 比较两个对象是否不等,不等为真 |
| 比较两个值的大小,如果左边的值大于右边的值,则为真 | |
| < | 比较两个值的大小,如果左边的值小于右边的值,则为真 |
| >= | 比较两个值的大小,如果左边的值大于右边的值或左右相等,则为真 |
| <= | 比较两个值的大小,如果左边的值小于右边的值或左右相等,则为真 |
处理程序
处理程序:程序响应由其他任务触发通知的任务
handllers可以理解成另一种tasks,handlers是另一种人物列表,由通知者进行notify,如果没有被notify,handlers就不会被调用。但是,被调用不意味着一定会执行,只有当tasks中的任务真正执行以后,handlers中被调用的任务才会执行,如果tasks中的任务并没有做出任何实际的操作,那么handlers中的任务即使被调用也不会执行
如:复制文件给受管主机
---
#~/test.yml
- hosts: node2
gather_facts: no
tasks:
- name: copy files
copy:
src: ~/1.txt
dest: ~/
notify:
- restart httpd
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
[root@node1 ~]# ansible-playbook playbook/test1.yml
PLAY [node2] ************************************************************************************************************************
TASK [copy files] *******************************************************************************************************************
changed: [node2]
RUNNING HANDLER [restart httpd] *****************************************************************************************************
changed: [node2]
PLAY RECAP **************************************************************************************************************************
node2 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在上例中,restarted httpd处理程序只有在copy任务通知changer时才会触发。一个任务可以在其notify部分中调用多个处理程序。ansible将notify语句视为数组,并且迭代处理程序名称
tasks:
- name: copy file
copy:
src: ~/1.txt
dest: ~/
notify:
- restart mysql
- restart httpd
handlers:
- name: restart mysql
service:
name: mariadb
state: restarted
- name: restart httpd
service:
name: httpd
state: restarted
使用处理程序应注意
- 处理程序始终按照play的handlers部分指定的顺序运行,不按notify里的
- 处理程序通常在相关play中所有其他任务运行完后运行
- 处理程序名称存在于play命名空间中(如果两个处理程序同名,只会运行一个)
- 如果多个任务通知处理程序,处理程序也只会运行一次
- 如果包含notify的语句任务报告没有报告changed结果,则处理程序不会获得通知
处理任务失败
忽略任务失败
Ansible默认会检查命令和模块的返回状态,并进行相应的错误处理,默认是遇到错误就中断playbook的执行,这些默认行为都是可以改变的,可以通过ignore_errors忽略返回状态码
下例演示了如何在任务中使用ignore_errors,以便在任务失败时也继续在主机上执行playbook。例如,如果httpdabc软件包不存在,则yum模块将失败,但若将ignore_errors设置为yes,则执行将继续
- name: install httpdabc
yum:
name: httpdabc
state: present
ignore_errors: yes
强制执行任务
通常任务失败,playbook会终止,那么收到play中之前任务通知的处理程序将不会运行,如果要运行,需要使用关键字force_handlers: yes
---
#~/test.yml
- hosts: node2
gather_facts: no
force_handlers: yes
tasks:
- name: copy files
copy:
src: ~/1.txt
dest: ~/abc
notify:
- restart httpd
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
指定任务失败条件
方法一:使用failed_when关键字
---
#~/test.yml
- hosts: node2
tasks:
- name: test
script: files/test.sh
register: result
failed_when: "'No such file or directory' in result.stdout"
TASK [test] ********************************************************************************************
fatal: [node2]: FAILED! => {"changed": true, "failed_when_result": true, "rc": 0, "stderr": "Shared connection to node2 closed.\r\n", "stderr_lines": ["Shared connection to 192.168.190.134 closed."], "stdout": "ls: cannot access 'sdsdsdsdsdsds': No such file or directory\r\nanaconda-ks.cfg\r\n", "stdout_lines": ["ls: cannot access 'sdsdsdsdsdsds': No such file or directory", "anaconda-ks.cfg"]}
方法二:使用fail模块进行报错条件
---
#~/test.yml
- hosts: node2
tasks:
- name: test
script: ~/abc.sh
register: result
- name: fail control
fail:
msg: "you are a fool"
when:
"'No such file or directory' in result.stdout"
TASK [fail control] ************************************************************************************
fatal: [node2]: FAILED! => {"changed": false, "msg": "you are a fool"}
指定何时报告“changed”结果
利用changed_when关键字来确定是否报告changed结果
---
#~/test.yml
- hosts: node2
gather_facts: no
tasks:
- name: useradd
user:
name: tom
state: present
changed_when: True
ansible块和错误处理
三种关键字:
- block:定义要运行的任务
- rescue:定义要在block子句中定义的任务失败时运行的任务
- always:定义始终独立运行的任务
---
#~/test.yml
- hosts: node2
vars:
file_name: test1
tasks:
- name: test block
block:
- name: block1
command: ls /tmp
- name: block2
command: ls /tmp/ {{ file_name }}
rescue:
- name: touch the {{ file_name}}
file:
name: "{{ file_name}}"
state: touch
always:
- name: print
command: echo "123456"
register: rrresult
- debug:
msg: " {{ result.stdout }} "
文件管理
ansible中常用的文件管理模块:
- blockinfile:将文本块添加到现有文件
- copy:将文件复制到受管主机
- fetch:从受管主机拷贝文件到控制节点
- file:设置文件属性
- lineinfile:确保特定行位于某个文件
- stat:检索文件状态信息
- synchronize:rsync命令的打包程序
确保受管主机上存在文件
使用file模块处理受管主机上的文件。其工作方式与touch命令类似,如果不存在则创建一个空文件,如果存在,则更新其修改时间。
- name: Touch a file and set permissions
file:
path: ~/file/test
owner: tom
group: tom
mode: 0777
state: touch
修改文件属性
使用file模块还可以确保新的或现有的文件具有正确的权限和SELinux类型
例如,以下文件保留了相对于用户主目录的默认SELinux上下文,这不是所需的上下文
[root@localhost ~]# ls -Z samba_file
- rw-r--r-- owner group unconfined_u:object_r:user_home_t:s0 samba_file
使SELinux文件上下文更改具有持久性
设置文件上下文时,file模块的行为与chcon类似。通过运行restorecon,可能会意外的撤销使用该模块所做的更改。使用file设置上下文后,用户可以使用system模块集合中的sefcontext来更新SELinux策略,如semanage fcontext。
- name: SELinux
sefcontext:
target: ~/file/samba_file
setype: samba_share_t
state: present
在受管主机上复制和编辑文件
在此示例中,copy模块用于将位于控制节点上的Ansible工作目录中的文件复制到选定的受管主机。
默认情况下,此模块假定设置了force: yes。这会强制该模块覆盖远程文件(如果存在但包含与正在复制的文件不同的内容)。如果设置force: no,则它仅会将该文件复制到受管主机(如果该文件尚不存在)。
name: Copy a file to managed hosts
copy:
src: file
dest: ~/file
要确保现有文件中存在特定的单行文本,请使用lineinfile模块:
- name: Add a line of text to a file
lineinfile:
path: ~/file
line: 'Add this line to the file'
state: present
要将文本块添加到现有文件,请使用blockinfile模块:
- name: Add additional lines to a file
blockinfile:
path: ~/file
block: |
First line in the additional block of text
Second line in the additional block of text
state: present
使用blockinfile模块时,注释块标记插入到块的开头和结尾,以确保幂等性。
# BEGIN ANSIBLE MANAGED BLOCK
First line in the additional block of text
Second line in the additional block of text
# END ANSIBLE MANAGED BLOCK
从受管主机中删除文件
从受管主机中删除文件的基本示例是使用file模块和state:absent参数。state参数对于许多模块是可选的
- name: shan chu wenjian
file:
dest: ~/test
state: absent
检索受管主机上的文件状态
stat模块检索文件的事实,类似于linux中的stat命令。参数提供检索文件属性、确定文件检验和等功能
stat模块返回一个包含文件状态数据的值的散列字典,允许用户使用单独的变量引用各条信息
以下示例注册stat模块的结果,然后显示它检查的文件的MD5检验和。
- name: Verify the checksum of a file
stat:
path: ~/file/123
checksum_algorithm: md5
register: result
- debug
msg: "The checksum of the file is {{ result.stat.checksum }}"
有关stat模块返回的值的信息由ansible-doc记录,或者可以注册一个变量并显示其内容以查看可用内容:
- hosts: node2
tasks:
- name: stat /etc/passwd
stat:
path: /etc/passwd
register: results
- name: Display stat results
debug:
var: results
同步控制节点和受管主机之间的文件
synchronize模块是一个围绕rsync工具的打包程序,它简化了playbook中的常见文件管理任务。rsync工具必须同时安装在本机和远程主机上。默认情况下,在使用synchronize模块时,“本地主机”是同步任务所源自的主机(通常是控制节点),而“目标主机”是synchronize连接到的主机。
以下示例将位于Ansible工作目录中的文件同步到受管主机:
- name: tong bu
synchronize:
src: file
dest: ~/file/abc
有很多种方法可以使用synchronize模块及其许多参数,包括同步目录。运行ansible-doc synchronize命令查看其他参数和playbook示例。