Skip to content

06. 条件

1. when 语句

when 语句就是条件语句。

该语句可以包含不带双花括号的原生的 Jinja2 表达式:

tasks:
  - name: "shut down Debian flavored systems"
    command: /sbin/shutdown -t now
    when: ansible_facts['os_family'] == "Debian"

Important

所有的变量都可以在when字句中像这样不带双花括号直接使用!

还可以使用括号对条件进行分组:

when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
      (ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")

若需要满足多个条件还可以这样写:

when:
  - ansible_facts['distribution'] == "CentOS"
  - ansible_facts['distribution_major_version'] == "6"

还能使用很多的 Jinja2 “tests” and “filters”,其中一些是 ansible 提供的:

tasks:
  - command: /bin/false
    register: result
    ignore_errors: True

  - command: /bin/something
    when: result is failed

  # In older versions of ansible use ``success``, now both are valid but succeeded uses the correct tense.
  - command: /bin/something_else
    when: result is succeeded

  - command: /bin/still/something_else
    when: result is skipped

在 playbooks 或 inventory 中定义的变量也能使用,仅需要注意使用|bool过滤器来应用到你想要的一些值上面:

vars:
  epic: true
  monumental: "yes"
tasks:
    - shell: echo "This certainly is epic!"
      when: epic or monumental|bool
# or
tasks:
    - shell: echo "This certainly isn't epic!"
      when: not epic

判断是否定义了变量:

tasks:
    - shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
      when: foo is defined

    - fail: msg="Bailing out. this play requires 'bar'"
      when: bar is undefined

2. 条件导入

静态导入会将条件应用到被导入的文件中每个 task 身上。动态导入则不会。

所以静态导入适合每个 task 都适用于同一个条件的情况。

例如:

# main.yml
- import_tasks: other_tasks.yml # note "import"
  when: x is not defined

# other_tasks.yml
- set_fact:
    x: foo
- debug:
    var: x

在导入之后相当于:

- set_fact:
    x: foo
  when: x is not defined
- debug:
    var: x
  when: x is not defined

set_fact 被执行后, debug 就不会再执行了。使用 include_tasks 即可解决该问题。

3. 根据变量选择文件与模板

可以根据变量名的不同导入不同的文件:

---
- hosts: all
  remote_user: root
  vars_files:
    - "vars/common.yml"
    - [ "vars/{{ ansible_facts['os_family'] }}.yml", "vars/os_defaults.yml" ]
  tasks:
  - name: make sure apache is started
    service: name={{ apache }} state=started

若是 Red Hat 操作系统,ansible 会先试图导入 vars/RedHat.yml 文件,若没有该文件则导入 vars/os_defaults.yml 文件,若还没有则抛出错误。

- name: template a file
  template:
      src: "{{ item }}"
      dest: /etc/myapp/foo.conf
  loop: "{{ query('first_found', { 'files': myfiles, 'paths': mypaths}) }}"
  vars:
    myfiles:
      - "{{ansible_facts['distribution']}}.conf"
      -  default.conf
    mypaths: ['search_location_one/somedir/', '/opt/other_location/somedir/']

找到第一个可用文件作为模板。