Ansible 的条件判断

绝大数语言中,都使用 if 作为条件判断的方法,而在 Ansible 中,条件判断使用关键字 when

简单示例

使用 when 关键字指明条件是:ansible_distribution == “CentOS”,这里的 ansible_distribution 是 facts 信息中的一个 key,我们在调用 ansible_distribution 变量时并没有为它添加 { { var } },这是在 when 关键字中引用变量时,不需要加 { { var } }。如果 ansible_distribution == “CentOS” 这个条件成立,那么就调用 debug 模块,打印 msg 的内容,如果不成立则不执行 debug 模块

# 简单示例
---
- hosts: dbserver
  remote_user: root
  tasks:
  - debug:
      msg: 'system release is centos'
    when: ansible_distribution == "CentOS"

配合循环进行判断

定义条件为 item > 1,只有条件成立时 item 才会被打印,而 with_items 会循环列表中的值,item 变量的值不断变化

---
- hosts: dbserver
  remote_user: root
  tasks:
  - debug:
      msg: '{{ item }}'
    with_items:
    - 1
    - 2
    - 3
    when: item > 1

条件判断通配符

运算符 条件 结果
== 两个值是否相等 相等则为真
!= 两个值是否不相等 不等则为真
> 左边的值大于右边的值 则为真
< 左边的值小于右边的值 则为真
>= 左边的值大于或等于右边的值 则为真
<= 左边的值小于或等于右边的值 则为真

逻辑运算符

运算符 条件 结果
and 当左边与右边同时为真 则返回真
or 当左边与右边有任意一个为真 则返回真
not 对一个操作取反
() 将一组操作包装在一起

逻辑运算和分组示例

---
- hosts: dbserver
  remote_user: root
  tasks:
  - debug:
      msg: 'System release is centos6 or centos7'
    when: ansible_distribution == "CentOS" and (ansible_distribution_major_version == "6" or ansible_distribution_major_version == "7")

判断模块执行返回的信息

我们在执行 shell 命令时,通常需要获取命令的返回信息,这样才能够根据返回的信息,判断之后的操作如何进行下去

---
- hosts: dbserver
  remote_user: root
  tasks:
  - name: touch file1
    shell: "touch /file1"
    register: returnmsg
  - name: debug file1
    debug:
      msg: "Command execution successful"
    when: returnmsg.rc == 0        # 命令执行成功的返回值中rc的值为0
  - name: debug file2
    debug:
      msg: "Command execution failed"
    when: returnmsg.rc != 0

跳过执行遇到的错误

有些时候我们的 tasks 执行到一半时,遇到错误之后就不再继续往下执行了,我们可以使用 ignore_errors 关键字去跳过这个错误,让剧本继续往下执行

---
- hosts: dbserver
  remote_user: root
  tasks:
  - name: touch file1
    shell: "ls /file123"
    register: returnmsg
    ignore_errors: true

  - name: debug file1
    debug:
      msg: "Command execution successful"
    when: returnmsg.rc == 0

  - name: debug file2
    debug:
      msg: "Command execution failed"
    when: returnmsg.rc != 0

条件判断与tests

Linux 系统中可以使用一些常用的判断操作,例如使用 test 命令判断文件或者目录是否存在

test /etc/
echo $?
0

Ansible 中也有类似用于判断文件和目录的方法,注意这个是判断控制节点上的文件和目录,”is exists” | “is not exists”

---
- hosts: dbserver
  remote_user: root
  vars:
    testpath: /etc
  tasks:
  - debug:
      msg: "file exist"
    when: testpath is exists    # 判断testpath变量这个路径是否存在,存在则为真,打印msg内容

ok: [dbserver] => {
    "msg": "file exist"
}

判断变量的 tests

defined:判断变量是否已经定义,已经定义则返回真

undefind:判断变量是否已经定义,未定义则返回真

none:判断变量值是否为空,如果变量已经定义,但是变量值为空,则返回真

定义变量 f1 赋值为 test,定义 h2 但不赋值,debug 模块根据对应的条件是否为真打印具体 msg 内容

---
- hosts: dbserver
  remote_user: root
  tasks:
  vars:
    f1: 'test'
    h2:
  tasks:
    - debug:
        msg: 'varf1 is undefined'
      when: f1 is undefined
    - debug:
        msg: 'The variable is defined, but there is no value'
      when: h2 is none

判断执行结果的 tests

success 或 succeeded:通过任务的返回信息判断任务的执行状态,任务执行成功则返回真

failure 或 failed:通过任务的返回信息判断任务的执行状态,任务执行失败则返回真

change 或 changed:通过任务的返回信息判断任务的执行状态,任务执行状态为 changed 则返回真

skip 或 skipped:通过任务的返回信息判断任务的执行状态,当任务没有满足条件而被跳过执行时,则返回真

使用 shell 模块执行一条命令,并且使用 register 将返回值存进 returnmsg 变量,如果命令执行报错就跳过继续往下执行,下面再判断这个变量的执行结果

---
- hosts: dbserver
  remote_user: root
  tasks:
  - shell: "ls /etc/hosts"
    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 changed
  - debug:
      msg: "skip"
    when: "returnmsg is skip"

判断路径的 tests

file:判断路径是否是一个文件,如果是则返回真

directory:判断路径是否是一个目录,如果是则返回真

link:判断路径是否是一个软链接,如果是则返回真

mount:判断路径是否是一个挂载点,如果是则返回真

exists:判断路径是否存在,如果存在则返回真

判断字符串的 tests

lower:判断包含字母的字符串中的字母是否是纯小写,如果是则返回真

upper:判断包含字母的字符串中的字母是否是纯大写,如果是则返回真

判断整除的 tests

even:判断数值是否是偶数,如果是则返回真

odd:判断数值是否是奇数,如果是则返回真

divisibleby(num):判断是否可以整除指定的数值,如果可以整除则返回真

条件判断与 block

想要在条件成立时,执行多个任务,我们不需要在每个任务中都加入判断条件,我们可以使用 block 关键字将多个任务整合成一个块

---
- hosts: dbserver
  remote_user: root
  tasks:
  - shell: "ls /loo"
    ignore_errors: true
  - block:    # 这个block块有两个任务
      - debug: 
          msg: "run command failed"
      - file:
          path: "/oo"
          state: touch
    when: 2 > 1        # 条件成立就执行block块的任务

block 与 rescue 的错误处理

我们在处理某些复杂的任务时,需要使用到错误处理的判断,使我们的 Playbook 更加灵活。例如我需要执行多个任务,这多个任务中只要有一个执行失败,就会触发错误处理,执行我们提前定义好的救援任务进行补救

---
- hosts: dbserver
  remote_user: root
  tasks:
  - block:
      - shell: "ls /123"
      - debug:
          msg: "tcodmf"
      - file:
          path: "/loo"
          state: touch
    rescue:
      - debug:
          msg: "error"    # 只要block块里面的三个任务有一个执行失败就会执行rescue定义好的任务

block 和 always 的错误处理

如果 block 中的任务执行出错,那么就会执行 rescue 中的任务,如果 block 中的任务执行没有出错,那么 rescue 中的任务就不会执行,但是 always 中的任务是无论如何都会执行的,不管 block 中的内容是否出错

---
- hosts: dbserver
  remote_user: root
  tasks:
  - block:
      - debug:
          msg: "echo 123"
      - command: cat /etc/hosts | wc -l        # command模块不能执行带特殊字符的命令,第一次出错
      - debug:
          msg: "echo 456"

    rescue:
      - debug:
          msg: "echo error1"
      - command: cat /etc/hosts | wc -l        # command模块不能执行带特殊字符的命令,第二次出错

    always:
      - debug:
          msg: "echo error2"    # 最后执行always

条件判断与错误处理

我们有时候需要在判断条件成立时,执行退出的指令,使 Playbook 中断执行,这里我们需要使用到 fail 模块。我们知道,在执行 Playbook 时,如果 Playbook 中的任意一个任务执行失败,Playbook 都会终止执行,而 fail 模块就是天生用来执行失败的模块。只要Playbook 中执行fail模块,Playbook 就会认为有任务执行失败了

---
- hosts: dbserver
  remote_user: root
  tasks:
  - debug:
      msg: "123"
  - debug:
      msg: "456"
  - fail:    # 执行fail模块中断playbook执行,后面的任务不再执行
  - debug:
      msg: "789"

使用 fail 模块终止 Playbook,默认打印 “Failed as requested from task” 的错误提示,这个我们可以自定义 fail 模块的错误提示

---
- hosts: dbserver
  remote_user: root
  tasks:
  - debug:
      msg: "123"
  - debug:
      msg: "456"
  - fail:
      msg: "stop operation playbook"
  - debug:
      msg: "789"

利用条件判断去控制 fail 模块的执行

---
- hosts: dbserver
  remote_user: root
  tasks:
  - shell: "echo 'This is a string for testing--error'"
    register: return_value    # 取到shell模块执行的返回值
  - fail:
      msg: "stop operation playbook"
    when: "'error' in return_value.stdout"    # 判断字符串是否存在于return_value.stdout这个输出信息
  - debug:
      msg: "playbook has stopped"    # 由于fail模块执行而中断playbook,这个将不会执行

failed_when 关键字

---
- hosts: dbserver
  remote_user: root
  tasks:
  - debug:
      msg: "123456"
  - shell: "echo 'This is a string for testing--error'"
    register: return_value
    failed_when: '"error" in return_value.stdout'    # 如果条件成立,那么failed_when就会提示所对应的shell模块执行失败
  - debug:
      msg: "654321"        # 不会被打印

failed_changed 关键字

正常情况下,debug 模块正常执行的情况下只能是 “ok” 状态,我们可以使用 failed_changed 关键字改变执行后的状态定义为 changed

---
- hosts: dbserver
  remote_user: root
  tasks:
  - debug:
      msg: "test message"
    changed_when: 2 > 1

changed: [dbserver] => {
    "msg": "test message"
}