1、When语句

有时候用户有可能需要某一个主机越过某一个特定的步骤.这个过程就可以简单的像在某一个特定版本的系统上少装了一个包一样或者像在一个满了的文件系统上执行清理操作一样.

这些操作在Ansible上,若使用`when`语句都异常简单.When语句也含Jinja2表达式,

第一个例子:

tasks:  - name: "shutdown Debian flavored systems"    command: /sbin/shutdown -t now    when: ansible_os_family == "Debian"如果你在RedHat系列linux系统执行,就不会被执行

第二个例子:

#cat copyfile.yml ---- hosts: "`host`"  user: "`user`"  gather_facts: True  tasks:    - name: Copy file to client      copy: src=/etc/ansible/test.txt dest=/usr/local/src      when: ansible_os_family == "Debian"    - include: add_user.yml      when: ansible_os_family == "Debian"执行: #ansible-playbook copyfile.yml -e "host=web user=root"     --可以看到下面都skipping掉了PLAY ***************************************************************************TASK [setup] *******************************************************************ok: [10.0.90.26]ok: [10.0.90.25]TASK [Copy file to client] *****************************************************skipping: [10.0.90.25]skipping: [10.0.90.26]TASK [include] *****************************************************************skipping: [10.0.90.25]skipping: [10.0.90.26]PLAY RECAP *********************************************************************10.0.90.25                 : ok=1    changed=0    unreachable=0    failed=0   10.0.90.26                 : ok=1    changed=0    unreachable=0    failed=0   以上yml中的任务都没有执行,因为我测试机器是CentOS系统!而条件是只有当系统是Debian类型的时候执行!

PS:文件中的include模块后续会介绍。

第三个例子:

tasks:  - shell: echo "only on Red Hat 6, derivatives, and later"    when: ansible_os_family == "RedHat" and ansible_distribution_major_version|int  >= 6意思是只有当系统是RedHat并且版本大于等于6的时候执行

第三个例子:只有在server组或者名为server的这台服务器才执行

- name: Copy file to client      copy: src=/etc/ansible/test.txt dest=/usr/local/src      when: "host=='server'"

带管道的when语句

tasks:  - command: /bin/false    register: result    ignore_errors: True  - command: /bin/something    when: result|failed  - command: /bin/something_else    when: result|success  - command: /bin/still/something_else    when: result|skipped

判断变量是否已经定义:

如果一个变量不存在,你可以使用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 not defined

2、debug模块

Print statements during execution 

打印执行过程中的语句,通常用来调试编写好的playbook语句,

Examples# Example that prints the loopback address and gateway for each host- debug: msg="System {
{ inventory_hostname }} has uuid {
{ ansible_product_uuid }}"- debug: msg="System {
{ inventory_hostname }} has gateway {
{ ansible_default_ipv4.gateway }}"  when: ansible_default_ipv4.gateway is defined- shell: /usr/bin/uptime  register: result- debug: var=result verbosity=2- name: Display all variables/facts known for a host  debug: var=hostvars[inventory_hostname] verbosity=4

生产环境遇到的一个案例:

有2台server:

第一台:10.0.90.25安装了nginx,

第二台:10.0.90.26没有安装nginx

现在我只想在没有安装nginx的server上做操作,需要通过when条件语句实现,如下:

#cat test1.yml---- hosts: web  remote_user: root  tasks:    - name: ps      shell: ps -ef | grep nginx | grep -v grep|wc -l      register: nginx_num    - debug: var=nginx_num    - name: command       copy: src=/etc/ansible/server.xml dest=/root      when: nginx_num.stdout == "0"

PS:刚开始的时候,没有添加- debug: var=nginx_num这一项,结果执行的时候,总是skipping跳过,说明条件错误后来才使用debug模块调试

执行结果:

#ansible-playbook  test1.yml PLAY ***************************************************************************TASK [setup] *******************************************************************ok: [10.0.90.25]ok: [10.0.90.26]TASK [ps] **********************************************************************changed: [10.0.90.25]changed: [10.0.90.26]TASK [debug] *******************************************************************ok: [10.0.90.25] => {    "nginx_num": {        "changed": true,         "cmd": "ps -ef | grep nginx | grep -v grep|wc -l",         "delta": "0:00:00.008476",         "end": "2016-05-19 20:40:51.742088",         "rc": 0,         "start": "2016-05-19 20:40:51.733612",         "stderr": "",         "stdout": "3",         "stdout_lines": [            "3"        ],         "warnings": []    }}ok: [10.0.90.26] => {    "nginx_num": {        "changed": true,         "cmd": "ps -ef | grep nginx | grep -v grep|wc -l",         "delta": "0:00:00.009458",         "end": "2016-05-19 20:40:51.754993",         "rc": 0,         "start": "2016-05-19 20:40:51.745535",         "stderr": "",         "stdout": "0",         "stdout_lines": [            "0"        ],         "warnings": []    }}TASK [command] *****************************************************************skipping: [10.0.90.25]changed: [10.0.90.26]PLAY RECAP *********************************************************************10.0.90.25                 : ok=3    changed=1    unreachable=0    failed=0   10.0.90.26                 : ok=4    changed=2    unreachable=0    failed=0

可以看到跳过了10.0.90.25,只在10.0.90.26上执行了命令。

范例1:

#cat test2.yml ---- hosts: 10.0.90.25  user: root  gather_facts: True  tasks:    - name: test debug module      debug: msg="System {
{ inventory_hostname }} has uuid {
{ ansible_product_uuid }}"#ansible-playbook test2.yml PLAY ***************************************************************************TASK [setup] *******************************************************************ok: [10.0.90.25]TASK [test debug module] *******************************************************ok: [10.0.90.25] => {    "msg": "System 10.0.90.25 has uuid 564DB430-3121-EEE4-33F1-559FEF576AC9"}PLAY RECAP *********************************************************************10.0.90.25                 : ok=2    changed=0    unreachable=0    failed=0

范例2:

#cat test3.yml ---- hosts: 10.0.90.25  user: root  gather_facts: True  tasks:    - debug: msg="System {
{ inventory_hostname }} has gateway {
{ ansible_default_ipv4.gateway }}"      when: ansible_default_ipv4.gateway is defined说明:只有当远端server的gateway配置的情况下才执行,执行结果如下:#ansible-playbook test3.yml PLAY ***************************************************************************TASK [setup] *******************************************************************ok: [10.0.90.25]TASK [debug] *******************************************************************ok: [10.0.90.25] => {    "msg": "System 10.0.90.25 has gateway 10.0.90.1"}PLAY RECAP *********************************************************************10.0.90.25                 : ok=2    changed=0    unreachable=0    failed=0   将10.0.90.25网关配置去掉,再一次执行:#ansible-playbook test3.yml PLAY ***************************************************************************TASK [setup] *******************************************************************ok: [10.0.90.25]TASK [debug] *******************************************************************skipping: [10.0.90.25]PLAY RECAP *********************************************************************10.0.90.25                 : ok=1    changed=0    unreachable=0    failed=0   说明:因为将远端server的网关配置去掉了,when条件不成立,就skipping了。

3、notify和Handlers

handlers 用于在发生改变时执行的操作。notify这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之的是仅在所有的变化发生完成后一次性地执行指定操作。比如多个resources指出因为一个配置文件被改动,所以apache需要重新启动,但是重新启动的操作只会被执行一次。在notify中列出的操作称为handler也即notify调用handler中定义的操作,Handlers也是一些task的列表,通过名字来引用,他们和一般的task并没有什么区别。Handlers是由通知者进行notify,如果没有被notify,handlers不会执行,不管有多少个通知者进行了notify,等到play中的所有task执行完成之后,handlers也只会被执行一次。

注意:Handlers 最佳的应用场景是用来重启服务,或者触发系统重启操作.除此以外很少用到了,而且它会按照声明的顺序执行

如下一个例子:

自定义好httpd.conf配置文件(有变量),拷贝到/etc/httpd/conf目录,然后启动httpd,并设置开机自启动!

#cat test3.yml ---- hosts: web  remote_user: root  gather_facts: True  vars:    http_port: 80    max_clients: 200  tasks:    - name: ensure apache is at the latest version      yum: pkg=httpd state=latest    - name: copy httpd config file to client       copy: src=/etc/ansible/httpd_test.config dest=/etc/httpd/conf/      notify:      - restart apache    - name: ensure apache is running      service: name=httpd state=started  handlers:    - name: restart apache      service: name=httpd state=restarted

执行:

#ansible-playbook test3.yml PLAY ***************************************************************************TASK [setup] *******************************************************************ok: [10.0.90.25]ok: [10.0.90.26]TASK [ensure apache is at the latest version] **********************************changed: [10.0.90.26]changed: [10.0.90.25]TASK [copy httpd config file to client] ****************************************changed: [10.0.90.26]changed: [10.0.90.25]TASK [ensure apache is running] ************************************************ok: [10.0.90.26]ok: [10.0.90.25]RUNNING HANDLER [restart apache] ***********************************************changed: [10.0.90.26]changed: [10.0.90.25]PLAY RECAP *********************************************************************10.0.90.25                 : ok=5    changed=3    unreachable=0    failed=0   10.0.90.26                 : ok=5    changed=3    unreachable=0    failed=0

注:此处定义的notify是restart,就是安装好httpd并拷贝好配置文件之后。

notify也可以是restarted、stopped、reloaded

enabled=yes是表示设置httpd开机自启动。

如果再次执行,就不会有任何改变了。因为httpd已经启动了

#ansible-playbook test3.yml PLAY ***************************************************************************TASK [setup] *******************************************************************ok: [10.0.90.25]ok: [10.0.90.26]TASK [ensure apache is at the latest version] **********************************ok: [10.0.90.25]ok: [10.0.90.26]TASK [copy httpd config file to client] ****************************************ok: [10.0.90.26]ok: [10.0.90.25]TASK [ensure apache is running] ************************************************ok: [10.0.90.26]ok: [10.0.90.25]PLAY RECAP *********************************************************************10.0.90.25                 : ok=4    changed=0    unreachable=0    failed=0   10.0.90.26                 : ok=4    changed=0    unreachable=0    failed=0