目录

一、循环

二、条件

三、handlers

四、失败的处理


一、循环

使用 loop 关键字对一组项目迭代任务,循环变量 item 保存每个迭代过程中使用的值。

[student@workstation ansible]$ vim loop.yml 

---
- name: Test loop
  hosts: dev
  gather_facts: no
  vars:
    num:
      - one
      - two
      - three
      - four
      - five
  tasks:
    - name: Echo some
      shell: "echo This is {{ item }}"
      loop: "{{ num }}"
      register: echo_results

    - name: Loop register var
      debug:
        msg: "{{ item.stdout }}"
      loop: "{{ echo_results.results }}"

二、条件

when 语句用于有条件地运行任务。它取要测试的条件作为值。如果条件满足, 则运行任务。如果条件不满足,则跳过任务。举例,我们在 webservers 组添加了自定义事实,如果定义了那么安装一下自定义的包,否则跳过。

[student@workstation ansible]$ vim when.yml 

---
- name: Install 
  hosts: all
  tasks:
    - name: Install db_pkg if db_pkg is defined
      yum:
        name: "{{ ansible_facts.ansible_local.myfact.packages.db_pkg }}"
        state: present
      when: ansible_facts.ansible_local.myfact is defined

[student@workstation ansible]$ ansible-playbook when.yml 
......
TASK [Install db_pkg if db_pkg is defined] *************************************************
skipping: [servera.lab.example.com]
skipping: [serverb.lab.example.com]
changed: [serverc.lab.example.com]
changed: [serverd.lab.example.com]
......

三、handlers

Ansible 模块设计为具有幂等性,playbook 及其任务可以运行多次而不会改变受管主机。
handlers 是由其他任务触发的通知的任务。仅当任务在受管主机上被更改,任务才通知handlers。
每个处理程序具有全局唯一的名称,在 playbook 中任务块的末尾触发。
处理程序可视为非活动任务,只有在使用 notify 语句调用时才会被触发。

handlers 在一个 playbook 里面和 tasks 是对齐的。

处理handlers的规范:

  • 处理程序始终按照 play 的 handlers 部分指定的顺序运行。它们不按在任务中由 notify 语句列出的顺序运行,或按任务通知它们的顺序运行。
  • 处理程序通常在相关 play 中的所有其他任务完成后运行。
  • 如果两个处理程序被错误地给予相同的名称,则仅会运行一个。
  • 即使有多个任务通知处理程序,该处理程序依然仅运行一次。如果没有任务通知处理程序,它就不会运行。 

比如,覆盖 /etc/httpd/conf/httpd.conf 配置文件,使 httpd 监听端口改为 8421。这就需要修改 selinux 端口上下文、重启 httpd 服务、配置防火墙入栈规则。顺序一定是先修改 selinux 端口上下文,再重启 httpd 服务,否则因为 selinux 重启 httpd 会失败。

[student@workstation ansible]$ vim handlers.yml 

---
- name: Test handlers
  hosts: webservers
  tasks:
    - name: Httpd listen 8421
      copy:
        src: httpd.conf.new
        dest: /etc/httpd/conf/httpd.conf
      notify: 
        - Allow Apache to listen on tcp port 8421
        - Restart httpd
        - Firewall permit 8421/tcp

  handlers:
    - name: Allow Apache to listen on tcp port 8421
      seport:
        ports: 8421
        proto: tcp
        setype: http_port_t
        state: present

    - name: Restart httpd
      service:
        name: httpd
        state: restarted

    - name: Firewall permit 8421/tcp
      firewalld:
        port: 8421/tcp
        state: enabled
        permanent: yes
        immediate: yes
[student@workstation ansible]$ ansible-playbook handlers.yml

......
PLAY [Test handlers] ******************************************

TASK [Gathering Facts] ****************************************
ok: [serverc.lab.example.com]
ok: [serverd.lab.example.com]

TASK [Httpd listen 8421] **************************************
changed: [serverc.lab.example.com]
changed: [serverd.lab.example.com]

RUNNING HANDLER [Allow Apache to listen on tcp port 8421] *****
changed: [serverc.lab.example.com]
changed: [serverd.lab.example.com]

RUNNING HANDLER [Restart httpd] *******************************
changed: [serverd.lab.example.com]
changed: [serverc.lab.example.com]

RUNNING HANDLER [Firewall permit 8421/tcp] ********************
changed: [serverd.lab.example.com]
changed: [serverc.lab.example.com]
......

[student@workstation ansible]$ curl http://serverc.lab.example.com:8421
Added by ansible.
[student@workstation ansible]$ curl http://serverd.lab.example.com:8421
Added by ansible.

四、失败的处理

block-rescue-always 就类似 java 里面的 try-catch-finally 处理方式,block 升级一下,如果失败那么 rescue 一下,无论如何都有收尾工作放在 always里面。比如,webservers 组的两个服务器有 300 ~ 1000MiB 不同大小的卷组 vg_data,我们创建大小为 800MiB 的逻辑卷 lv_web,如果空间不够就创建大小 200MiB 的逻辑卷 lv_web,最后用 xfs 格式创建文件系统。

[student@workstation ansible]$ vim control.yml 

---
- name: BlockRescueAlways
  hosts: webservers
  vars:
  tasks:
    - name: Create lvm
      block:
        - name: Check 0.8g
          debug:
            msg: "vg_data is less than 0.8g, not enough space"
          when: ansible_facts.lvm.vgs.vg_data is defined and ansible_facts.lvm.vgs.vg_data.free_g | float < 0.8
          failed_when: ansible_facts.lvm.vgs.vg_data is defined and ansible_facts.lvm.vgs.vg_data.free_g | float < 0.8

        - name: Create a logical volume of 0.8g
          lvol:
            vg: vg_data
            lv: lv_web
            size: 800m

      rescue:
        - name: Create a logical volume of 0.2g
          lvol:
            vg: vg_data
            lv: lv_web
            size: 0.2g

      always:
        - name: Create a xfs filesystem
          filesystem:
            fstype: xfs
            dev: /dev/vg_data/lv_web

执行过程

[student@workstation ansible]$ ansible-playbook control.yml 

PLAY [BlockRescueAlways] **********************************************************************

TASK [Gathering Facts] ************************************************************************
ok: [serverd.lab.example.com]
ok: [serverc.lab.example.com]

TASK [Check 0.8g] *****************************************************************************
fatal: [serverc.lab.example.com]: FAILED! => {
    "msg": "vg_data is less than 0.8g, not enough space"
}
skipping: [serverd.lab.example.com]

TASK [Create a logical volume of 0.8g] ********************************************************
changed: [serverd.lab.example.com]

TASK [Create a logical volume of 0.2g] ********************************************************
changed: [serverc.lab.example.com]

TASK [Create a xfs filesystem] ****************************************************************
changed: [serverd.lab.example.com]
changed: [serverc.lab.example.com]
.......

检查结果,看到创建 lv_web 的大小是不同的。

[student@workstation ansible]$ ansible webservers -a "lvs"
serverd.lab.example.com | CHANGED | rc=0 >>
  LV     VG      Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  root   cl      -wi-ao---- <17.00g                                                    
  swap   cl      -wi-ao----   2.00g                                                    
  lv_web vg_data -wi-a----- 800.00m                                                    
serverc.lab.example.com | CHANGED | rc=0 >>
  LV     VG      Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  root   cl      -wi-ao---- <17.00g                                                    
  swap   cl      -wi-ao----   2.00g                                                    
  lv_web vg_data -wi-a----- 208.00m