tasks: - name: Configure SELinux to start mysql on any port ansible.posix.seboolean: name: mysql_connect_any state: true persistent: true when: ansible_selinux.status == "enabled" # all variables can be used directly in conditionals without double curly braces
基于 ansible_facts 的条件语句
通常,您希望根据事实来执行或跳过任务。事实是单个主机的属性,包括 IP 地址、操作系统、文件系统的状态等等。使用基于事实的条件语句:
- name: Show facts available on the system ansible.builtin.debug: var: ansible_facts
这是一个基于事实的条件语句示例:
tasks: - name: Shut down Debian flavored systems ansible.builtin.command: /sbin/shutdown -t now when: ansible_facts['os_family'] == "Debian"
如果有多个条件,可以使用括号将它们组合在一起。
tasks: - name: Shut down CentOS 6 and Debian 7 systems ansible.builtin.command: /sbin/shutdown -t now when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or (ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")
tasks: - ansible.builtin.shell: echo "only on Red Hat 6, derivatives, and later" when: ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb']['major_release'] | int >= 6
您可以将 Ansible 事实存储为变量,以用于条件逻辑,如下例所示:
tasks: - name: Get the CPU temperature set_fact: temperature: "{{ ansible_facts['cpu_temperature'] }}"
- name: Restart the system if the temperature is too high when: temperature | float > 90 shell: "reboot"
- name: check registered variable for emptiness hosts: all
tasks:
- name: List contents of directory ansible.builtin.command: ls mydir register: contents
- name: Check contents for emptiness ansible.builtin.debug: msg: "Directory is empty" when: contents.stdout == ""
Ansible 始终为每个主机在已注册变量中注册某些内容,即使在任务失败或 Ansible 由于条件未满足而跳过任务的主机上也是如此。要在这些主机上运行后续任务,请查询已注册变量的 is skipped(而不是“undefined”或“default”)。有关详细信息,请参见 注册变量。以下是基于任务成功或失败的条件语句示例。如果希望 Ansible 在发生错误时继续在主机上执行,请记住忽略错误。
tasks: - name: Register a variable, ignore errors and continue ansible.builtin.command: /bin/false register: result ignore_errors: true
- name: Run only if the task that registered the "result" variable fails ansible.builtin.command: /bin/something when: result is failed
- name: Run only if the task that registered the "result" variable succeeds ansible.builtin.command: /bin/something_else when: result is succeeded
- name: Run only if the task that registered the "result" variable is skipped ansible.builtin.command: /bin/still/something_else when: result is skipped
- name: Run only if the task that registered the "result" variable changed something. ansible.builtin.command: /bin/still/something_else when: result is changed
tasks: - name: Run the command if "epic" or "monumental" is true ansible.builtin.shell: echo "This certainly is epic!" when: epic or monumental | bool
- name: Run the command if "epic" is false ansible.builtin.shell: echo "This certainly isn't epic!" when: not epic
如果未设置所需的变量,您可以使用 Jinja2 的 defined 测试来跳过或失败。例如:
tasks: - name: Run the command if "foo" is defined ansible.builtin.shell: echo "I've got '{{ foo }}' and am not afraid to use it!" when: foo is defined
- name: Fail if "bar" is undefined ansible.builtin.fail: msg="Bailing out. This play requires 'bar'" when: bar is undefined
这与 vars 文件的条件导入(见下文)结合使用特别有用。如示例所示,您无需使用 {{ }} 来在条件语句中使用变量,因为这些变量已经隐含。
在循环中使用条件语句
如果将 when 语句与 循环 结合使用,Ansible 会分别处理每个项目的条件。这是设计使然,因此您可以对循环中的某些项目执行任务,而跳过其他项目。例如:
tasks: - name: Run with items greater than 5 ansible.builtin.command: echo {{ item }} loop: [ 0, 2, 4, 6, 8, 10 ] when: item > 5
- name: Skip the whole task when a loop variable is undefined ansible.builtin.command: echo {{ item }} loop: "{{ mylist|default([]) }}" when: item > 5
在循环遍历字典时,也可以执行相同的操作:
- name: The same as above using a dict ansible.builtin.command: echo {{ item.key }} loop: "{{ query('dict', mydict|default({})) }}" when: item.value > 5
# all tasks within an imported file inherit the condition from the import statement # main.yml - hosts: all tasks: - import_tasks: other_tasks.yml # note "import" when: x is not defined
# other_tasks.yml - name: Set a variable ansible.builtin.set_fact: x: foo
- name: Print a variable ansible.builtin.debug: var: x
Ansible 在执行时将其扩展为等效于以下内容:
- name: Set a variable if not defined ansible.builtin.set_fact: x: foo when: x is not defined # this task sets a value for x
- name: Do the task if "x" is not defined ansible.builtin.debug: var: x when: x is not defined # Ansible skips this task, because x is now defined
# using a conditional on include_* only applies to the include task itself # main.yml - hosts: all tasks: - include_tasks: other_tasks.yml # note "include" when: x is not defined
现在,如果x最初未定义,则调试任务不会被跳过,因为条件是在 include 时进行评估的,并且不适用于各个任务。
向角色本身内的各个任务或块添加条件。这是唯一允许您根据when语句选择或跳过角色中某些任务的方法。要选择或跳过角色中的任务,您必须在各个任务或块上设置条件,在您的剧本中使用动态include_role,并将条件添加到 include。当您使用此方法时,Ansible 会将条件应用于 include 本身以及角色中也具有该when语句的任何任务。
- name: check value of return code ansible.builtin.debug: var: bar_status.rc
- name: check test for rc value as string ansible.builtin.debug: var: bar_status.rc == "127"
- name: check test for rc value as integer ansible.builtin.debug: var: bar_status.rc == 127
TASK [check value of return code] ********************************************************************************* ok: [foo-1] => { "bar_status.rc": "127" }
TASK [check test for rc value as string] ************************************************************************** ok: [foo-1] => { "bar_status.rc == \"127\"": false }
TASK [check test for rc value as integer] ************************************************************************* ok: [foo-1] => { "bar_status.rc == 127": true }