ansible的任务执行控制

  • 一、循环
  • 1、简单循环
  • 2、循环散列或字典列表
  • 二、条件判定
  • 1、when条件语句
  • 2、条件判断
  • 三、触发器
  • 四、 处理失败任务
  • 1、ignore_errors
  • 2、force_handlers
  • 3、changed_when
  • 4、failed_when
  • 5、block


  • 实验环境

此处参考:

共四台主机,server1~server4,server1为ansible主机,其他三台为被控端,均开启火墙;
将server2~server4加入资源清单;
在server1主机上拥有ansible用户skk,并单独配置ansible环境,在其他三台主机上创建devops用户,用visudo免密授权,将server1的公钥分发给其他三台主机的devops用户。

一、循环

1、简单循环

使用loop赋值列表的格式:

loop:  ##赋值列表
- value1
- value2
- ...
{{item}}  ##迭代变量名称

(1)在playbook中使用

vim user.yml

---
- name: create user
  hosts: server2
  tasks:
    - name: create user
      user:
        name: "{{item}}"  ##迭代变量名称
        state: present
      loop:  ##赋值列表
        - user1
        - user2
        - user3

ansible 主机依次执行 ansible执行模式_devops

建立用户成功

ansible 主机依次执行 ansible执行模式_devops_02

(2)通过文件定义变量

编写变量文件

vim user_list.yml

---
USERS:  ##定义变量
  - user1
  - user2
  - user3

编写yaml文件

vim user.yml

---
- name: create user
  hosts: server2
  vars_files: ./user_list.yml
  tasks:
    - name: create user
      user:
        name: "{{item}}"
        state: absent
        remove: yes
      loop:
        "{{USERS}}"  ##此处赋值时不用加-

删除用户成功

ansible 主机依次执行 ansible执行模式_devops_03

2、循环散列或字典列表

  • 可以赋予不同的服务不同的状态

示例:为server3主机建立用户,并赋予密码

(1)此处的密码必须是加密过后的,使用rhel8openssl passwd -6将密码加密

ansible 主机依次执行 ansible执行模式_linux_04

vim user.yml

---
- name: create user
  hosts: server3
  tasks:
    - name: create user
      user:
        name: "{{ item.user }}"
        password: "{{ item.passwd }}"
        state: present
      loop:
        - user: user1
          passwd: "$6$P2MmG.dGe59uEe0R$SVmq6oojHWvYVK.BZhmL7pWjb7zVKRkUM.Rp2kFbLtl7jS570ZClaVPRZkX9BtfkqlLLCbTrlG7a04YRi/wz3."
        - user: user2
          passwd: "$6$YZcSU4GwSVBnw.ro$wQ0fAO9lB2M1Nwu9tVyBoGiEV/qOzQGBY.UHw2pQiq0GEjYpNW3c2FtG/wWZ0iVpqZi.iCo1x18LjpJg9tGTK/"
        - user: user3
          passwd: "$6$lqv/hz7ynndCR9NR$BmhKzFUsW4XzP9x9eAXv782gYBnxWUGFnh1qYExYwof5PSPk36GnlDKjjeygCSohM0cpncmk.1mkljEAgX3FQ1"

ansible 主机依次执行 ansible执行模式_devops_05

测试连接:

ansible 主机依次执行 ansible执行模式_linux_06

二、条件判定

1、when条件语句

此条件代表两者都满足时

when:
- 条件1
- 条件2

此条件代表两者满足一个即可

when:
- 条件1 or 条件2

也可以表示为

when:
- 条件1
  or
  条件2

示例:检测文件是否存在
ignore_errors: yes:当文件不存在时,系统会判定失败,没有返回值,加此参数可以忽略错误

vim exist.yml

---
- name: test
  hosts: demo
  tasks:
    - name: test
      shell: test -e /mnt/file  ##使用shell模块检测文件是否存在
      ignore_errors: yes
      register: OUTPUT  ##将得到的结果注册给OUTPUT变量
      
    - name: show message
      debug:
        msg: /mnt/file is exist
      when: OUTPUT.rc == 0  ##输出的结果rc部分为0,文件存在
      
    - name: show message
      debug:
        msg: /mnt/file is not exist
      when: OUTPUT.rc == 1  ##输出的结果rc部分为1,文件不存在

在server4主机上创建/mnt/file,在server2和server3上不创建,执行yaml文件

ansible 主机依次执行 ansible执行模式_ansible 主机依次执行_07

2、条件判断

=

value == "字符串“,value == 数字

<

value < 数字

>

value > 数字

<=

value <= 数字

>=

value >= 数字

!=

value != 数字

is defined

value is defined(变量存在)

is not defined

value is not defined(变量不存在)

in

value is in value(变量为)

not in

value is not in value(变量不为)

bool变量为true

value(value的值为true)

bool变量false

not value(value的值为false)

value in value2(value的值在value2列表中)

示例:添加磁盘,利用条件语句对磁盘进行检测

(1)为server2主机添加磁盘

ansible 主机依次执行 ansible执行模式_devops_08

通过ansible语句可以检测到

ansible server2 -m shell -a "fdisk -l /dev/vdb"

ansible 主机依次执行 ansible执行模式_ansible_09

(2)编写yaml文件,检测是否存在vdb磁盘

vim vdb.yml

---
- name: test
  hosts: demo
  tasks:
    - name: show message
      debug:
        msg: /dev/vdb is exist
      when:
        - ansible_facts['devices']['vdb'] is defined  ##vdb存在时
        - inventory_hostname in "server2"  ##hostname为server2时,与上面条件须同时满足
        
    - name: show message
      debug:
        msg: /dev/vdb is not find
      when:
        - ansible_facts['devices']['vdb'] is not defined
          or
          inventory_hostname not in "server2"  ##vdb不存在或hostname不为server2时,也可以写到一行

(3)执行yaml文件,得到结果

ansible 主机依次执行 ansible执行模式_ansible_10

三、触发器

notify:触发器当遇到更改时触发handlershandlers:触发器触发后执行的动作

示例:安装下载vsftpd并修改访问家目录
1、编写yaml文件

vim vsftpd.yml

---
- name: vsftpd
  hosts: server4
  tasks:
    - name: install vsftpd
      yum:
        name: vsftpd
        state: present
    - name: start vsftpd
      service:
        name: vsftpd
        state: started
        enabled: yes
      notify:
        - firewalld  ##当vsftpd服务被设定开机自启后,触发firewalld模块

    - name: vsftpd.conf
      lineinfile:
        path: /etc/vsftpd/vsftpd.conf
        line: "anon_root=/mnt"  ##修改访问家目录
        regexp: "^anon_root"  ##替换的行
        backrefs: no  ##匹配到时替换,没匹配到时,文件结尾添加一行
      notify:
        - restart vsftpd  ##当文件替换后,触发模块重启服务

  handlers:  ##被触发后的模块,注意此处与tasks对齐
   - name: firewalld
     firewalld:
       service: ftp
       state: enabled
       permanent: yes
       immediate: yes
   - name: restart vsftpd
     service:
       name: vsftpd
       state: restarted

ansible 主机依次执行 ansible执行模式_devops_11

2、执行yaml文件

ansible 主机依次执行 ansible执行模式_运维_12


3、在server4的/mnt/file中添加内容,匿名访问测试

ansible 主机依次执行 ansible执行模式_ansible_13

四、 处理失败任务

1、ignore_errors

作用:当play遇到任务失败时会终止,ignore_errors: yes 将会忽略任务失败使下面的任务继续运行

示例:安装一个不存在的服务

vim ignore.yml

---
- name: ignore_errors
  hosts: server3
  tasks:
    - name: install haha
      yum:
        name: haha
        state: present
      ignore_errors: yes  ##忽略错误
        
    - name: debug
      debug:
        msg: heloo lll

ansible 主机依次执行 ansible执行模式_linux_14

2、force_handlers

作用:当任务失败后play被终止也会调用触发器进程

示例:安装一个不存在的服务,任务失败play终止后仍会有触发
注意去除 ignore_errors: yes 的干扰

vim force.yml

---
- name: force_handlers
  hosts: server3
  force_handlers: yes  ##任务失败后仍触发
  tasks:
    - name: hostname
      shell:
        hostname
      register: info  ##使用注册变量
      notify:
        - debug

    - name: install haha
      yum:
        name: haha
        state: present

  handlers:
    - name: debug
      debug:
        msg: "{{ info['stdout'] }}"  ##展示变量info的输出变量

ansible 主机依次执行 ansible执行模式_devops_15

3、changed_when

作用:控制任务在何时报告它已进行更改,抑制更改

示例:测试changed_when: true

vim changed.yml

---
- name: test
  hosts: server4
  tasks:
    - name: install vsftpd
      yum:
        name: vsftpd
        state: present
      changed_when: true  ##当检测到vsftpd安装后(无论是刚安装还是之前已安装),报告发生改变

server4的vsftpd之前已经安装,应该显示为绿色,但此处显示为黄色

ansible 主机依次执行 ansible执行模式_linux_16


示例:测试changed_when: false

vim changed.yml

---
- name: test
  hosts: server4
  tasks:
    - name: remove vsftpd
      yum:
        name: vsftpd
        state: absent
      changed_when: false  ##当检测到vsftpd被卸载时,报告不改变

此处卸载了vsftpd,应该有改变为黄色,但这里为绿色

ansible 主机依次执行 ansible执行模式_devops_17

4、failed_when

作用:当符合条件时强制任务失败,但不会更改任务本身的行为

示例:建立文件,报错,但实质已经建立

vim failed.yml

---
- name: test
  hosts: server2
  tasks:
    - name: touch file
      file:
        path: /mnt/failedfile
        state: touch
      failed_when: true  ##当文件创建后报错

ansible 主机依次执行 ansible执行模式_运维_18

但实际文件创建成功

ansible 主机依次执行 ansible执行模式_ansible 主机依次执行_19

示例:在不存在的目录下创建文件,却报告成功

vim failed.yml

---
- name: test
  hosts: server2
  tasks:
    - name: touch file
      file:
        path: /mnt/haha/linuxfile
        state: touch
      failed_when: false  ##当文件未创建时不报错

ansible 主机依次执行 ansible执行模式_linux_20

文件自然没有创建

ansible 主机依次执行 ansible执行模式_devops_21

5、block

block:定义要运行的任务
rescue:定义当block句子中出现失败任务后运行的任务
always:定义最终独立运行的任务

示例1:此时/mnt/file存在

vim block.yml

---
- name: test
  hosts: server4
  tasks:
    - name: check file
      block:
        - name: test
          shell: test -e /mnt/file
        - name: debug
          debug:
            msg: /mnt/file is exist
            
      rescue:
        - name: debug
          debug:
            msg: /mnt/file is not exist
            
      always:
        - name:
          debug:
            msg: good night!

所以block句子中没有失败,所以不会执行rescue模块

ansible 主机依次执行 ansible执行模式_ansible_22

示例2:此时/mnt/file不存在

再次执行block.yml,因为block句子中有失败,所以执行rescue模块

ansible 主机依次执行 ansible执行模式_linux_23