Bootstrap

Linux Ansible任务控制(循环判断、处理程序、失败任务)

目录

Ansible的Loop循环

简单的Loop循环

数组列表方式的Loop循环

字典方式的Loop循环

基于外部变量的Loop循环

Ansible的When判断

通过魔法变量、事实变量作为条件

通过剧本执行结果的变量来作为条件

Ansible处理程序

Ansible处理失败任务

处理失败任务ignore_errors

强制执行失败的任务对应的处理程序force_handlers

指定任务失败的条件failed_when

通过Ansible块block处理错误任务


Ansible的Loop循环

在playbook中使用循环语句,可以批量的执行任务(例如批量创建用户、批量安装应用等)

在loop关键字中定义要循环的元素列表,然后通过固定变量名为item来依次提取loop中的元素列表

简单的Loop循环

创建用户admin1和admin2

---
- name: create users with loop
  hosts: web
  tasks:
    - name: create user
      user:
        name: "{{ item }}"    
      loop:
        - admin1
        - admin2

数组列表方式的Loop循环

创建普通用户admin1,系统用户admin2

---
- name: create users with loop
  hosts: web
  tasks:
    - name: create user
      user:
        name: "{{ item.user }}"
        group: "{{ item.shell }}"
      loop:
        - user: admin1
          shell: /bin/bash
        - user: admin2
          shell: /sbin/nologin

字典方式的Loop循环

创建普通用户admin1,系统用户admin2

---
- name: create users with loop
  hosts: web
  tasks:
    - name: create user
      user:
        name: "{{ item.name }}"
        shell: "{{ item.shell }}"
      loop:
        - { name: "admin1" , shell: "/bin/bash" }                                       
        - { name: "admin2" , shell: "/sbin/nologin" }     

基于外部变量的Loop循环

创建普通用户admin1,系统用户admin2

定义变量文件
vim user.yml
users:
  - name: admin1
    shell: /bin/bash
  - name: admin2
shell: /sbin/nologin

定义剧本
vim create_user.yml
---
- name: create users with loop
  hosts: web
  vars_files:
    - user.yml
  tasks:
    - name: create user
      user:
        name: "{{ item.name }}"
        shell: "{{ item.shell }}"
        state: present
      loop: "{{ user }}"

Ansible的When判断

可以通过when关键字来定义判断语句,只有这个判断语句成功了才会执行此模块任务,不满足条件就不执行

When判断语句格式

when: 跟上判断表达式

比较运算符

==         两边是否相等

!=           两边是否不相等

:             比较大小,左边的值大于右边的值为真

<            比较大小,左边的值小于右边的值为真

=            比较大小,左边的值大于等于右边的值为真

<=         比较大小,左边的值小于等于右边的值为真

逻辑运算符

and        逻辑与;都满足才成功

or          逻辑或;只要有一个条件满足,就成功

not         逻辑否;对表达式进行取反

()            将其多个表达式组合到一起(组合内的所有表达式要同时满足)

通过魔法变量、事实变量作为条件

如果主机属于资产清单中web主机组中的主机,则安装httpd(invenrtory_hostname为魔法变量)

---
- name: yum 
  hosts: all
  tasks:
    - name: install httpd
      yum:
        name: httpd
        state: latest
      when: inventory_hostname in groups.web

如果主机存在IPv4地址,则安装httpd(ansible_facts为事实变量)

---
- name: yum 
  hosts: all
  tasks:
    - name: install httpd
      yum:
        name: httpd
        state: latest
      when: ansible_facts['default_ipv4']['address'] is defined

通过剧本执行结果的变量来作为条件

以rc变量举例子

当通过剧本安装软件包时,执行结果中会有rc变量,rc变量有0和1两种值

如果rc=0,表示此安装包已经存在或之前不存在但是安装成功

如果rc=1,表示此安装包不存在,安装失败

可以通过register关键字来将执行结果定义到某个变量中,然后再提取出此变量中rc变量对应的值来作为判断条件(也可以通过debug模块将执行结果显示出来)

安装httpd,并显示执行结果;如果主机上已经存在httpd,则删除httpd

---
- name: install
  hosts: all
  tasks:
    - name: install httpd
      yum:
        name: httpd
        state: present
      register: result

    - name: debug
      debug:
        var: result

    - name: renove httpd
      yum:
        name: httpd
        state: absent
      when: result.rc == 0


Ansible处理程序

Ansible处理程序是指响应其他任务而触发的任务,触发的任务就为处理程序

只有当响应任务在被管理节点执行并生效后(执行结果为黄色),才会触发处理程序;并且处理程序是在playbook中所有任务完成后才会运行

handlers元素

handlers元素属于和tasks同级的列表,作用是定义处理程序

等待tasks中任务执行的结果为changed(黄色)时触发notify,然后调用handlers下的此notify所对应的任务

notify元素

notify元素作为handlers的触发器,在tasks中的某段代码中定义,与模块并列

实例

当httpd和phpinfo安装成功后,开启httpd和phpinfo服务

---
- name: httpd
  hosts: web
  tasks:
    - name: install httpd
      yum:
        name: httpd
        state: present
      notify:
        - start httpd
  handlers:
    - name: start httpd
      service:
        name: httpd
        state: started     

注意事项

handler执行的顺序只与playbook定义的顺序有关,与handler配置的notify的顺序无关

handlers中的- name的名字需要与notify定义的名字一致

处理程序只有在使用notify语句调用时才会被触发

处理程序是在playbook的正常任务全部执行结束后才会被执行

handler里面的任务只会执行依次,即使handler中的一个任务被通知了多次


Ansible处理失败任务

处理失败任务ignore_errors

当ansibke任务执行失败时,就会中止playbook的执行,并跳过所有后续任务

当有时希望即使在任务失败时,忽略此处的错误,继续执行后续任务,此时就需要配置ignore_error:yes来实现(ignore_error元素与模块并列)

注意事项

并不是所有的错误都可以忽略,只有当任务的执行成功或失败对后面的任务没有关联的时候才可以忽略

实例

当php安装失败后继续执行mariadb的安装

---
  - name: install
    hosts: server
    tasks:
          - name: install php
            yum:
              name: php
              state: present
            ignore_errors: yes

          - name: isntall mariadb
            yum:
              name: mariadb
              tate: present
            ignore_errors: yes

强制执行失败的任务对应的处理程序force_handlers

如果在主机上的执行的任务失败时,则此任务对应的处理程序不再运行

此时可以通过force_handlers: yes实现,即使notify对应的响应任务执行失败,仍继续执行noftify对应的处理程序(即使任务失败了也要调用notify触发handlers)

force_handlers与tasks同层级

实例

---
- name: httpd
  hosts: web
  force_handlers: yes
  tasks:
    - name: install httpd
      yum:
        name: httpd
        state: present
      notify:
        - start httpd
  handlers:
    - name: start httpd
      service:
        name: httpd
        state: started

指定任务失败的条件failed_when

通过failed_when来指定任务失败的条件;即人为指定此任务失败的条件,将正常的任务转为失败的任务(如果满足failed_when定义的条件,则就判断此任务执行失败)

注意

任务执行失败不一定就是任务存在错误(也有可能是人为制造的)

实例

如果主机属于ftp组,则显示bug模块的内容,然后中止任务

---
- name: httpd
  hosts: all
  tasks:
    - name: deubg
      debug:
        msg: "hostname is not web"
      when: inventory_hostname in groups['ftp']
      failed_when: inventory_hostname in groups['ftp']

    - name: copy
      copy:
        content: "Welcome to {{ ansible_facts.hostname }}"
        dest: /var/www/index.html

通过Ansible块block处理错误任务

在playbook中,通过块block可以对任务进行逻辑分组,可以实现错误处理

通过块block可以结合rescue和always语句来实现错误处理

block与when、rescue、always是同一级别,位于tasks之下

如果块block中的任何任务失败,则执行其rescue中的任务来进行

block、rescue、always概念

block:定义要运行的主要任务(block中的任何一个task出错,会顺序执行rescue中的task)

rescue:定义 当在block子句中定义的任务失败时 运行的任务

always:定义始终都独立运行的任务,不论block和rescue子句中定义的任务是成功还是失败

block任务执行成功 → 直接走always中的任务(不执行rescue对应的任务)

block任务执行失败 → 走rescue中的任务 → 走always中的任务

实例

对vdc磁盘分区,分为1500m(如果磁盘无法分为1500m则分为800m),最后将磁盘格式化为ext4格式

---
- name: create /dev/vdc
  hosts: web
  tasks:
    - name: block
      block:
        - name: create vdc1 1000MiB
          parted:
            device: /dev/vdc
            number: 1
            state: present
            part_end: 1000MiB
      rescue:
        - name: create vdc 500MiB
          parted:
            device: /dev/vdc
            number: 1
            state: present
            part_end: 500MiB
      always:
        - name: create ext4
          filesystem:
            fstype: ext4
            dev: /dev/vdc1

;