有时候我们希望在某些情况对特定主机执行、不执行一些操作。例如给某主机安装特定的软件,或者在磁盘快满时执行清理工作。
when
when语句就是用来实现这个功能的,它是一个jinja2的语法,但是不需要双大括号,他真的很简单:
tasks:
- name: "shut down Debian flavored systems"
command: /sbin/shutdown -t now
when: ansible_os_family == "Redhat"
# 注意 Ansible facts和vars 比如 ansible_os_family 应能被引用
# 直接写,不带双大括号。
- 可以用小括号来组织一组条件:
tasks:
- name: "shut down CentOS 6 and Debian 7 systems"
command: /sbin/shutdown -t now
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or
(ansible_distribution == "Debian" and ansible_distribution_major_version == "7")
- 多重条件需要同时生效才为真(逻辑与),用一个list来写:
tasks:
- name: "shut down CentOS 7 systems"
command: /sbin/shutdown -t now
when:
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "7"
一些jinja2的“filter”可以在条件语句里使用,其中部分filter由ansible提供。这里假设我们需要忽略错误返回信息,然后基于success和failure来决定执行一些动作。
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|succeeded
- command: /bin/still/something_else
when: result|skipped
register在后面会说
有时候想对字符串类型的返回变量中使用数学运算符,可以这样做:
tasks:
- shell: echo "only on Red Hat 6, derivatives, and later"
when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6
还可以使用在playbook或者inventory中定义的变量的布尔值来判断。
vars:
epic: true
然后在task中这样引用判断:
tasks:
- shell: echo "This certainly is epic!"
when: epic
或者:
tasks:
- shell: echo "This certainly isn't epic!"
when: not epic
如果需要的变量还没有定义,则可以使用jinja2的defined测试语句来跳过或退出并返回错误信息:
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
这特别适用于var导入的情况,同时在when语句中,变量依然不用{{ }}来表示。(已经隐含了)
循环与条件
把when和with_item结合起来,when语句将会多次在with_item中被执行。
tasks:
- command: echo {{ item }}
with_items: [ 0, 2, 4, 6, 8, 10 ]
when: item > 5
如果需要根据定义的循环变量跳过整个任务,则使用| default过滤器来提供一个空的迭代器:
- command: echo {{ item }}
with_items: "{{ mylist|default([]) }}"
when: item > 5
字典型也可以:
- command: echo {{ item.key }}
with_dict: "{{ mydict|default({}) }}"
when: item.value > 5
这部分在loop中会学到。
register
在playbook中,把一个命令的结果存在一个变量中并提供后续调用,以这种方式使用命令模块可以在很多方面消除编写site specific facts的需要,例如你可以检测一个特定的程序是否存在。
register关键字决定哪个变量的结果去存入。可以在template,cation line,when语句中使用:
- name: test play
hosts: all
tasks:
- shell: cat /etc/motd
register: motd_contents
- shell: echo "motd contains the word hi"
when: motd_contents.stdout.find('hi') != -1
在上面的例子中,register变量名为motd_contents
,它可以使用stdout
方法调用,这里调用的是/etc/motd
中的返回结果,如果结果中有'hi'
字符,第二个cation就会被执行。
with_item
- name: registered variable usage as a with_items list
hosts: all
tasks:
- name: retrieve the list of home directories
command: ls /home
register: home_dirs
- name: add home dirs to the backup spooler
file: path=/mnt/bkspool/{{ item }} src=/home/{{ item }} state=link
with_items: "{{ home_dirs.stdout_lines }}"
# same as with_items: "{{ home_dirs.stdout.split() }}"
上面的例子中,把第一个cation的结果保存在了register变量home_dirs
中,在第二个action的item位置,使用with_item的输出语句来作为结果写入。
还可以用一个空字符来检查registered变量中的内容:
- name: check registered variable for emptiness
hosts: all
tasks:
- name: list contents of directory
command: ls mydir
register: contents
- name: check contents for emptiness
debug: msg="Directory is empty"
when: contents.stdout == ""