Ansible 核心功能进阶:自动化任务的灵活控制与管理

发布于:2025-08-18 ⋅ 阅读:(12) ⋅ 点赞:(0)

一、管理 FACTS:获取远程主机的 “身份信息”

  • FACTS 是 Ansible 自动收集的远程主机详细信息(类似 “主机身份证”),包括主机名、IP、系统版本、硬件配置等。通过 FACTS 可以动态获取主机信息,让 Playbook 更灵活

 1. 查看远程主机的完整域名(FQDN)
 "playbook.yml"
 #vim编辑,查看远程主机(node1)的完整域名(FQDN)
   1 ---                            
   2 - name: Dump facts             
   3   hosts: node1                 
   4                                
   5   tasks:                       
   6     - name: Print all facts    
   7       debug:                   
   8         var: ansible_facts.fqdn   
 ​
 PLAY [Dump facts] ************************************************************************
 ​
 TASK [Gathering Facts] *******************************************************************
 ok: [node1]
 ​
 TASK [Print all facts] *******************************************************************
 ok: [node1] => {
     "ansible_facts.fqdn": "node1.lyk.cloud"
 -作用:在 node1 主机上执行,通过 debug 模块打印主机的完整域名(FQDN)。
 -关键说明:
 ansible_facts.fqdn 是 FACTS 中的变量,存储主机的完整域名(如 node1.lyk.cloud)。
 debug: var=变量名 用于在执行时显示变量的值,方便调试。
 [lyk@controller web 09:51:25]$ ansible-playbook playbook.yml 
 ​
 ​
 ​
 ​
 2. 查看远程主机的 IPv4 网络信息
   1 ---                                    
   2 - name: Dump facts                     
   3   hosts: node1                         
   4                                        
   5   tasks:                               
   6     - name: Print all facts            
   7       debug:                           
   8         var: ansible_facts.default_ipv4  
   
   TASK [Print all facts] *******************************************************************
 ok: [node1] => {
     "ansible_facts.default_ipv4": {
         "address": "10.1.8.11", 
         "alias": "ens33", 
         "broadcast": "10.1.8.255", 
         "gateway": "10.1.8.2", 
         "interface": "ens33", 
         "macaddress": "00:0c:29:1f:2f:2d", 
         "mtu": 1500, 
         "netmask": "255.255.255.0", 
         "network": "10.1.8.0", 
         "type": "ether"
     }
 }
 -作用:打印 node1 的默认 IPv4 网络信息(IP 地址、网关、子网掩码等)。
 关键说明:
 -ansible_facts.default_ipv4 是 FACTS 中存储默认网卡 IPv4 信息的变量,包含 address(IP 地址)、gateway(网关)等子字段。
 ​
 3. 导出所有 FACTS 到文件
 #ansible node1 -m setup > node1.facts:把 node1 的所有信息(不止网络,还有系统、硬件等)导出到文件
 [lyk@controller web 09:52:44]$ ansible node1 -m setup > node1.facts
 #下载到本地电脑,notepad打开,语言选json
 [lyk@controller web 09:54:04]$ sz node1.facts
 ​

二、loop 循环:批量执行重复任务

  • 当需要对多个对象执行相同操作(如安装多个软件、启动多个服务)时,用 loop 循环可以简化 Playbook,避免重复写任务。

1. 批量安装软件包和启动服务

 [lyk@controller web 10:39:17]$ vim deploy_web.yml 
 ​
  15     # 第一个任务
  16     # 任务具有属性:涵name和模块名等。
  17     # name属性,用于简要描述任务
  18     - name: latest version of httpd and firewalld installed
  19      
  20       # 指明模块名,也就是要执行的任务
  21       yum:
  22      
  23         # 执行要操作的rpm包名称
  24         name:
  25           # rpm包名称是-开头的列表格式,或者逗号分隔的列表格式
  26           - httpd
  27           - firewalld
  28      
  29         # 定义软件包的状态,lastet代表升级为最新版本
  30         state: latest
  31      
  32     # 第二个任务
  33     - name: test html page is installed
  34       # copy模块,用于将content属性值写入到目标文件
  35       copy:
  36         content: "Welcome to {{ ansible_fqdn }}\n"
  37         dest: /var/www/html/index.html                                        38      
  39     # 第三个任务
  40     - name: enabled and start httpd/firewalld
  41       # service模块,用于启用并启动httpd服务
  42       service:
  43         name: "{{ item }}"  ##注意对齐
  44         enabled: true
  45         state: started
  46       loop:                 ##注释任务4,和任务3一起执行httpd/firewalld
  47         - httpd
  48         - firewalld
  49      
  50     # 第四个任务和任务三一起执行
  51 #    - name: firewalld enabled and running
  52 #      # service模块,用于启用并启动firewalld服务
  53 #      service:
  54 #        name: firewalld
  55 #        enabled: true
  56 #        state: started       
  57      
  58      
  59     # 第五个任务
  60     - name: firewalld permits access to httpd service
  61       # firewalld,用于放行http服务
  62       firewalld:
  63         service: http
  64         permanent: true
  65         state: enabled
  66         immediate: yes
  67      
  68 # Playbook中第二个play,-开头表示列表
  69 - name: Test intranet web server
  70   hosts: localhost
  71   become: no
  72   tasks:
  73     - name: connect to intranet web server
  74       # uri模块,用于测试网站是否可以访问
  75       uri:
  76         url: http://node1
  77         return_content: yes
  78         status_code: 200
  79      
  80 # yaml格式结束行,一般省略
  81 ...  
                 
  
  
 [lyk@controller web 10:39:17]$ ansible-playbook deploy_web.yml 
 ​

2. 循环字典列表:批量创建用户(带不同属性)

 [lyk@controller web 09:49:57]$ vim playbook.yml
   1 ---                    
   2 - name: add several users
   3   hosts: node1         
   4   gather_facts: no     
   5   tasks:               
   6     - name: add user jane
   7       user:            
   8         name: "{{ item }}"                                                               
   9         groups: "wheel"
  10         state: present 
  11       loop:            
  12         - jane         
  13         - joe        
  
  [lyk@controller web 10:49:01]$ ansible-playbook playbook.yml 
 ​
 PLAY [add several users] **************************************************************************
 ​
 TASK [add user jane] ******************************************************************************
 changed: [node1] => (item=jane)
 changed: [node1] => (item=joe)
 ​
 ​
 ​
 [lyk@controller web 10:16:10]$ vim playbook.yml 
 ​
 ​
   1 ---    
   2 - name: add several users
   3   hosts: node1
   4   gather_facts: no
   5   tasks:
   6 #    - name: add user jane
   7 #      user:
   8 #        name: "{{ item }}"
   9 #        groups: "wheel"
  10 #        state: present
  11 #      loop:
  12 #        - jane
  13 #        - joe
  14     - name: add users
  15       user:
  16         name: "{{ item.name }}"      ##改item->item.name
  17         groups: "{{ item.groups }}"  ##改item->item.groups
  18         state: present
  19       loop: 
  20         - name: jane
  21           groups: wheel
  22         - name: joe
  23           groups: root   
  
  
 ​
3. Do-Until 循环:重试直到成功
 [lyk@controller web 10:16:10]$ vim playbook.yml 
 ​
   1 - name: test loop
   2   hosts: node1
   3   gather_facts: no         
   4   tasks:      
   5     - shell: ping -c1 -w 2 node2
   6       register: result     
   7       until: result.rc == 0
   8       retries: 20
   9       delay: 1 
   
   
 #断开node2 
 [lyk@node2 ~ 09:36:13]$ init 0
 ​
 #尝试连接
 [lyk@controller web 11:21:53]$ ansible-playbook playbook.yml 
 ​
 PLAY [test loop] *******************************************************************
 ​
 TASK [shell] ***********************************************************************
 FAILED - RETRYING: command (20 retries left).
 FAILED - RETRYING: command (19 retries left).
 FAILED - RETRYING: command (18 retries left).
 ......
 ​
 #恢复连接node2,正常进入
 [lyk@controller web 11:23:15]$ ansible-playbook playbook.yml 
 ​
 PLAY [test loop] *******************************************************************
 ​
 TASK [shell] ***********************************************************************
 changed: [node1]
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 ​
 ​
 ​

三、when 条件判断:按需执行任务

  • when 用于根据条件决定任务是否执行(类似 “如果满足条件就做,否则跳过”),让 Playbook 更智能

1. 基本条件判断(布尔值、变量是否定义)

 #vim playbook.yml
   1 ---                    
   2 - name: test           
   3   hosts: node1         
   4   gather_facts: no     
   5   vars:                
   6     run_my_task: true  
   7   tasks:               
   8     - name: test when  
   9       debug:           
  10         msg: "Hello run task"
  11       when: run_my_task 
 [lyk@controller web 11:23:20]$ ansible-playbook playbook.yml 
 ​
 PLAY [test] ************************************************************************
 ​
 TASK [test when] *******************************************************************
 ok: [node1] => {
     "msg": "Hello run task"
 }
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 ​
 ​
 ​
 #vim playbook.yml
   1 ---              
   2 - hosts: node1   
   3   gather_facts: no
   4   vars:          
   5     username: lll     #lll也可以不写,主要有username:就行                                                   
   6   tasks:         
   7     - debug:     
   8         msg: "var: username is defined"
   9       when: username is defined
 ​
 ​
 ​

2. 判断变量 / 文件 / 设备是否存在

 #vim playbook.yml
   1 ---                                       
   2 - hosts: node1                            
   3   gather_facts: yes                       
   4   tasks:                                  
   5     - debug:                              
   6         msg: "sr0 is exist"               
   7       when: ansible_devices.sr0 is defined 
   
   [lyk@controller web 11:47:58]$ ansible-playbook playbook.yml 
 ​
 PLAY [node1] ***********************************************************************
 ​
 TASK [Gathering Facts] *************************************************************
 ok: [node1]
 ​
 TASK [debug] ***********************************************************************
 ok: [node1] => {
     "msg": "sr0 is exist"
 }
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 ​
 ​
 ​
 ​
 #vim playbook.yml
   1 ---                                     
   2 - name: create and use lv               
   3   hosts: node1                          
   4   tasks:                                
   5     - name: Create a logical volume of 4000m       
   6       lvol:                             
   7         vg: research                    
   8         lv: data                        
   9         size: 4000                      
  10       when: ansible_lvm.vgs.research is defined    
  11     - debug:                            
  12         msg: Volume group does not exist  
  
 [lyk@controller web 13:30:04]$ ansible-playbook playbook.yml 
 ​
 PLAY [create and use lv] ***********************************************************
 ​
 TASK [Gathering Facts] *************************************************************
 ok: [node1]
 ​
 TASK [Create a logical volume of 4000m] ********************************************
 skipping: [node1]
 ​
 TASK [debug] ***********************************************************************
 ok: [node1] => {
     "msg": "Volume group does not exist"
 ​
  
  
 #判断文件是否存在
  ---
 - hosts: node1
   gather_facts: no
   vars:
     file_name: /etc/hosts
   tasks:
     - debug:
         msg: "{{ file_name }} is regular file"
       when: file_name is file

3. 1根据主机组安装不同软件

   1 ---                                            
   2 - name: test                                  
   3   hosts: node1                 
   4   gather_facts: no                 
   5   vars:             
   6     username: devops                       
   7     supergroup: wheel                      
   8   tasks:                                   
   9     - name: gather user information        
  10       shell: id {{ username }}             
  11       register: result                     
  12     - name: Task run if user is in supergroups
  13       user:                                
  14         name: "{{ username }}"             
  15         groups: "{{ supergroup }}"         
  16         append: yes                        
  17       when: supergroup not in result.stdout   
  
 [lyk@node1 ~ 13:26:53]$ sudo useradd devops
  
  
  [lyk@controller web 13:49:17]$ ansible-playbook playbook.yml 
 ​
 PLAY [test] ************************************************************************
 ​
 TASK [gather user information] *****************************************************
 changed: [node1]
 ​
 TASK [Task run if user is in supergroups] ******************************************
 changed: [node1]
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 ​
 ​
  

3.2

 #根据不同的主机组在指定节点上安装不同的软件(web 服务器和数据库)
 ​
 #vim "playbook.yml"
  1 ---    
   2 - name: test
   3   hosts: node1 node3
   4   gather_facts: no
   5   tasks:
   6     - name: install httpd
   7       yum:
   8         name: httpd
   9         state: present
  10       when: inventory_hostname in groups.webs
  11     - name: install mariadb                
  12       yum:    
  13         name: mariadb                                                       
  14         state: present
  15       when: inventory_hostname in groups.dbs
 ​
 [lyk@controller web 13:49:20]$ vim inventory 
 ​
   1 controller
   2  
   3 [nodes]
   4 node1
   5 node2
   6 node3
   7 node4
   8  
   9 [webs]
  10 node1
  11 node2
  12                                                                                 
  13 [dbs]
  14 node3
  15 node4
 ​
 ​
 [lyk@controller web 14:00:07]$ ansible-playbook playbook.yml 
 ​
 PLAY [test] ************************************************************************
 ​
 TASK [install httpd] ***************************************************************
 skipping: [node3]
 ok: [node1]
 ​
 TASK [install mariadb] *************************************************************
 skipping: [node1]
 changed: [node3]
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
 node3                      : ok=1    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
 ​

4. loop + when:循环中过滤执行

示例:当 / 文件系统可用空间大于300000000 安装 mariadb-server

解决方法:通过 ansible_facts 获取 / 文件系统可用空间

 #vim "playbook.yml"
 ​
   1 ---                                                                             
   2 - name: Combining Loops and Conditional Play
   3   hosts: node1                         
   4   tasks:                               
   5   - name: install mariadb-server if enough space on root
   6     yum:                               
   7       name: mariadb-server             
   8       state: latest                    
   9     loop: "{{ ansible_mounts }}"       
  10     when:                              
  11       - item.mount == "/"              
  12       - item.size_available > 300000000 
  
  
 [lyk@controller web 14:20:44]$ ansible-playbook playbook.yml 
 ​
 PLAY [Combining Loops and Conditional Play] ****************************************
 ​
 TASK [Gathering Facts] *************************************************************
 ok: [node1]
 ​
 TASK [install mariadb-server if enough space on root] ******************************
 skipping: [node1] => (item={u'block_used': 35554, u'uuid': u'b54b3764-2b2b-4a76-a0ec-83e308071ae5', u'size_total': 1063256064, u'block_total': 259584, u'mount': u'/boot', u'block_available': 224030, u'size_available': 917626880, u'fstype': u'xfs', u'inode_total': 524288, u'options': u'rw,relatime,attr2,inode64,noquota', u'device': u'/dev/sda1', u'inode_used': 326, u'block_size': 4096, u'inode_available': 523962}) 
 ok: [node1] => (item={u'block_used': 523935, u'uuid': u'30af660e-85fc-4fa4-b7a8-72102f439059', u'size_total': 53660876800, u'block_total': 13100800, u'mount': u'/', u'block_available': 12576865, u'size_available': 51514839040, u'fstype': u'xfs', u'inode_total': 26214400, u'options': u'rw,relatime,attr2,inode64,noquota', u'device': u'/dev/mapper/centos-root', u'inode_used': 34064, u'block_size': 4096, u'inode_available': 26180336})
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 ​
  
  

5.register 和 when 联合

示例:当 / 文件系统可用空间大于300000000 安装 mariadb-server

解决方法:通过 shell 获取 / 文件系统可用空间

 #vim "playbook.yml"
   1 ---                                                                         
   2 - name: test 
   3   hosts: node1
   4   gather_facts: no
   5   tasks:    
   6     - name: get / available
   7       shell: df / | awk 'NR==2 {print $4}'
   8       register: fs_size   
   9     - name: install mariadb-server       
  10       yum:  
  11         name: mariadb-server             
  12         state: present    
  13       when: fs_size.stdout | int >= 300000
 ​

一、两个 Playbook 的核心功能

两者的核心逻辑都是:

  1. 检查根目录(/)的可用空间

  2. 当可用空间满足条件(大于某个值)时,安装 mariadb-server

  3. 仅在 node1 主机上执行操作

二、具体区别

对比维度 loop + ansible_facts 方式 register + shell 方式
获取磁盘信息的方式 使用 Ansible 内置的ansible_facts收集磁盘信息 通过shell命令(df + awk)手动获取磁盘信息
是否需要收集 facts 需要(默认启用gather_facts: yes 不需要(显式设置gather_facts: no
循环的使用 使用loop: "{{ ansible_mounts }}"遍历所有挂载点 不使用循环,直接获取根目录信息
条件判断的逻辑 1. 先通过item.mount == "/"筛选根目录挂载点 2. 再判断可用空间是否满足条件 直接对 shell 命令返回的根目录可用空间进行判断
可用空间的单位 ansible_facts返回的是字节(bytes) df命令默认返回的是 KB(千字节)
适用场景 适合需要处理多个挂载点的复杂场景 适合只需要检查单个特定目录的简单场景

四、Ansible Handlers:任务改变后触发操作

示例:安装软件后重启服务
 [lyk@node1 ~ 14:41:45]$ sudo yum remove -y httpd
 ​
 #vim "playbook.yml"
   1 ---                 
   2 - name: deploy web server
   3   hosts: node1      
   4   tasks:            
   5     - name: install packages
   6       yum:          
   7         name: httpd 
   8         state: present
   9       notify:       
  10         - enable and restart apache
  11                     
  12     - name: install httpd-manual
  13       yum:          
  14         name: httpd-manual
  15         state: present
  16       notify:       
  17         - enable and restart apache
  18                     
  19     - debug:        
  20         msg: last task in tasks
  21                     
  22   handlers:         
  23     - name: enable and restart apache
  24       service:      
  25         name: httpd 
  26         state: restarted
  27         enabled: yes        
  
  
 [lyk@controller web 14:40:28]$ ansible-playbook playbook.yml 
 ​
 PLAY [deploy web server] ***********************************************************
 ​
 TASK [Gathering Facts] *************************************************************
 ok: [node1]
 ​
 TASK [install packages] ************************************************************
 changed: [node1]
 ​
 TASK [install httpd-manual] ********************************************************
 changed: [node1]
 ​
 TASK [debug] ***********************************************************************
 ok: [node1] => {
     "msg": "last task in tasks"
 }
 ​
 RUNNING HANDLER [enable and restart apache] ****************************************
 changed: [node1]
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=5    changed=3    unreachable=0    failed=0    skipp
 ​
 #再次执行有区别
 [lyk@controller web 14:42:02]$ ansible-playbook playbook.yml 
 ​
 PLAY [deploy web server] ***********************************************************
 ​
 TASK [Gathering Facts] *************************************************************
 ok: [node1]
 ​
 TASK [install packages] ************************************************************
 ok: [node1]
 ​
 TASK [install httpd-manual] ********************************************************
 ok: [node1]
 ​
 TASK [debug] ***********************************************************************
 ok: [node1] => {
     "msg": "last task in tasks"
 }
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 ​

meta 模块

在多个任务中间加入meta任务,那么在此之前调用的 handler 会立即处理。

示例:

---
- name: deploy db server
  hosts: node1
  tasks:
    - name: install mariadb
      yum:
        name:
          - mariadb-server
          - python3-PyMySQL
        state: present
      notify:
        - enable_and_start_db

    - meta: flush_handlers
    
    - name: add mariadb user
      mysql_user:
        name: lyk
        password: redhat

  handlers:
    - name: enable_and_start_db
      service:
        name: mariadb
        state: started

五、错误处理:控制任务失败后的行为

处理 Errors

 #node1
 [lyk@node1 ~ 15:00:39]$ sudo cp /etc/hosts /etc/myhosts
 #node2
 [lyk@node2 ~ 15:01:26]$ rm -f /etc/myhosts
 ​
 ​
 [lyk@controller web 15:02:35]$ ansible-playbook playbook.yml 
 ​
 PLAY [test] ************************************************************************
 ​
 TASK [Gathering Facts] *************************************************************
 ok: [node2]
 ok: [node1]
 ​
 TASK [show /etc/myhosts] ***********************************************************
 fatal: [node2]: FAILED! => {"changed": true, "cmd": "cat /etc/myhosts", "delta": "0:00:00.002070", "end": "2025-08-14 15:09:39.413406", "msg": "non-zero return code", "rc": 1, "start": "2025-08-14 15:09:39.411336", "stderr": "cat: /etc/myhosts: 没有那个文件或目录", "stderr_lines": ["cat: /etc/myhosts: 没有那个文件或目录"], "stdout": "", "stdout_lines": []}
 changed: [node1]
 ​
 TASK [echo end] ********************************************************************
 ok: [node1] => {
     "msg": "echo end"
 }
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 node2                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
 ​

ignore_errors

   1 ---                         
   2 - name: test                
   3   hosts: node1              
   4   tasks:                    
   5     - name: install a not exist package
   6       yum:                  
   7         name: notexitpackage
   8         state: present      
   9       ignore_errors: yes    
  10       register: result      
  11     - name: debug install result
  12       debug:                
  13         msg: notexitpackage is not exit
  14       when: result is failed   
  
  
  [lyk@controller web 15:09:39]$ ansible-playbook playbook.yml 
 ​
 PLAY [test] ************************************************************************
 ​
 TASK [Gathering Facts] *************************************************************
 ok: [node1]
 ​
 TASK [install a not exist package] *************************************************
 fatal: [node1]: FAILED! => {"changed": false, "msg": "No package matching 'notexitpackage' found available, installed or updated", "rc": 126, "results": ["No package matching 'notexitpackage' found available, installed or updated"]}
 ...ignoring
 ​
 TASK [debug install result] ********************************************************
 ok: [node1] => {
     "msg": "notexitpackage is not exit"
 }
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   
 ​
 ​
  
  

force_handlers

   1 ---                                                                             
   2 - name: test
   3   hosts: node1
   4   force_handlers: yes
   5   tasks:   
   6     - name: a task which always notifies its handler
   7       command: /bin/true
   8       notify: restart the sshd
   9            
  10     - name:  fails because the package doesn't exist
  11       yum: 
  12         name: notexistpkg
  13         state: latest  
  14  
  15   handlers:
  16     - name: restart the sshd
  17       service:      
  18         name: sshd  
  19         state: restarted
 ​
 [lyk@controller web 15:10:41]$ ansible-playbook playbook.yml 
 ​
 PLAY [test] ************************************************************************
 ​
 TASK [Gathering Facts] *************************************************************
 ok: [node1]
 ​
 TASK [a task which always notifies its handler] ************************************
 changed: [node1]
 ​
 TASK [fails because the package doesn't exist] *************************************
 fatal: [node1]: FAILED! => {"changed": false, "msg": "No package matching 'notexistpkg' found available, installed or updated", "rc": 126, "results": ["No package matching 'notexistpkg' found available, installed or updated"]}
 ​
 RUNNING HANDLER [restart the sshd] *************************************************
 changed: [node1]
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=3    changed=2    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
 ​

fail 模块

   1 - name: test fail module                                                        
   2   hosts: node1
   3   gather_facts: no
   4   tasks:
   5     - debug:
   6         msg: task1
   7     - fail:
   8     - debug:
   9         msg: task3
 ​
 [lyk@controller web 15:11:41]$ ansible-playbook playbook.yml 
 ​
 PLAY [test fail module] ************************************************************
 ​
 TASK [debug] ***********************************************************************
 ok: [node1] => {
     "msg": "task1"
 }
 ​
 TASK [fail] ************************************************************************
 fatal: [node1]: FAILED! => {"changed": false, "msg": "Failed as requested from task"}
 ​
 PLAY RECAP *************************************************************************
 node1                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
 ​

failed_when

指明什么条件下,判定任务执行失败

 - name: test failed_when
   hosts: node1
   tasks:
     - shell: /root/adduser
       register: command_result
       failed_when: "'failed' in command_result.stdout"

环境准备:

 [root@node1 ~]# cat /root/adduser 
 #!/bin/bash
 useradd devops &> /dev/null
 if [ $? -eq 0 ];then
   echo add user devops success
 else
   echo add user devops failed
 fi
 [root@node1 ~]# chmod +x /root/adduser 

以上示例:

  • 当devops用户不存在时,shell模块跳过执行。

  • 当devops用户存在时,shell模块执行失败。

以上示例可改写为fail模块和when语句联合使用:

 - name: test fail module
   hosts: node1
   tasks:
     - shell: /root/adduser
       register: command_result
 ​
     - fail:
         msg: "add user devops failed"
       when: "'failed' in command_result.stdout"

changed_when

指明什么条件下,判定任务执行结果为changed。

示例1:

 - name: changed_when
   hosts: node1
   tasks:
     - name: upgrade-database
       shell: /usr/local/bin/upgrade-database
       register: result
       changed_when: "'Success' in result.stdout"
       notify:
         - restart_database
   handlers:
     - name: restart_database
       service:
         name: mariadb
         state: restarted

环境准备:

 [root@node1 ~]# yum install -y mariadb-server
 [root@node1 ~]# systemctl enable mariadb --now
 [root@node1 ~]# vim /usr/local/bin/upgrade-database
 #!/bin/bash
 mysql -e 'create user lyk@"%" identified by "123";' && mysql -e 'GRANT ALL PRIVILEGES on *.* TO 123@"%";' && echo update database Success
 [root@node1 ~]# chmod +x /usr/local/bin/upgrade-database

对于command模块和shell模块,只要命令正常执行,结果状态通常都是changed。可以通过返回码和输出结果来判定它们是否做出更改。

关键字 changed_when: false ,让任务结果状态不为changed,只能报告为ok或failed。

示例2:

 ---
 - name: Test When
   hosts: node1
   gather_facts: no
   tasks:
   - name: test changed_when
     shell: cat /etc/redhat-release
     changed_when: false

Ansible block

示例2:在所有受管节点上创建符合以下要求的逻辑卷:

  • 在research卷组中创建逻辑卷:

    • 逻辑卷名称为data

    • 逻辑卷大小为4000MiB

    • 使用ext4文件系统格式化逻辑卷

    • 将逻辑卷挂载到/data目录

    • 如果无法创建请求的逻辑卷大小,应显示错误信息:Could not create logical volume of that size 并且应改为使用大小800MiB。

  • 如果卷组research不存在,应显示错误信息:Volume does not exist

环境准备

 node1添加20G
 node2添加20G
 ​
 ​
 [root@node1 ~ 15:36:17]# vgcreate research /dev/sdb
   Physical volume "/dev/sdb" successfully created.
   Volume group "research" successfully created
 ​
 ​
 [root@node2 ~ 15:37:09]# parted /dev/sdb unit MiB mklabel msdos
 信息: You may need to update /etc/fstab.
 ​
 [root@node2 ~ 15:37:26]# parted /dev/sdb unit MiB mkpart primary 1 1025   
 信息: You may need to update /etc/fstab.
 ​
 [root@node2 ~ 15:37:34]# vgcreate research /dev/sdb1                      
   Physical volume "/dev/sdb1" successfully created.
   Volume group "research" successfully created

vim编辑

 [lyk@controller web 16:02:28]$ ansible-doc -l |grep -i lvm
 aix_filesystem                                                Configure LVM and...
 aix_lvg                                                       Manage LVM volume...
 lvol                                                          Configure LVM log...
 aix_lvol                                                      Configure AIX LVM...
 lvg                                                           Configure LVM vol...
 ​
 [lyk@controller web 16:03:12]$ ansible-doc lvol
 #进入文件复制
 EXAMPLES:
 ​
 - name: Create a logical volume of 512m
   lvol:
     vg: firefly
     lv: test
     size: 512
 ​
 ​
 ​
   1 ---                       
   2 - name: create logical volume
   3   hosts: all              
   4   tasks:                  
   5     - name: create lv     
   6       block:              
   7         - name: Create a logical volume of 4000m
   8           lvol:           
   9             vg: research  
  10             lv: data      
  11             size: 4000    
  12       rescue:             
  13         - name: Could not create logical volume of that size
  14           debug:          
  15             msg: Could not create logical volume of that size
  16         - name: Create a logical volume of 800m
  17           lvol:           
  18             vg: research  
  19             lv: data      
  20             size: 800     
  21       always:             
  22         - name: Create a ext4 filesystem
  23           filesystem:     
  24             fstype: ext4  
  25             dev: /dev/research/data
  26         - name: Create a directory
  27           file:           
  28             path: /data   
  29             state: directory
  30         - name: Mount up device
  31           mount:          
  32             path: /data   
  33             src: /dev/research/data
  34             fstype: ext4  
  35             state: mounted                                                   
  36       when: ansible_lvm.vgs.research is defined
  37     - name: Volume does not exist
  38       debug:              
  39         msg: Volume does not exist
  40       when: ansible_lvm.vgs.research is defined
 ​
 ​
 ​
 [lyk@controller web 16:37:04]$ ansible-playbook playbook.yml 
 ​
 PLAY [create logical volume] *******************************************************
 ​
 TASK [Gathering Facts] *************************************************************
 ok: [node3]
 ok: [node1]
 ok: [node2]
 ok: [node4]
 ok: [controller]
 ​
 TASK [Create a logical volume of 4000m] ********************************************
 skipping: [controller]
 skipping: [node3]
 skipping: [node4]
 [WARNING]: The value 4000 (type int) in a string field was converted to u'4000'
 (type string). If this does not look like what you expect, quote the entire value
 to ensure it does not change.
 fatal: [node2]: FAILED! => {"changed": false, "err": "  Volume group \"research\" has insufficient free space (255 extents): 1000 required.\n", "msg": "Creating logical volume 'data' failed", "rc": 5}
 changed: [node1]
 ​
 TASK [Could not create logical volume of that size] ********************************
 ok: [node2] => {
     "msg": "Could not create logical volume of that size"
 }
 ​
 TASK [Create a logical volume of 800m] *********************************************
 [WARNING]: The value 800 (type int) in a string field was converted to u'800' (type
 string). If this does not look like what you expect, quote the entire value to
 ensure it does not change.
 changed: [node2]
 ​
 TASK [Create a ext4 filesystem] ****************************************************
 skipping: [controller]
 skipping: [node3]
 skipping: [node4]
 changed: [node2]
 changed: [node1]
 ​
 TASK [Create a directory] **********************************************************
 skipping: [controller]
 skipping: [node3]
 skipping: [node4]
 changed: [node2]
 changed: [node1]
 ​
 TASK [Mount up device] *************************************************************
 skipping: [controller]
 skipping: [node3]
 skipping: [node4]
 changed: [node1]
 changed: [node2]
 ​
 TASK [Volume does not exist] *******************************************************
 skipping: [controller]
 ok: [node2] => {
     "msg": "Volume does not exist"
 }
 ok: [node1] => {
     "msg": "Volume does not exist"
 }
 skipping: [node3]
 skipping: [node4]
 ​
 PLAY RECAP *************************************************************************
 controller                 : ok=1    changed=0    unreachable=0    failed=0    skipped=5    rescued=0    ignored=0   
 node1                      : ok=6    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 node2                      : ok=7    changed=4    unreachable=0    failed=0    skipped=0    rescued=1    ignored=0   
 node3                      : ok=1    changed=0    unreachable=0    failed=0    skipped=5    rescued=0    ignored=0   
 node4                      : ok=1    changed=0    unreachable=0    failed=0    skipped=5    rescued=0    ignored=0   
 ​

网站公告

今日签到

点亮在社区的每一天
去签到