ansible笔记(13)之条件判断

ansible笔记(13)之条件判断

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

本来打算自己写一波 ansible 系列的,后来发现一老哥写的太好了,「点击此处直达」,我这里也就边看边对该系列文章做下笔记,方便以后查阅,ansible 入门的话墙裂建议阅读前方链接博文~~~

在 ansible 中,条件判断的关键字是 when,使用 when 关键字为任务指定条件,条件成立,则执行任务,条件不成立,则不执行任务。

when 关键字中引用变量时,变量名不需要加 {{ }}

字符串判断

在 ansible 中使用 == 就可以判断字符串是否相同,还可通过如下关键字判断字符串大小写的状态:

  • lower:判断包含字母的字符串中的字母是否是纯小写,字符串中的字母全部为小写则返回真;
  • upper:判断包含字母的字符串中的字母是否是纯大写,字符串中的字母全部为大写则返回真;

除此之外,还可通过 in 关键字判断指定字符串是否存在于另一个字符串中。

例 1:判断当前操作主机的系统是不是 CentOS。

---
- hosts: all
  tasks:
  - debug:
      msg: "System release is CentOS"
    when: ansible_distribution == "CentOS"

例 2:判断给定字符串的大小写状态。

---
- hosts: B
  gather_facts: no
  vars:
    str1: "abc"
    str2: "ABC"
  tasks:
  - debug:
      msg: "This string is all lowercase"
    when: str1 is lower
  - debug:
      msg: "This string is all uppercase"
    when: str2 is upper

例 3:判断给定字符串变量值是否存在于 hello world 字符串中。

---
- hosts: B
  gather_facts: no
  vars:
    str1: "hello"
    str2: "hello world"
  tasks:
  - debug:
      msg: "{{str1}} in {{str2}}"
    when: str1 in str2

运算符判断

在 ansible 中,我们可以使用如下比较运算符:

  • ==:比较两个对象是否相等,相等为真;
  • !=:比较两个对象是否不等,不等为真;
  • >:比较两个值的大小,如果左边的值大于右边的值,则为真;
  • <:比较两个值的大小,如果左边的值小于右边的值,则为真;
  • >=:比较两个值的大小,如果左边的值大于右边的值或左右相等,则为真;
  • <=:比较两个值的大小,如果左边的值小于右边的值或左右相等,则为真;

我们总结的这些运算符其实都是 jinja2 的运算符,ansible 使用 jinja2 模板引擎,在 ansible 中也可以直接使用 jinja2 的这些运算符。

说完了比较运算符,再来说说逻辑运算符,可用的逻辑运算符如下

  • and:逻辑与,当左边与右边同时为真,则返回真;
  • or:逻辑或,当左边与右边有任意一个为真,则返回真;
  • not:取反,对一个操作体取反;
  • ( ):组合,将一组操作体包装在一起,形成一个较大的操作体;

例 1:输出大于 2 的数字。

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      var: item
    when: item > 2
    with_items: [ 1, 2, 3 ]

例 2:判断客户机系统是否是 CentOS 7。

---
- hosts: all
  tasks:
  - debug:
      msg: "System release is centos7"
    when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7"

# 这里的 when 条件也可写为如下:
#    when:
#    - ansible_distribution == "CentOS"
#    - ansible_distribution_major_version == "7"
# 其含义为列表中每一项结果都为 true 时才执行。

例 3:判断任务是否成功执行。

---
- hosts: B
  gather_facts: no
  tasks:
  - name: task1
    shell: "ls /testabc"
    register: returnmsg
    ignore_errors: true
# 如果任务执行失败 ansible 默认会立即停止继续往下执行,使用 ignore_errors 可以忽略失败的错误,让其正常向下执行
  - name: task2
    debug:
      msg: "Command execution successful"
    when: returnmsg.rc == 0
  - name: task3
    debug:
      msg: "Command execution failed"
    when: returnmsg.rc != 0

文件判断

ansible 可通过如下关键字对文件状态进行判断:

  • file:判断路径是否是一个文件,如果路径是一个文件则返回真;
  • directory:判断路径是否是一个目录,如果路径是一个目录则返回真;
  • link:判断路径是否是一个软链接,如果路径是一个软链接则返回真;
  • mount:判断路径是否是一个挂载点,如果路径是一个挂载点则返回真;
  • exists:判断路径是否存在,如果路径存在则返回真;

注意哦,这里的文件路径是 ansible 管理机的路径。

例:判断 /testdir 是否存在。

---
- hosts: B
  gather_facts: no
  vars:
    testpath: /testdir
  tasks:
  - debug:
      msg: "file exist"
    when: testpath is exists
# 取反可使用 not,下面判断表示 testpath 路径是否不存在
# when: testpath is not exists

变量判断

ansible 可通过如下几个关键字对变量进行判断:

  • string:判断对象是否是一个字符串,是字符串则返回真;
  • number:判断对象是否是一个数字,是数字则返回真;
  • defined:判断变量是否已经定义,已经定义则返回真;
  • undefind:判断变量是否已经定义,未定义则返回真;
  • none:判断变量值是否为空,如果变量已经定义,但是变量值为空,则返回真;

例 1:当对应的条件为真时,你可以看到 debug 模块对应的输出。

---
- hosts: B
  gather_facts: no
  vars:
    testvar: "test"
    testvar1:
  tasks:
  - debug:
      msg: "Variable is defined"
    when: testvar is defined
  - debug:
      msg: "Variable is undefined"
    when: testvar2 is undefined
  - debug:
      msg: "The variable is defined, but there is no value"
    when: testvar1 is none

例 2:判断给定变量是一个字符串还是数字。

---
- hosts: B
  gather_facts: no
  vars:
    testvar: "a"
  tasks:
  - debug:
      msg: "{{testvar}} is a number"
    when: testvar is number
  - debug:
      msg: "{{testvar}} is a string"
    when: testvar is string

结果判断

ansible 可通过如下几个关键字来对任务的执行结果进行判断:

  • successsucceeded:通过任务的返回信息判断任务的执行状态,任务执行成功则返回真;
  • failurefailed:通过任务的返回信息判断任务的执行状态,任务执行失败则返回真;
  • changechanged:通过任务的返回信息判断任务的执行状态,任务执行状态为 changed 则返回真;
  • skipskipped:通过任务的返回信息判断任务的执行状态,当任务没有满足条件,而被跳过执行时,则返回真;

例:根据任务执行结果输出对应信息。

---
- hosts: B
  gather_facts: no
  vars:
    doshell: "yes"
  tasks:
  - shell: "cat /testdir/abc"
    when: doshell == "yes"
    register: returnmsg
    ignore_errors: true
  - debug:
      msg: "success"
    when: returnmsg is success
  - debug:
      msg: "failed"
    when: returnmsg is failure
  - debug:
      msg: "changed"
    when: returnmsg is change
  - debug:
      msg: "skip"
    when: returnmsg is skip

整除判断

ansible 可通过如下关键字对一个数字进行整除判断:

  • even:判断数值是否是偶数,是偶数则返回真;
  • odd:判断数值是否是奇数,是奇数则返回真;
  • divisibleby(num):判断是否可以整除指定的数值,如果除以指定的值以后余数为0,则返回真;

看如下示例:

---
- hosts: B
  gather_facts: no
  vars:
    num1: 4
    num2: 7
    num3: 64
  tasks:
  - debug:
      msg: "An even number"
    when: num1 is even
  - debug:
      msg: "An odd number"
    when: num2 is odd
  - debug:
      msg: "Can be divided exactly by 8"
    when: num3 is divisibleby(8)

列表父子集判断

ansible 可使用如下关键字对列表进行父子集判断:

  • subset:判断一个 list 是不是另一个 list 的子集,是另一个 list 的子集时返回真;
  • superset : 判断一个 list 是不是另一个 list 的父集,是另一个 list 的父集时返回真;

看如下示例:

---
- hosts: B
  gather_facts: no
  vars:
    a:
    - 2
    - 5
    b: [1,2,3,4,5]
  tasks:
  - debug:
      msg: "A is a subset of B"
    when: a is subset(b)
  - debug:
      msg: "B is the parent set of A"
    when: b is superset(a)

版本判断

在 ansible 中 version 关键字可以用于对比两个版本号的大小,或者与指定的版本号进行对比,使用语法为 version('版本号', '比较操作符')

version 支持的比较操作符如下:

  • 大于:>gt
  • 大于等于:>=ge
  • 小于:<lt
  • 小于等于:<=le
  • 等于:===eq
  • 不等于:!=<>ne

看如下示例:

---
- hosts: B
  vars:
    ver: 7.4.1708
    ver1: 7.4.1707
  tasks:
  - debug:
      msg: "This message can be displayed when the ver is greater than ver1"
    when: ver is version(ver1,">")
  - debug:
      msg: "system version {{ansible_distribution_version}} greater than 7.3"
    when: ansible_distribution_version is version("7.3","gt")

# ver_val is version(ver1, ">") 表示 ver_val 是否大于 ver1 版本

合并判断

在 ansible 中,可以使用 block 关键字将多个任务整合成一个块,这个块将被当做一个整体,我们可以对这个块添加判断条件,当条件成立时,则执行这个块中的所有任务。

我们来看一个小示例,如下:

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      msg: "task1 not in block"
  - block:
      - debug:
          msg: "task2 in block1"
      - debug:
          msg: "task3 in block1"
    when: 2 > 1

状态判断

failed_when 的作用就是,当对应的条件成立时,将对应任务的执行状态设置为失败,我们可以借助 failed_when 关键字来完成类似 fail 模块的功能。

看下面示例:

---
- hosts: B
  gather_facts: no
  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"

上例中,failed_when 对应的条件是 "error" in return_value.stdout,表示 error 字符串如果存在于 shell 模块执行后的标准输出中,则条件成立,当条件成立后,shell 模块的执行状态将会被设置为失败,由于 shell 模块的执行状态被设置为失败,所以 playbook 会终止运行,于是,最后的 debug 模块并不会被执行。

理解了' failed_when'关键字以后,顺势理解'changed_when'关键字就容易多了。

failed_when 关键字的作用是在条件成立时,将对应任务的执行状态设置为失败。
changed_when 关键字的作用是在条件成立时,将对应任务的执行状态设置为 changed

有了前文作为基础,就不再对 changed_when 做过多解释了,我们直接来看一个小示例:

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      msg: "test message"
    changed_when: 2 > 1

我们知道,debug 模块在正常执行的情况下只能是 ok 状态,上例中,我们使用 changed_when 关键字将 debug 模块的执行后的状态定义为了 changed,你可以尝试执行上例 playbook,执行效果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
changed: [B] => {
    "msg": "test message"
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

前文中总结过 handlers 的用法,我们知道,只有任务作出了实际的操作时(执行后状态为 changed),才会真正的执行对应的handlers,而在某些时候,如果想要通过任务执行后的返回值将任务的最终执行。

其实,changed_when 除了能够在条件成立时将任务的执行状态设置为 changed,还能让对应的任务永远不能是 changed 状态,示例如下:

---
- hosts: B
  gather_facts: no
  tasks:
  - shell: "ls /opt"
    changed_when: false

当将 changed_when 直接设置为 false 时,对应任务的状态将不会被设置为 changed,如果任务原本的执行状态为 changed,最终则会被设置为 ok,所以,上例 playbook 执行后,shell 模块的执行状态最终为 ok

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/ansible13.html

Buy me a cup of coffee ☕.