Ansible playbook 条件处理


原文链接: Ansible playbook 条件处理

节讲如何控制playbook的执行流,记得前面说过playbook和模板文件中可以使用jinja2语法么,这节就会大量用到了。

首先,要讲下setup这个模块,作用类似salt的grains,用于获取远程服务器的信息(以一个字典返回),这些获取到的信息在template模块定义的模板文件和playbook文件中可以直接使用,该模块获取的结果又叫facts:

$ ansible 127.0.0.1 -m setup
127.0.0.1 | success >> {

"ansible_facts": {
    "ansible_all_ipv4_addresses": [
        "192.168.1.5"
    ], 
    "ansible_all_ipv6_addresses": [
        "fe80::a00:27ff:fead:a141"
    ], 
    "ansible_architecture": "i386", 
    "ansible_bios_date": "12/01/2006", 
    "ansible_bios_version": "VirtualBox", 
    "ansible_cmdline": {
        "KEYBOARDTYPE": "pc", 
        "KEYTABLE": "us", 
        "LANG": "en_US.UTF-8", 
        "SYSFONT": "latarcyrheb-sun16", 
        "quiet": true, 
        "rd_NO_DM": true, 
        "rd_NO_LUKS": true, 
        "rd_NO_LVM": true, 
        "rd_NO_MD": true, 
        "rhgb": true, 
        "ro": true, 
        "root": "UUID=ebfa916e-fc91-4f0e-bb2d-7f7c4e48aeca"
    }, 
    ...
    "ansible_userspace_architecture": "i386", 
    "ansible_userspace_bits": "32", 
    "ansible_virtualization_role": "guest", 
    "ansible_virtualization_type": "virtualbox", 
    "module_setup": true
}, 
"changed": false

}
在模板文件中通过{{ var }}来使用这些获取到的信息,假如我有一个模板文件os.j2:

{% if ansible_distribution == "FreeBSD" %}
FreeBSD
{% elif ansible_distribution == "CentOS" %}
CentOS
{% endif %}

hostname: {{ ansible_hostname }}

when语句

when语句的作用是只有匹配指定条件,才执行task,when后面使用jinja2的表达方式

例子:只关闭操作系统为Debian的服务器

  • hosts: all
    tasks:
    • name: "shutdown Debian flavored systems"
      command: /sbin/shutdown -t now #只有Debian系统才会执行该command
      when: ansible_os_family == "Debian" #这里ansible_os_family变量就是通过setup模块获取的
      jiaja2模板的过滤器也可以使用,ansible也提供了一些自己的过滤器:

tasks:

  • name: test
    shell: ps aux|grep nginx|grep -v grep|wc -l
    register: cmd_result
    failed_when: cmd_result.stdout|int == 0 #使用jinja2的"int"过滤器

  • command: /bin/false
    register: result
    ignore_errors: True #忽略该task的错误

  • command: /bin/something
    when: result|failed #通过结果判断上一个task如果执行失败,则执行该task

  • command: /bin/something_else
    when: result|success #通过结果判断上一个task如果执行成功,则执行该task

  • command: /bin/still/something_else
    when: result|skipped
    自定义变量:

vars:
epic: true
tasks:

  • shell: echo "I've got '{{ epic }}' and am not afraid to use it!"
    when: epic is defined #变量已定义

  • fail: msg="Bailing out: this play requires 'epic'"
    when: epic is not defined #变量未定义

  • shell: echo "This certainly is epic!"
    when: epic #变量值为真

  • shell: echo "This certainly isn't epic!"
    when: not epic #变量值为假
    当when用于循环中时,是对列表中的每一项都进行检查:

tasks:

- command: echo {{ item }}
  with_items: [ 0, 2, 4, 6, 8, 10 ]
  when: item > 5

在roles和include中使用when指令,when不能用在包含一个playbook文件上,且当包含一个task文件时,会对task文件中的每个task都会使用一次when判断:

  • hosts: all
    tasks:
    • include: tasks/sometasks.yml
      when: "'reticulating splines' in output"
      roles:
      • { role: debian_stock_config, when: ansible_os_family == 'Debian' } #首先判断远程主机是否是Debian,是的话才会导入这个role
        当执行这个play的时候,输出中可能会出现很多的skipped,这些就是经过when的条件判断不符合,跳过执行的输出。

条件导入:


  • hosts: all
    remote_user: root
    vars_files: #用于导入变量文件
    • [ "vars/{{ ansible_os_family }}.yml", "vars/os_defaults.yml" ]
      tasks:
    • name: make sure apache is running
      service: name={{ apache }} state=running
      根据不同的系统导入不同变量文件,如果是CentOS系统则首先导入vars/CentOS.yml文件(Debian系统则会首先导入vars/Debian.yml),如果该文件不存在则导入vars/os_defaults.yml文件,如果两个文件都不存在则生成一个错误,vars/CentOS.yml文件内容如下:


for vars/CentOS.yml

apache: httpd
somethingelse: 42
基于变量选择文件或模板:

  • name: template a file
    template: src={{ item }} dest=/etc/myapp/foo.conf
    with_first_found:
    • files:
      • {{ ansible_distribution }}.conf #CentOS系统会使用CentOS.conf文件,Debian系统会使用Debian.conf文件
      • default.conf
        paths:
      • search_location_one/somedir/
      • /opt/other_location/somedir/


register
register用于注册一个变量,保存命令的结果(shell或command模块),这个变量可以在后面的task、when语句或模板文件中使用,该指令用在循环中会有不同,请看ansible学习之八:Loops中关于register的讲解

  • shell: /bin/pwd
    register: pwd_result
    此时变量pwd_result的结果为:

{

u'changed': True, 
u'end': u'2014-02-23 12:02:51.982893', 
u'cmd': [u'/bin/pwd'], 
u'start': u'2014-02-23 12:02:51.980191', 
u'delta': u'0:00:00.002702', 
u'stderr': u'', 
u'rc': 0,           #这个就是命令返回状态,非0表示执行失败
'invocation': {'module_name': 'command', 'module_args': '/bin/pwd'}, 
u'stdout': u'/home/sapser',    #以一个字符串保存命令结果
'stdout_lines': [u'/home/sapser']     #以列表保存命令结果

}
在随后的task中使用该变量:

  • debug: msg="{{pwd_result}}"
    when: pwd_result.rc == 0
    循环处理命令结果:

  • 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 #等同于with_items: home_dirs.stdout.split()

`