• Ansible的when语句做条件判断


    环境

    • 控制节点:Ubuntu 22.04
    • Ansible 2.10.8
    • 管理节点:CentOS 8

    使用 when 语句做条件判断

    创建文件 test1.yml 如下:

    ---
    - hosts: all
      tasks:
        - name: task1
          debug:
            msg: "hello"
          when: 1 > 0
    
        - name: task2
          debug:
            msg: "OK"
          when: 1 > 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    运行结果如下:

    ......
    TASK [task1] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "hello"
    }
    
    TASK [task2] ***************************************************************************************
    skipping: [192.168.1.55]
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    可见,task满足条件,所以运行了;task2不满足条件,所以没有运行。

    多个条件之间可以做逻辑运算(与或非),比如:

          when: ((1 > 0) and (1 < 2)) or (not (1 == 3))
    
    • 1

    多个 and 条件,也可以写成list的形式,比如:

          when:
            - 1 < 2
            - 2 < 3
            - 3 < 4
    
    • 1
    • 2
    • 3
    • 4

    基于 ansible_facts 的条件判断

    例如:

        - name: task3
          debug:
            msg: "hello"
          when: ansible_facts['os_family'] == "RedHat" #"Debian"
    
    • 1
    • 2
    • 3
    • 4

    也可以先把ansible_facts先存为变量,再对变量做条件判断,比如:

        - name: task5
          block:
            - name: part1
              set_fact:
                version: "{{ ansible_facts['distribution_major_version'] }}"
            - name: part2
              debug:
                msg: "Horse"
              when: version | int >= 8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注:先用filter把变量转为int类型,再和整数8比较大小。

    基于register变量的条件判断

    这是一种常见的用法,上一个task把结果记录在变量里,下一个task根据该变量的值做条件判断。

    ---
    - hosts: all
      tasks:
        - name: task1
          shell: cat /tmp/a.txt | wc -l
          register: result
        - name: task2
          debug:
            msg: "More than 100 lines!"
          when: result.stdout | int > 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 当文件超过100行时,结果如下:
    ......
    TASK [task2] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "More than 100 lines!"
    }
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    当文件不超过100行时,结果如下:

    ......
    TASK [task2] ***************************************************************************************
    skipping: [192.168.1.55]
    ......
    
    • 1
    • 2
    • 3
    • 4

    对register变量,可作如下判断:

    • is failed
    • is succeeded
    • is skipped
    • is changed

    例如:

    ---
    - hosts: all
      tasks:
      - name: task1
        ansible.builtin.command: /bin/false
        register: result
        ignore_errors: true
    
      - name: task2
        debug:
          msg: "Task fails!"
        when: result is failed
    
      - name: task3
        debug:
          msg: "Task succeeds!"
        when: result is succeeded
    
      - name: task4
        debug:
          msg: "Task skipped!"
        when: result is skipped
    
      - name: task5 
        debug:
          msg: "Task changed!"
        when: result is changed
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    基于变量的条件判断

    注意: when 语句里的变量,不需要加 {{ }}

    变量可转换成bool类型,例如:

    ---
    - hosts: all
      vars:
        - var1: true
        - var2: false
        - var3: "yes"
        - var4: "no"
      tasks:
        - name: task1
          debug:
            msg: "task1"
          when: var1
        - name: task2
          debug:
            msg: "task2"
          when: not var2
        - name: task3
          debug:
            msg: "task3"
          when: var3 | bool
        - name: task4
          debug:
            msg: "task4"
          when: not (var4 | bool)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    使用没有定义的变量会报错,所以,在使用变量前,可以先判断其是否定义:

    • is defined
    • is undifined

    例如:

    ---
    - hosts: all
      tasks:
        - name: task1
          debug:
            msg: "OK"
          when: var1 is defined and var1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这是一种非常常见的用法。

    在循环里使用条件判断

    loopwhen 可以一起用,对每次循环做条件判断。例如,遍历文件每一行,若内容超过2个字符,则打印其内容:

    ---
    - hosts: all
      tasks:
        - name: task1
          shell: cat /tmp/a.txt
          register: result
        - name: task2
          debug:
            msg: "{{ item }}"
          loop: "{{ result.stdout_lines }}"
          when: item | length > 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    假设 a.txt 内容如下:

    aaaaa
    b
    ccccc
    
    • 1
    • 2
    • 3

    则运行结果如下:

    TASK [task2] ***************************************************************************************
    ok: [192.168.1.55] => (item=aaaaa) => {
        "msg": "aaaaa"
    }
    skipping: [192.168.1.55] => (item=b) 
    ok: [192.168.1.55] => (item=ccccc) => {
        "msg": "ccccc"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    也可以遍历/判断自定义的list或者dict,例如:

    ---
    - hosts: all
      vars:
        - mylist1: [ 1, 2, 3 ]
        - mydict1: {"a": 10, "b": 20, "c": 30}
      tasks:
        - name: task1
          debug:
            msg: "{{ item }}"
          loop: "{{ mylist1 }}"
          when: item > 1
        - name: task2
          debug:
            msg: "{{ item }}"
          loop: "{{ query('dict', mydict1) }}"
          when: item.value > 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    运行结果如下:

    ......
    TASK [task1] ***************************************************************************************
    skipping: [192.168.1.55] => (item=1) 
    ok: [192.168.1.55] => (item=2) => {
        "msg": 2
    }
    ok: [192.168.1.55] => (item=3) => {
        "msg": 3
    }
    
    TASK [task2] ***************************************************************************************
    skipping: [192.168.1.55] => (item={'key': 'a', 'value': 10}) 
    ok: [192.168.1.55] => (item={'key': 'b', 'value': 20}) => {
        "msg": {
            "key": "b",
            "value": 20
        }
    }
    ok: [192.168.1.55] => (item={'key': 'c', 'value': 30}) => {
        "msg": {
            "key": "c",
            "value": 30
        }
    }
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    注意,最好也判断一下变量是否定义,比如:

        - name: task3
          debug:
            msg: "{{ item }}"
          loop: "{{ mylist2 }}"
          when: mylist2 is defined and item > 1
    
        - name: task4
          debug:
            msg: "{{ item }}"
          loop: "{{ query('dict', mydict2) }}"
          when: mydict2 is defined and item.value > 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    或者提供一个缺省的空list/dict,例如:

        - name: task5
          debug:
            msg: "{{ item }}"
          loop: "{{ mylist2 | default([]) }}"
          when: item > 1
    
        - name: task6
          debug:
            msg: "{{ item }}"
          loop: "{{ query('dict', mydict2 | default({})) }}"
          when: item.value > 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注意:task3和task4会skip,而task5和task6会运行。

    import和include的条件判断

    先看include。例如, main.yml 内容如下:

    ---
    - hosts: all
      tasks:
        - name: task1
          include_tasks: test11.yml
          #import_tasks: test11.yml
          when: var1 is not defined
          #vars:
          #  - var1: 111
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    test11.yml 内容如下:

    ---
    - name: task1
      debug:
        msg: "var1 = {{ var1 }}"
      when: var1 is defined
    
    - name: task2
      debug:
        msg: "I am  task2"
    
    - name: task3
      set_fact:
        var1: 123
      when: var1 is not defined
    
    - name: task4
      debug:
        msg: "var1 = {{ var1 }}"
      when: var1 is defined
    
    - name: task5
      debug:
        msg: "I am task5"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    main.yml 中没有定义 var1 ,则运行结果如下:

    TASK [main_task1] **********************************************************************************
    included: /root/temp/temp1113_2/test11.yml for 192.168.1.55
    
    TASK [task1] ***************************************************************************************
    skipping: [192.168.1.55]
    
    TASK [task2] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am  task2"
    }
    
    TASK [task3] ***************************************************************************************
    ok: [192.168.1.55]
    
    TASK [task4] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "var1 = 123"
    }
    
    TASK [task5] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am task5"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    main.yml 中定义了 var1 ,则运行结果如下:

    TASK [main_task1] **********************************************************************************
    skipping: [192.168.1.55]
    
    • 1
    • 2

    include_tasks 的逻辑比较直观:

    • 如果 main.yml 没有定义 var1 ,则满足条件,运行 test11.yml
    • 如果 main.yml 定义了 var1 ,则不满足条件,不运行 test11.yml

    现在,把 include_tasks 换成 import_taskstest11.yml 内容不变。

    main.yml 中没有定义 var1 ,则运行结果如下:

    TASK [task1] ***************************************************************************************
    skipping: [192.168.1.55]
    
    TASK [task2] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am  task2"
    }
    
    TASK [task3] ***************************************************************************************
    ok: [192.168.1.55]
    
    TASK [task4] ***************************************************************************************
    skipping: [192.168.1.55]
    
    TASK [task5] ***************************************************************************************
    skipping: [192.168.1.55]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    main.yml 中定义了 var1 ,则运行结果如下:

    TASK [task1] ***************************************************************************************
    skipping: [192.168.1.55]
    
    TASK [task2] ***************************************************************************************
    skipping: [192.168.1.55]
    
    TASK [task3] ***************************************************************************************
    skipping: [192.168.1.55]
    
    TASK [task4] ***************************************************************************************
    skipping: [192.168.1.55]
    
    TASK [task5] ***************************************************************************************
    skipping: [192.168.1.55]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    import_tasks 的运行结果和 include_tasks 大不相同。这是因为, import_tasks 是在预编译期,就把引用的task替换过来了(注意在运行结果里并没有出现 main_task1 的字眼),所以就相当于把 when 的条件判断放到 test11.yml 的每个task里了:

    ---
    - name: task1
      debug:
        msg: "var1 = {{ var1 }}"
      when: var1 is defined and var1 is not defined
    
    - name: task2
      debug:
        msg: "I am  task2"
      when: var1 is not defined
    
    - name: task3
      set_fact:
        var1: 123
      when: var1 is not defined and var1 is not defined
    
    - name: task4
      debug:
        msg: "var1 = {{ var1 }}"
      when: var1 is defined and var1 is not defined
    
    - name: task5
      debug:
        msg: "I am task5"
      when: var1 is not defined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    这样就能理解运行结果了。

    注意: main_task1 里的变量定义,并没有放到 test11.yml 的每个task里。

    创建文件 main.yml 如下:

    ---
    - hosts: all
      tasks:
        - name: main_task1
          import_tasks: test13.yml
          vars:
            - var1: 111
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    创建文件 test13.yml 如下:

    ---
    - name: task1
      debug:
        msg: "var1 = {{ var1 }}"
      when: var1 is defined
    
    - name: task2
      set_fact:
        var1: 123
    
    - name: task3
      debug:
        msg: "var1 = {{ var1 }}"
      when: var1 is defined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    运行结果如下:

    TASK [task1] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "var1 = 111"
    }
    
    TASK [task2] ***************************************************************************************
    ok: [192.168.1.55]
    
    TASK [task3] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "var1 = 123"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    可见,task1和task3打印的 var1 变量值并不相同。前者是从 main.yml 而来,后者是从task2而来。

    注:关于 import_xxxinclude_xxx ,参见我另一篇文档。

    调试

    最简单的方法就是打印出来看一下。比如:

    ---
    - hosts: all
      tasks:
        - name: task1
          set_fact:
            var1: '123'
    
        - name: task2
          debug:
            msg: "var1 = {{ var1 }}"
          when: var1 == 123
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行结果如下:

    TASK [task1] ***************************************************************************************
    ok: [192.168.1.55]
    
    TASK [task2] ***************************************************************************************
    skipping: [192.168.1.55]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以看到,task2被skip了,这是因为 when 语句没有满足条件。

    要确认的话,可以把条件判断的结果打印出来:

    ......
        - name: task3
          debug:
            var: var1 == 123
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行结果如下:

    ......
    TASK [task3] ***************************************************************************************
    ok: [192.168.1.55] => {
        "var1 == 123": false
    }
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    可见条件判断的结果确实是false。

    注意:用的是 debugvar 打印条件判断的结果。

    接下来,可以打印出来变量看一下其值:

    ......
        - name: task4
          debug:
            var: var1
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行结果如下:

    ......
    TASK [task4] ***************************************************************************************
    ok: [192.168.1.55] => {
        "var1": "123"
    }
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    可见 var1 的值是 "123" ,是一个字符串(如果是数值则是 123 )。

    当然,更直接的办法是查看一下 var1 的类型:

    ......
        - name: task5
          debug:
            msg: "{{ var1 | type_debug }}"
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行结果如下:

    ......
    TASK [task5] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "AnsibleUnicode"
    }
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果是数值,则类型是 int

    因为 var1 是字符串,而 123 是整数,所以task2的判断条件不满足。

    修改方法为:

    原先为: var1 == 123
    应改为: var1 == '123' ,或者 var1 | int == 123

    参考

    • https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html
  • 相关阅读:
    [ROS](10)ROS通信 —— 服务(Service)通信
    百择电商:抖音超级福袋怎么使用?
    Intel汇编-内联汇编使用处理跳转
    作物检测:YOLOv8+SwanLab
    Github每日精选(第44期):磁盘工具diskusage
    猿创征文 |【C++】动态内存的分配与回收
    web前端之float布局与flex布局
    乡愁
    创新与重塑,佛塑科技打造集团型 CRM 建设标杆
    深度学习笔记
  • 原文地址:https://blog.csdn.net/duke_ding2/article/details/134388100