Ansible 核心功能进阶:自动化任务的灵活控制与管理
一、管理 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 installed19 20 # 指明模块名,也就是要执行的任务21 yum:22 23 # 执行要操作的rpm包名称24 name:25 # rpm包名称是-开头的列表格式,或者逗号分隔的列表格式26 - httpd27 - firewalld28 29 # 定义软件包的状态,lastet代表升级为最新版本30 state: latest31 32 # 第二个任务33 - name: test html page is installed34 # 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/firewalld41 # service模块,用于启用并启动httpd服务42 service:43 name: "{{ item }}" ##注意对齐44 enabled: true45 state: started46 loop: ##注释任务4,和任务3一起执行httpd/firewalld47 - httpd48 - firewalld49 50 # 第四个任务和任务三一起执行51 # - name: firewalld enabled and running52 # # service模块,用于启用并启动firewalld服务53 # service:54 # name: firewalld55 # enabled: true56 # state: started 57 58 59 # 第五个任务60 - name: firewalld permits access to httpd service61 # firewalld,用于放行http服务62 firewalld:63 service: http64 permanent: true65 state: enabled66 immediate: yes67 68 # Playbook中第二个play,-开头表示列表69 - name: Test intranet web server70 hosts: localhost71 become: no72 tasks:73 - name: connect to intranet web server74 # uri模块,用于测试网站是否可以访问75 uri:76 url: http://node177 return_content: yes78 status_code: 20079 80 # yaml格式结束行,一般省略81 ... [lyk@controller web 10:39:17]$ ansible-playbook deploy_web.yml
2. 循环字典列表:批量创建用户(带不同属性)
[lyk@controller web 09:49:57]$ vim playbook.yml1 --- 2 - name: add several users3 hosts: node1 4 gather_facts: no 5 tasks: 6 - name: add user jane7 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 users3 hosts: node14 gather_facts: no5 tasks:6 # - name: add user jane7 # user:8 # name: "{{ item }}"9 # groups: "wheel"10 # state: present11 # loop:12 # - jane13 # - joe14 - name: add users15 user:16 name: "{{ item.name }}" ##改item->item.name17 groups: "{{ item.groups }}" ##改item->item.groups18 state: present19 loop: 20 - name: jane21 groups: wheel22 - name: joe23 groups: root
3. Do-Until 循环:重试直到成功
[lyk@controller web 10:16:10]$ vim playbook.yml 1 - name: test loop2 hosts: node13 gather_facts: no 4 tasks: 5 - shell: ping -c1 -w 2 node26 register: result 7 until: result.rc == 08 retries: 209 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.yml1 --- 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.yml1 --- 2 - hosts: node1 3 gather_facts: no4 vars: 5 username: lll #lll也可以不写,主要有username:就行 6 tasks: 7 - debug: 8 msg: "var: username is defined"9 when: username is defined
2. 判断变量 / 文件 / 设备是否存在
#vim playbook.yml1 --- 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.yml1 --- 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: node1gather_facts: novars:file_name: /etc/hoststasks:- 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 supergroups13 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: test3 hosts: node1 node34 gather_facts: no5 tasks:6 - name: install httpd7 yum:8 name: httpd9 state: present10 when: inventory_hostname in groups.webs11 - name: install mariadb 12 yum: 13 name: mariadb 14 state: present15 when: inventory_hostname in groups.dbs[lyk@controller web 13:49:20]$ vim inventory 1 controller2 3 [nodes]4 node15 node26 node37 node48 9 [webs]10 node111 node212 13 [dbs]14 node315 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 Play3 hosts: node1 4 tasks: 5 - name: install mariadb-server if enough space on root6 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: node14 gather_facts: no5 tasks: 6 - name: get / available7 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 的核心功能
两者的核心逻辑都是:
检查根目录(/)的可用空间
当可用空间满足条件(大于某个值)时,安装 mariadb-server
仅在 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 server3 hosts: node1 4 tasks: 5 - name: install packages6 yum: 7 name: httpd 8 state: present9 notify: 10 - enable and restart apache11 12 - name: install httpd-manual13 yum: 14 name: httpd-manual15 state: present16 notify: 17 - enable and restart apache18 19 - debug: 20 msg: last task in tasks21 22 handlers: 23 - name: enable and restart apache24 service: 25 name: httpd 26 state: restarted27 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 serverhosts: node1tasks:- name: install mariadbyum:name:- mariadb-server- python3-PyMySQLstate: presentnotify:- enable_and_start_db- meta: flush_handlers- name: add mariadb usermysql_user:name: lykpassword: redhathandlers:- name: enable_and_start_dbservice:name: mariadbstate: 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 package6 yum: 7 name: notexitpackage8 state: present 9 ignore_errors: yes 10 register: result 11 - name: debug install result12 debug: 13 msg: notexitpackage is not exit14 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"]}...ignoringTASK [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: test3 hosts: node14 force_handlers: yes5 tasks: 6 - name: a task which always notifies its handler7 command: /bin/true8 notify: restart the sshd9 10 - name: fails because the package doesn't exist11 yum: 12 name: notexistpkg13 state: latest 14 15 handlers:16 - name: restart the sshd17 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: node13 gather_facts: no4 tasks:5 - debug:6 msg: task17 - 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_whenhosts: node1tasks:- shell: /root/adduserregister: command_resultfailed_when: "'failed' in command_result.stdout"
环境准备:
[root@node1 ~]# cat /root/adduser #!/bin/bashuseradd devops &> /dev/nullif [ $? -eq 0 ];thenecho add user devops successelseecho add user devops failedfi[root@node1 ~]# chmod +x /root/adduser
以上示例:
当devops用户不存在时,shell模块跳过执行。
当devops用户存在时,shell模块执行失败。
以上示例可改写为fail模块和when语句联合使用:
- name: test fail modulehosts: node1tasks:- shell: /root/adduserregister: command_result- fail:msg: "add user devops failed"when: "'failed' in command_result.stdout"
changed_when
指明什么条件下,判定任务执行结果为changed。
示例1:
- name: changed_whenhosts: node1tasks:- name: upgrade-databaseshell: /usr/local/bin/upgrade-databaseregister: resultchanged_when: "'Success' in result.stdout"notify:- restart_databasehandlers:- name: restart_databaseservice:name: mariadbstate: restarted
环境准备:
[root@node1 ~]# yum install -y mariadb-server[root@node1 ~]# systemctl enable mariadb --now[root@node1 ~]# vim /usr/local/bin/upgrade-database#!/bin/bashmysql -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 Whenhosts: node1gather_facts: notasks:- name: test changed_whenshell: cat /etc/redhat-releasechanged_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添加20Gnode2添加20G[root@node1 ~ 15:36:17]# vgcreate research /dev/sdbPhysical 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 lvmaix_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 512mlvol:vg: fireflylv: testsize: 5121 --- 2 - name: create logical volume3 hosts: all 4 tasks: 5 - name: create lv 6 block: 7 - name: Create a logical volume of 4000m8 lvol: 9 vg: research 10 lv: data 11 size: 4000 12 rescue: 13 - name: Could not create logical volume of that size14 debug: 15 msg: Could not create logical volume of that size16 - name: Create a logical volume of 800m17 lvol: 18 vg: research 19 lv: data 20 size: 800 21 always: 22 - name: Create a ext4 filesystem23 filesystem: 24 fstype: ext4 25 dev: /dev/research/data26 - name: Create a directory27 file: 28 path: /data 29 state: directory30 - name: Mount up device31 mount: 32 path: /data 33 src: /dev/research/data34 fstype: ext4 35 state: mounted 36 when: ansible_lvm.vgs.research is defined37 - name: Volume does not exist38 debug: 39 msg: Volume does not exist40 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 valueto 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' (typestring). If this does not look like what you expect, quote the entire value toensure 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