条件判断
有条件地运行任务
Ansible可使用conditionals在符合特定条件时执行任务或play。
所以我们可以利用条件来区分不同的受管主机,并根据它们所符合的条件来分配功能角色。Playbook变量、注册的变量和Ansible事实都可通过条件来进行测试。可以使用比较字符串、数字数据和布尔值的运算符。
以下场景说明了在Ansible中使用条件的几种情况:
可以在变量中定义硬限制(如min_memory)并将它与受管主机上的可用内存进行比较。
Ansible可以捕获并评估命令的输出,以确定某一任务在执行进一步操作前是否已经完成。例如,如果某一程序失败,则将路过批处理。
可以利用Ansible事实来确定受管主机网络配置,并决定要发送的模板文件(如,网络绑定或中继)。
可以评估CPU的数量,来确定如何正确调节某一Web服务器。
将注册的变量与预定义的变量进行比较,以确定服务是否已更改。例如,测试服务配置文件的MD5检验以和查看服务是否已更改。
条件任务语法
when语句用于有条件地运行任务。它取要测试的条件为值。如果条件满足,则运行任务。如果条件不满足,则跳过任务。
测试my_service变量是否具有值。
---
- hosts: all
vars:
my_ser: httpd
tasks:
- name: "{{ my_ser }} package is install"
yum:
name: "{{ my_ser }}"
state: present
when: my_ser is defined
下表显示了在处理条件时可使用的一些运算
项目 | Value |
---|---|
操作 | 示例 |
等于(值为字符串) | ansible_machine == “x86_64” |
等于(值为数字) | max_memory == 512 |
小于 | min_memory < 128 |
大于 | min_memory > 256 |
小于等于 | min_memory <= 256 |
大于等于 | min_memory >= 512 |
变量存在 | min_memory is defined |
变量不存在 | min_memory is not defined |
布尔变量是True。1、True或yes的求值为True | memory_available |
布尔变量是False 。0、False或no的求值为False | not memory_available |
第一个变量的值存在,作为第二个变量的列表中的值 | ansible_distribution in supported_distros |
如果ansible_distribution的值在sup_dir列表中,则条件通过且任务运行
---
- hosts: all
vars:
sup_dir:
- RedHat
- CentOS
tasks:
- name: asdad
yum:
name: httpd
state: present
when: ansible_facts['distribution'] in sup_dir
[root@ansible jay]# ansible-playbook playbook.yml
PLAY [all] ***********************************************************************
TASK [Gathering Facts] ***********************************************************
ok: [192.168.10.129]
TASK [asdad] *********************************************************************
changed: [192.168.10.129]
PLAY RECAP ***********************************************************************
192.168.10.129 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
多个条件一起测试:
一个when语句可用于评估多个条件。使用and和or关键字组合条件,并使用括号分组条件。
如果任一条件为真时满足条件语句,则应当使用or语句。
when: ansible_distribution == "Redhat" or ansible_distribution == "CentOS"
使用and运算时,两个条件都必须为真,才能满足整个条件语句。
when: ansible_distribution_version == "7.3" or ansible_distribution == "CentOS"
when关键字还支持使用列表来描述条件列表。向when关键字提供列表时,将使用and运算组合所有条件。
when:
- ansible_distribution_version == "7.5"
- ansible_distribution == "CentOS"
通过使用括号分组条件,可以表达更复杂的条件语句。
---
- hosts: all
tasks:
- name: asdad
yum:
name: httpd
state: absent
when: >
ansible_distribution == "CentOS"
or
ansible_distribution_version == "7.5"
组合循环和有条件任务
循环和条件可以组合使用
---
- hosts: all
tasks:
- name: asdad
yum:
name: httpd
state: present
loop: "{{ ansible_facts['mounts'] }}"
when:
- item.mount == "/"
- item.size_available > 30000000
handlers
简介
需要出发的才能执行任务,当前面的tasks中的任务执行成功后,若希望在此基础上触发其他任务,这时就需要定义handlers。
例如,当通过ansible的模块对目标主机的配置文件进行修改之后,如果任务执行成功,可以触发一个触发器,在触发器中定义目标主机的服务重启操作,以便配置文件生效
特点
handlers是ansible提供的条件机制之一,handlers和tasks很类似,但是只在被tasks通知的时候才会触发执行;
handlers只会在任务执行完成后执行。即使被通知了很多次,也只会执行一次。
playbook
# cat handlers_sample.yaml
---
- hosts: 127.0.0.1
handlers:
- name: echo handlers
shell: echo "handlers"
tasks:
- name: 输出 test1
shell: echo "test1"
notify:
- echo handlers
- name: 输出test2
shell: echo "test2"
- name: 输出test3
shell: echo "test3"
#
运行结果
# ansible-playbook -v handlers_sample.yaml
Using /etc/ansible/ansible.cfg as config file
PLAY [127.0.0.1] ***************************************************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************************************************
ok: [127.0.0.1]
TASK [输出 test1] ****************************************************************************************************************************************************************************
changed: [127.0.0.1] => {"changed": true, "cmd": "echo \"test1\"", "delta": "0:00:00.002695", "end": "2019-05-25 02:22:36.625148", "rc": 0, "start": "2019-05-25 02:22:36.622453", "stderr": "", "stderr_lines": [], "stdout": "test1", "stdout_lines": ["test1"]}
TASK [输出test2] *****************************************************************************************************************************************************************************
changed: [127.0.0.1] => {"changed": true, "cmd": "echo \"test2\"", "delta": "0:00:00.002935", "end": "2019-05-25 02:22:36.898646", "rc": 0, "start": "2019-05-25 02:22:36.895711", "stderr": "", "stderr_lines": [], "stdout": "test2", "stdout_lines": ["test2"]}
TASK [输出test3] *****************************************************************************************************************************************************************************
changed: [127.0.0.1] => {"changed": true, "cmd": "echo \"test3\"", "delta": "0:00:00.002666", "end": "2019-05-25 02:22:37.141926", "rc": 0, "start": "2019-05-25 02:22:37.139260", "stderr": "", "stderr_lines": [], "stdout": "test3", "stdout_lines": ["test3"]}
RUNNING HANDLER [echo handlers] ************************************************************************************************************************************************************
changed: [127.0.0.1] => {"changed": true, "cmd": "echo \"handlers\"", "delta": "0:00:00.002762", "end": "2019-05-25 02:22:37.401675", "rc": 0, "start": "2019-05-25 02:22:37.398913", "stderr": "", "stderr_lines": [], "stdout": "handlers", "stdout_lines": ["handlers"]}
PLAY RECAP *********************************************************************************************************************************************************************************
127.0.0.1 : ok=5 changed=4 unreachable=0 failed=0
#
任务失败处理
任务失败控制
Ansible 通常默认会确保检测模块和命令的返回码并且会快速失败 – 专注于一个错误除非你另作打算.
有时一条命令会返回 0 但那不是报错.有时命令不会总是报告它 ‘改变’ 了远程系统.本章节描述了 如何将 Ansible 处理输出结果和错误处理的默认行为改变成你想要的.
忽略错误的命令
通常情况下, 当出现失败时 Ansible 会停止在宿主机上执行.有时候,会想要继续执行下去.为此需要像这样编写任务
- name: cat no exist file
command: cat /root/noexist
ignore_errors: yes
- name: cat file info
shell: cat /root/fileinfo
控制对失败的定义
假设一条命令的错误码毫无意义只有它的输出结果能告诉你什么出了问题,比如说字符串 “FAILED” 出 现在输出结果中.
在 Ansible 1.4及之后的版本中提供了如下的方式来指定这样的特殊行为
- name: this command prints FAILED when it fails
command: /usr/bin/ls -x -y -z
register: command_result
failed_when: "'FAILED' in command_result.stderr"
在 Ansible 1.4 之前的版本能通过如下方式完成
- name: this command prints FAILED when it fails
command: /usr/bin/ls -x -y -z
register: command_result
ignore_errors: True
- name: fail the play if the previous command did not succeed
fail: msg="the command failed"
when: "'FAILED' in command_result.stderr"
文件管理
文件模块简介
项目 | Value |
---|---|
模块名称 | 模块说明 |
blockinfile | 插入更新或删除多行文本块 |
copy | 复制文件从src到dest,可以设置SELinux属性 |
fetch | 与copy相反,用于从被管理主机拉取文件到控制节点,并存储在按住机组名称组织的文件树中 |
file | 创建或删除文件、设置权限、链接、设置时间戳等 |
lineinfile | 确保某行在文件中,也可以使用正则表达式来替换当前行 |
stat | 检索文件的状态信息 |
file
作用:如果文件存在,就修改文件的时间;如果文件不存在,就创建
可以指定所属组、所属人、设置权限
- name: User file test
file:
path: /home/student/inventory
owner: student
group: student
mode: 0640
state: touch
删除文件
设置state: absent
---
- name:
hosts: all
remote_user: devops
tasks:
- file:
path: /home/devops/users.txt
state: absent
设置SELinux上下文
- name:
file:
path: /home/devops/users.txt
seuser: _default
serole: _default
setype: _default
selevel: _default
[student@workstation file-manage]$ ansible all -a 'ls -Z' -u devops
servera.lab.example.com | CHANGED | rc=0 >>
unconfined_u:object_r:user_home_t:s0 inventory
unconfined_u:object_r:user_home_t:s0 users.txt
serverb.lab.example.com | CHANGED | rc=0 >>
unconfined_u:object_r:user_home_t:s0 users.txt
copy
copy可以将文件从src复制到dest
其中有一个force属性,默认为yes。即在目标主机的路径下,若当前文件存在,则覆盖。
将force设置为no,则不会覆盖原文件
---
- name:
remote_user: root
hosts: all
tasks:
- name:
copy:
src: /home/student/file-manage/files/users.txt
dest: /home/devops/users.txt
owner: devops
group: devops
mode: u+rw,g-wx,o-rwx
setype: samba_share_t
copy还支持将字符串输出到指定文件中:将src换为content
copy:
content: abcde
dest: /home/student/1.txt
force: yes
fetch
从目标主机拉取文件到控制节点
---
- name: use the fetch
hosts: all
remote_user: root
tasks:
- name: fetch the logs
fetch:
src: /var/log/secure
dest: secure-backups
flat: no
运行结果
[student@workstation file-manage]$ tree secure-backups/
secure-backups/
├── servera.lab.example.com
│ └── var
│ └── log
│ └── secure
└── serverb.lab.example.com
└── var
└── log
└── secure
6 directories, 2 files
lineinfile & blockinfile
lineinfile:指定对目标文件某一行的操作
blockinfile:在文件中插入某个文本块
---
- name:
hosts: all
remote_user: devops
tasks:
- name:
lineinfile:
path: /home/devops/users.txt
line: this line was addes by the lineinfile module
state: present
---
- name:
hosts: all
remote_user: devops
tasks:
- blockinfile:
path: /home/devops/users.txt
block: |
this block of taxt consists of two lines
they hava been added by the blockinfile module
state: present
运行结果
serverb.lab.example.com | CHANGED | rc=0 >>
this line was addes by the lineinfile module
# BEGIN ANSIBLE MANAGED BLOCK
this block of taxt consists of two lines
they hava been added by the blockinfile module
# END ANSIBLE MANAGED BLOCK
servera.lab.example.com | CHANGED | rc=0 >>
this line was addes by the lineinfile module
# BEGIN ANSIBLE MANAGED BLOCK
this block of taxt consists of two lines
they hava been added by the blockinfile module
# END ANSIBLE MANAGED BLOCK
stat
检索文件的属性、确定文件校验
---
- name: checksum
hosts: servera
tasks:
- name:
stat:
path: /etc/passwd
checksum_algorithm: md5
register: result
- name: debug outpiut
debug:
msg: "the res is {{ result.stat.checksum }}"
运行结果
TASK [debug outpiut] *****************************************************************************************************************
ok: [servera] => {
"msg": "the res is aaf177a0da6689efa01585c7602641fd"
}