Ansible:when 子句中的多个和/或条件

问题描述 投票:0回答:3

尝试在when语句中使用多个和/或条件来决定是否需要运行任务时遇到问题。基本上,我正在制作一个剧本来进行自动系统修补,其中包含安全补丁、仅内核补丁的选项以及在 var 文件中指定包。

我使用以下命令运行剧本,并通过扩展变量选项 (-e) 定义变量

ansible-playbook site.yml -i inventory --ask-vault -u (username) -e "security=true restart=true" -k -K

默认情况下,剧本将更新系统上除内核之外的每个包,但如果我指定了几个变量中的任何一个,我想跳过该操作。我的代码如下:

- name: Update all packages
  yum:
     name: "*"
     state: latest
     exclude: "kernel*"
  when: security is not defined or kernel is not defined  or specified_packages 
 is not defined and ansible_os_family == "RedHat" 

我尝试了以下所有组合:

when: (ansible_os_family == "RedHat") and (security is defined or kernel is defined or specified_packages is defined)

when: (ansible_os_family == "RedHat") and (security == true or kernel == true or specified_packages == true )
<- this case throws a not defined error because i don't define all variables every time i run the playbook

when: ansible_os_family == "RedHat"
 when: security is defined or kernel is defined or specified_packages is defined

注意:我知道并使用了额外的变量(例如“skip”)来跳过此任务并使用when子句

when: ansible_os_family == "RedHat" and skip is not defined
,但不希望我的用户需要使用额外的变量来跳过此默认操作.

我也没有使用标签,因为我正在收集升级前后的软件包列表,以便最终进行比较和报告,因此我将无法运行它们,因为它们是本地操作命令。这就是为什么我使用一个角色并通过扩展变量打开和关闭多个任务。我愿意接受任何以更有效的方式重写剧本的建议,因为我有点菜鸟。

ansible ansible-2.x
3个回答
18
投票

这是一个如此简单的答案!

以下作品:

when: not (security is defined or kernel is defined or specified_packages is defined) and ansible_os_family == "RedHat"

9
投票

正如 @techraf 在评论中指出的那样,

defined
/
undefined
是一个令人讨厌的测试......

像这样重构:

when:
  - ansible_os_family == "RedHat"
  - security|d('') != '' or kernel|d('') != '' or specified_packages|d('') != ''

更新。可重现的示例:

- hosts: localhost
  gather_facts: no
  tasks:
    - debug:
      msg: hello
      when:
        - '"RedHat" == "RedHat"'
        - security|d('') != '' or kernel|d('') != '' or specified_packages|d('') != ''

执行:

ansible-playbook -e kernel=true playbook.yml

PLAY [localhost] ***************************************************************

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": "hello"
}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0

版本:

$ pip list | grep -iP 'ansible|jinja'
ansible (2.2.1.0)
Jinja2 (2.8)

3
投票

我刚刚遇到了类似的问题,需要测试两个不同的变量以查看它们是否为“true”,但它们并不总是存在于输出 json 中。所需的基本逻辑是:

( a is defined ) and ( a == 'present' or a == 'reinstalled' )

在本例中,a 是“install_vs2022_status.inspiration.module_args.state”,以下三种不同的场景产生了正确的结果:

直接:

when: (install_vs2022_status.invocation.module_args.state is defined) and (install_vs2022_status.invocation.module_args.state == 'reinstalled' or install_vs2022_status.invocation.module_args.state == 'present')

分布式:

when: (install_vs2022_status.invocation.module_args.state is defined and install_vs2022_status.invocation.module_args.state == 'present') or (install_vs2022_status.invocation.module_args.state is defined and install_vs2022_status.invocation.module_args.state == 'reinstalled')

分成暗示“与”或“交集”的行,除非第一项计算结果为 false 时停止。

when:
  - install_vs2022_status.invocation.module_args.state is defined
  - install_vs2022_status.invocation.module_args.state == 'reinstalled' or install_vs2022_status.invocation.module_args.state == 'present'

每种情况下最重要的因素是首先进行存在性测试,以防止评估不存在的变量。

编辑:刚刚学会了如何使用多行“或”条件:

- name: get process list
  shell: ps -ef
  when: >
    ("passed" in env_status.stdout) or
    ("fixed" in env.status.stdout)

当我寻找多个“或”时,这使得它更具可读性,并且括号可用于和/或的多个组合。

© www.soinside.com 2019 - 2024. All rights reserved.