目录
四、ansible中的条件判断 与错误处理fail模块 failed_when changed_when关键字
一、when控制语句
when 判断在用于控制在满足when所指定的条件的情况下 才执行相应的动作。
在when关键字中引用变量时,变量名不需要加"{{ }}",我们可以使用when关键字为任务指定条件,条件成立,则执行任务,条件不成立,则不执行任务。
比如:比如: Centos 与 Ubuntu 都需要安装 Apache ,而 Centos 系统软件包为httpd ,而 Ubuntu 系统软件包为httpd2 ,那么此时就需要判断主机系统,然后为不同的主机系统安装不同的软件包。
示例1:
为所有主机安装Apache软件,若系统为CentOS :安装httpd,若系统为Ubuntu :安装httpd2。
ansible_distribution 变量可以获取主机的发行版本
[root@k8s-master-1 variables]# ansible web -m setup -a 'filter=ansible_distribution'
192.168.134.138 | SUCCESS => {
"ansible_facts": {
"ansible_distribution": "CentOS",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
playbook 如下,因为我的系统是centos 的系统,所以在安装时候,会直接跳过
[root@k8s-master-1 test]# vim when.yaml
---
- hosts: web
remote_user: root
tasks:
- name: test when
yum:
name: httpd2
state: installed
when: ansible_distribution=="Ubuntu" <==判断版本语句,此处变量不需要{{ }}引用。
# when也可以使用and与or方式进行多项匹配。
[root@k8s-master-1 test]# ansible-playbook when.yaml
PLAY [web] **************************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.134.138]
TASK [test when] ****************************************************************
skipping: [192.168.134.138]
PLAY RECAP *********************************************************************
192.168.134.138 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
示例2:
---
- hosts: web
remote_user: root
tasks:
- name: test when
debug:
msg: "{{ item }}"
with_items:
- 1
- 2
- 3
when: item >= 2 // 输出item的值大于等于2
[root@k8s-master-1 test]# ansible-playbook -C when.yaml
skipping: [192.168.134.138] => (item=1)
ok: [192.168.134.138] => (item=2) => {
"msg": 2
}
ok: [192.168.134.138] => (item=3) => {
"msg": 3
}
示例3:
判断kubelet.service 服务是否正常运行,运行就停止,不运行不作处理
[root@k8s-master-1 test]# vim when.yaml
---
- hosts: web
remote_user: root
tasks:
- name: Check Nginx Status
shell: systemctl status kubelet.service
register: check_k8s
- name: Print check_k8s
debug:
var:
"check_k8s" <==#通过debug的var输出该变量的所有内容
- name:
service:
name: kubelet.service
state: stopped
when: check_k8s.rc == 0 <==.rc是check_nginx变量中的执行结果,见下面的执行过程
[root@k8s-master-1 test]# ansible-playbook when.yaml
PLAY [web] *******************************
TASK [Gathering Facts] *****************
ok: [192.168.134.138]
TASK [Check Nginx Status] *****************
changed: [192.168.134.138]
TASK [Print check_k8s] *********************
ok: [192.168.134.138] => {
"check_k8s": {
"changed": true,
"cmd": "systemctl status kubelet.service",
"delta": "0:00:00.006566",
"end": "2023-07-24 16:30:11.969695",
"failed": false,
"rc": 0, <==.rc是check_nginx变量中的执行结果状态,0表示执行正常
"start": "2023-07-24 16:30:11.963129",
"stderr": "",
"stderr_lines": [],
"stdout_lines": [
"● kubelet.service - Kubernetes Kubelet",
" Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)",
" Active: active (running) since 一 2023-07-24 16:27:35 CST; 2min 36s ago",
" Main PID: 40292 (kubelet)",
" Memory: 48.5M",
" CGroup: /system.slice/kubelet.service",
]
}
}
TASK [service] ********************
changed: [192.168.134.138]
PLAY RECAP ************************
192.168.134.138 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
运算符
比较运算符 | 含义 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
== | 等于 |
!= | 不等于 |
逻辑运算符 | 含义 |
and | 逻辑与,当左边与右边同时为真,则返回真 |
or | 逻辑或,当左边或右边有一个为真时,返回真 |
not | 取反, |
() | 组合 |
示例4:
运算符和ignore_errors关键字
---
- hosts: web
remote_user: root
tasks:
- name: task1
shell: "df -h"
register: returnmsg
ignore_errors: true //设置为true,如果task1 报错,也不影响其他任务执行
- name: task2
debug:
msg: "{{returnmsg.stdout_lines}}"
when: returnmsg.rc == 0
- name: task3
debug:
msg: "Command execution failed"
when: returnmsg.rc != 0
[root@k8s-master-1 test]# ansible-playbook when.yaml
ok: [192.168.134.138] => {
"msg": [
"文件系统 容量 已用 可用 已用% 挂载点",
"/dev/mapper/centos-root 36G 8.3G 27G 24% /",
"devtmpfs 1.9G 0 1.9G 0% /dev",
"tmpfs 1.9G 0 1.9G 0% /dev/shm",
"tmpfs 1.9G 18M 1.9G 1% /run",
"tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup",
"/dev/sda1 1014M 179M 836M 18% /boot",
"tmpfs 378M 12K 378M 1% /run/user/42",
"tmpfs 378M 0 378M 0% /run/user/0",
]
}
TASK [task3] *******************************************************************
skipping: [192.168.134.138]
PLAY RECAP *********************************************************************
192.168.134.138 : ok=3 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
二、ansible中的条件判断和tests
1、条件判断和tests
tests会将判断后的布尔值返回,如果条件成立,则返回true,如果条件不成立,tests会返回false,我们通常会在条件判断时使用到tests
示例:
---
- hosts: web
remote_user: root
vars:
testpath: /tmp
tasks:
- name: test
debug:
msg: "file exist"
when: testpath is exists
"is exists"中的"exists"就是tests的一种,判断ansible主机中的对应路径是否存在(注意:是ansible控制主机中的路径,与目标主机没有关系),当对应的路径存在于ansible控制节点时,"is exists"为真。
"is not exists"表示对应路径不存在时返回真。
上边我们学了 逻辑运算符,也可以使用 not testpath is exists :表示取反,不存在则返回真
2、判断变量的tests
- defined:判断变量是否已经定义,已经定义返回真
- undefind:判断变量是否已经定义,没定义就返回真
- none:判断变量值是否为空,如果变量已经定义,但变量值为空,则返回真
示例:
---
- hosts: web
remote_user: root
vars:
test1: vl
test2:
tasks:
- debug:
msg: "test1 is defined"
when: test1 is defined
- debug:
msg: "test1 is undefind"
when: test2 is undefined
[root@k8s-master-1 condition]# ansible-playbook pd2.yaml
TASK [debug] *****************************************************************
ok: [192.168.134.138] => {
"msg": "test1 is defined"
}
TASK [debug] ****************************************************************
ok: [192.168.134.138] => {
"msg": "test1 is undefind"
}
3、判断执行结果的一些tests
- success或者succeeded:通过任务的返回信息判断任务的执行状态,任务执行成功则返回真
- failure 或 failed:通过任务的返回信息判断任务的执行状态,任务执行失败则返回真
- change 或 changed:通过任务的返回信息判断任务的执行状态,任务执行状态为changed则返回真
- skip 或 skipped:通过任务的返回信息判断任务的执行状态,当任务没有满足条件,而被跳过执行时,则返回真
4、判断是否是数字
- number:判断对象是否是一个数字,是数字则返回真
5、判断是否是字符串
- string:判断对象是否是一个字符串,是字符串则返回真
三、ansible中的条件判断与block
when 关键字表示:当条件成立时,我们只能执行一个任务,如果我们想要在条件成立的情况下,执行多个任务,那该怎么解决呢?
1、block 关键字
---
- hosts: web
remote_user: root
tasks:
- name: test
debug:
msg: "test 1 2 3 "
- name: test block
block:
- debug:
msg: "test2"
- debug:
msg: "test3"
when: 2 > 1
[root@k8s-master-1 condition]# ansible-playbook pd3.yaml
TASK [test] *******************************************************************
ok: [192.168.134.138] => {
"msg": "test 1 2 3 "
}
TASK [debug] *******************************************************************
ok: [192.168.134.138] => {
"msg": "test2"
}
TASK [debug] ********************************************************************
ok: [192.168.134.138] => {
"msg": "test3"
}
上例中一共包含三个任务,第一个任务使用debug模块输出了 "task1 1 2 3 "这句话,在第一个任务之后,我们定义了一个block,这个block中包含两个任务,两个debug任务分别输出各自的信息,上例的when关键字与block关键字对齐,表示when关键字的条件是针对block的,当when对应的条件成立,则执行block中的两个任务。
2、block 错误处理功能:
"错误处理"功能就是当某任务出错时,执行指定的其他任务,打个比方,我们想要在A任务执行失败时执行B任务,如果A任务执行成功,则无需执行B任务,实现这个功能,就能够使用block,当然,我们还有一些别的方法,也可以实现类似的功能,比如前文中提到的jinja2的tests,有个一名为failed的test,借助failed也可以实现类似的功能,
示例
---
- hosts: web
remote_user: root
tasks:
- shell: 'ls /ooo'
register: return_value
ignore_errors: true
- debug:
msg: "i caught an error"
when: return_value is failed
如上示例,web主机中,没有000 目录,所以是报错不执行的,但是把报错写进了变量return_value 中,然后使用 is failed 进行判断,如果条件成立,代表shell出错,就执行debug任务
2、使用block示例:
---
- hosts: web
remote_user: root
tasks:
- name: test block
block:
- shell: 'ls /ooo'
rescue:
- debug:
msg: "i caught an error"
[root@k8s-master-1 condition]# ansible-playbook -C pd4.yaml
ok: [192.168.134.138] => {
"msg": "i caught an error"
}
如上所示:定义了一个block,web主机中,没有000 目录,所以是报错不执行的,除了block关键字,还有另外一个关键字rescue,rescue关键字与block关键字对齐,rescue的字面意思为"救援",表示当block中的任务执行失败时,会执行rescue中的任务进行补救。当block中的任务出错时,会执行rescue中的任务,当block中的任务顺利执行时,则不会执行rescue中的任务:
---
- hosts: web
remote_user: root
tasks:
- name: test block
block:
- shell: 'ls /tmp'
register: return_value
- debug:
msg: "{{ return_value.stdout_lines }}"
rescue:
- debug:
msg: "i caught an error"
[root@k8s-master-1 condition]# ansible-playbook pd4.yaml
ok: [192.168.134.138] => {
"msg": [
"a.log",
"ansible_command_payload_HmpFJ4",
"asd.yaml",
"asd.yaml.31523.2023-07-25@10:27:55~",
"systemd-private-64d62f5f121349008dac5639e0d3cd34-colord.service-SA1hiU",
"systemd-private-64d62f5f121349008dac5639e0d3cd34-cups.service-1xLJWH",
"systemd-private-64d62f5f121349008dac5639e0d3cd34-rtkit-daemon.service-47dWX8",
"systemd-private-64d62f5f121349008dac5639e0d3cd34-vgauthd.service-H9RsHM",
"systemd-private-64d62f5f121349008dac5639e0d3cd34-vmtoolsd.service-b3zMCq",
"tracker-extract-files.1000"
]
}
这个示例是正常的 就输出/tmp 下的目录,rescue 任务 会跳过不执行。
3、always 关键字
always 关键字:意思就是无论block中的任务失败还是成功 always任务 都会执行
示例:
---
- hosts: web
remote_user: root
tasks:
- name: test block
block:
- shell: 'ls /000'
register: return_value
- debug:
msg: "{{ return_value.stdout_lines }}"
rescue:
- debug:
msg: "i caught an error"
always:
- debug:
msg: "asddsaasddsa"
[root@k8s-master-1 condition]# ansible-playbook pd4.yaml
TASK [shell] ********************************
fatal: [192.168.134.138]: FAILED! => {"changed": true, "cmd": "ls /000", "delta": "0:00:00.005273", "end": "2023-08-03 10:40:36.440712", "msg": "non-zero return code", "rc": 2, "start": "2023-08-03 10:40:36.435439", "stderr": "ls: 无法访问/000: 没有那个文件或目录", "stderr_lines": ["ls: 无法访问/000: 没有那个文件或目录"], "stdout": "", "stdout_lines": []}
TASK [debug] *************************************
ok: [192.168.134.138] => {
"msg": "i caught an error"
}
TASK [debug] ***********************************
ok: [192.168.134.138] => {
"msg": "asddsaasddsa"
}
四、ansible中的条件判断 与错误处理fail模块 failed_when changed_when关键字
1、failed_when关键字
作用:当对应的条件成立时,将对应的任务执行的状态设置为失败。
示例:
[root@k8s-master-1 condition]# vim failed_when.yaml
---
- hosts: web
remote_user: root
tasks:
- debug:
msg: "I execute normally"
- shell: "echo 'This is a string for testing error'"
register: return_value
failed_when: ' "error" in return_value.stdout'
- debug:
msg: "I never execute,Because the playbook has stopped"
上例中,一共有三个任务,第一个任务通过debug模块输出 “I execute normally”,第二个任务调用shell模块,echo了'This is a string for testing error'这句话,并且将返回值注册到了'return_value'变量中,'failed_when'关键字与shell关键字对齐,表示其对应的条件是针对shell模块的,'failed_when'对应的条件是"error” in return_value.stdout",表示"error"字符串如果存在于shell模块执行后的标准输出中,则条件成立,当条件成立后,shell模块的执行状态将会被设置为失败,由于shell模块的执行状态被设置为失败,所以playbook会终止运行,于是,最后的debug模块并不会被执行.
'failed_when'虽然会将任务的执行状态设置为失败,但是并不代表任务真的失败了,就以上例来说,上例的shell模块的确是完全正常的执行了,只不过在执行之后,'failed_when'对应的条件成立了,'failed_when'将shell模块的执行状态设置为失败而已,所以,'failed_when'并不会影响shell模块的执行过程,只会在条件成立时影响shell模块最终的执行状态,以便停止playbook的运行。
2、changed_when关键字
作用:在条件成立时,将对应任务的执行状态设置为changed
示例:
正常情况下:
[root@k8s-master-1 condition]# vim changed_when.yaml
---
- hosts: web
remote_user: root
tasks:
- debug:
msg: "test message"
changed_when: 2 > 1
[root@k8s-master-1 condition]# ansible-playbook changed_when.yaml
ok: [192.168.134.138] => {
"msg": "test message"
}
状态是“ok”
2、使用changed_when 关键字
[root@k8s-master-1 condition]# ansible-playbook changed_when.yaml
changed: [192.168.134.138] => {
"msg": "test message"
}
前文中总结过handlers的用法,我们知道,只有任务作出了实际的操作时(执行后状态为changed),才会真正的执行对应的handlers,而在某些时候,如果想要通过任务执行后的返回值将任务的最终执行状态判定为changed,则可以使用'changed_when'关键字,以便条件成立时,可以执行对应的handlers。
其实,'changed_when'除了能够在条件成立时将任务的执行状态设置为"changed",还能让对应的任务永远不能是changed状态
当将'changed_when'直接设置为 false 时,对应任务的状态将不会被设置为'changed',如果任务原本的执行状态为'changed',最终则会被设置为'ok'.