实施任务控制及在被管理节点上创建文件或目录
1 实施任务控制
1.1 有条件地运行任务
Ansible可使用conditionals在符合特定条件时执行任务或play。例如,可以利用一个条件在Ansible安装或配置服务前确定受管主机上的可用内存。我们可以利用条件来区分不同的受管主机,并根据它们所符合的条件来分配功能角色。Playbook变量、注册的变量和Ansible事实都可通过条件来进行测试。可以使用比较字符串、数字数据和布尔值的运算符。
以下场景说明了在Ansible中使用条件的情况:
- 可以在变量中定义硬限制(如min_memory)并将它与受管主机上的可用内存进行比较。
- Ansible可以捕获并评估命令的输出,以确定某一任务在执行进一步操作前是否已经完成。例如,如果某一程序失败,则将路过批处理。
- 可以利用Ansible事实来确定受管主机网络配置,并决定要发送的模板文件(如,网络绑定或中继)。
- 可以评估CPU的数量,来确定如何正确调节某一Web服务器。
- 将注册的变量与预定义的变量进行比较,以确定服务是否已更改。例如,测试服务配置文件的MD5检验以和查看服务是否已更改。
1.1.1 条件任务语法
when语句用于有条件地运行任务,它取要测试的条件为值,如果条件满足,则运行任务,如果条件不满足,则跳过任务
可以测试一个最简单的条件,某一布尔变量是True还是False
例
[root@ansible playbook]# vim cs.yml
[root@ansible playbook]# cat cs.yml
---
- name: test
hosts: apache
gather_facts: no
vars:
power: true #若为false则会跳过
tasks:
- name: 安装vsftpd
yum:
name: vsftpd
state: present
when: power
[root@ansible playbook]# ansible-playbook cs.yml
PLAY [apache] ******************************************************************
TASK [test] *********************************************************************
ok: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
如果变量有值,则变量的值用于模块的条件进行操作,如果没有定义变量的值则跳过任务且不显示任务
例
[root@ansible playbook]# vim cs.yml
[root@ansible playbook]# cat cs.yml
---
- hosts: apache
gather_facts: no
tasks:
- name:
yum:
name: "{{ service_name }}"
state: present
when: service_name is defined
[root@ansible playbook]# ansible-playbook cs.yml
PLAY [apache] ******************************************************************
TASK [yum] *********************************************************************
skipping: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
在处理条件时可使用的一些运算
操作 | 示例 |
---|---|
等于 | ansible_machine == “x86_64” |
等于 | max_memory == 512 |
小于 | min_memory < 128 |
大于 | min_memory > 256 |
小于等于 | min_memory <= 256 |
大于等于 | min_memory >= 512 |
不等于 | min_memory != 512 |
变量存在 | min_memory is defined |
变量不存在 | min_memory is not defined |
布尔变量是True。1、True或yes的求值为True | memory_available |
布尔变量是False。0、False或no的求值为False | not memory_available |
第一个变量的值存在,作为第二个变量的列表中的值 | ansible_distribution in supported_distros |
ansible_distribution变量是在Gathering Facts任务期间确定的事实,用于标识托管主机的操作系统分支。变量supported_distros由playbook创建,包含该playbook支持的操作系统分发列表。如果ansible_distribution的值在supported_distros列表中,则条件通过且任务运行。
例
[root@ansible playbook]# vim jj.yml
[root@ansible playbook]# cat jj.yml
---
- hosts: apache
vars:
platform:
- RedHat
- CentOS
tasks:
- name:
yum:
name: vsftpd
state: present
when: ansible_facts ['distribution'] in platform
[root@ansible playbook]# ansible-playbook jj.yml
PLAY [apache] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.136.225]
TASK [yum] *********************************************************************
changed: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
1.1.2 测试多个条件
一个when语句可用于评估多个条件。使用and和or关键字组合条件,并使用括号分组条件。
如果任一条件为真时满足条件语句,则应当使用or语句。
when: ansible_distribution == "Redhat" or ansible_distribution == "Fedora"
使用and运算时,两个条件都必须为真,才能满足整个条件语句。
when: ansible_distribution_version == "7.5" and ansible_kernel == "3.10.0-327.el7.x86_64"
when关键字还支持使用列表来描述条件列表。向when关键字提供列表时,将使用and运算组合所有条件。下面的示例演示了使用and运算符组合多个条件语句的另一方式:
when:
- ansible_distribution_version == "7.5"
- ansible_kernel == "3.10.0-327.el7.x86_64"
这种格式提高了可读性,而可读性是良好编写Ansible Playbook的关键目标。
通过使用括号分组条件,可以表达更复杂的条件语句。使用大于字符,这样长条件就可以在playbook中分成多行,以便于阅读。
when: >
( ansible_distribution == "Redhat" and
ansible_distribution_major_version == "7" )
or
( ansible_distribution == "Fedora" and
ansible_distribution_major_version == "28" )
1.2 组合循环和有条件任务
循环和条件可以组合使用
例:
[root@ansible playbook]# vim mount.yml
[root@ansible playbook]# cat mount.yml
---
- hosts: apache
tasks:
- name: anz
yum:
name: vsftpd
state: present
loop: "{{ ansible_mounts }}"
when: item.mount == "/" and item.size_available > 26081135
[root@ansible playbook]# ansible-playbook mount.yml
PLAY [apache] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.136.225]
TASK [anz] *********************************************************************
changed: [192.168.136.225] => (item={u'block_used': 1273104, u'uuid': u'403a4120-e665-469e-a5c7-6ed301fbb5c4', u'size_total': 53660876800, u'block_total': 13100800, u'mount': u'/', u'block_available': 11827696, u'size_available': 48446242816, u'fstype': u'xfs', u'inode_total': 26214400, u'options': u'rw,seclabel,relatime,attr2,inode64,noquota', u'device': u'/dev/mapper/rhel-root', u'inode_used': 133265, u'block_size': 4096, u'inode_available': 26081135})
skipping: [192.168.136.225] => (item={u'block_used': 90627, u'uuid': u'd6f4071b-525d-4523-8352-9522cc512e67', u'size_total': 48345096192, u'block_total': 11803002, u'mount': u'/home', u'block_available': 11712375, u'size_available': 47973888000, u'fstype': u'xfs', u'inode_total': 23617536, u'options': u'rw,seclabel,relatime,attr2,inode64,noquota', u'device': u'/dev/mapper/rhel-home', u'inode_used': 109, u'block_size': 4096, u'inode_available': 23617427})
skipping: [192.168.136.225] => (item={u'block_used': 58595, u'uuid': u'b0612149-cc35-411c-85d4-123c8a2405c9', u'size_total': 1063256064, u'block_total': 259584, u'mount': u'/boot', u'block_available': 200989, u'size_available': 823250944, u'fstype': u'xfs', u'inode_total': 524288, u'options': u'rw,seclabel,relatime,attr2,inode64,noquota', u'device': u'/dev/nvme0n1p1', u'inode_used': 301, u'block_size': 4096, u'inode_available': 523987})
skipping: [192.168.136.225] => (item={u'block_used': 4119280, u'uuid': u'2020-04-04-08-21-15-00', u'size_total': 8436285440, u'block_total': 4119280, u'mount': u'/mnt/cd', u'block_available': 0, u'size_available': 0, u'fstype': u'iso9660', u'inode_total': 0, u'options': u'ro,relatime,nojoliet,check=s,map=n,blocksize=2048', u'device': u'/dev/sr0', u'inode_used': 0, u'block_size': 2048, u'inode_available': 0})
PLAY RECAP *********************************************************************
192.168.136.225 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
对某个任务结合使用when和loop时,将对每个项检查when语句。
在文本中输入ignore_errors: yes 可以跳过错误程序继续运行程序
2 实施处理程序
2.1 ansible处理程序
Ansible模块设计为具有幂等性。这表示,在正确编写的playbook中,playbook及其任务可以运行多次而不会改变受管主机,除非需要进行更改使受管主机进入所需的状态。但在时候,在任务确实更改系统时,可能需要运行进一步的任务。例如,更改服务配置文件时可能要求重新加载该服务以便使其更改的配置生效。处理程序是响应由其他任务触发的通知的任务。仅当任务在受管主机上更改了某些内容时,任务才通知其处理程序。每个处理程序具有全局唯一的名称,在playbook中任务块的末尾触发。如果没有任务通过名称通知处理程序,处理程序就不会运行。如果一个或多个任务通知处理程序,处理程序就会在play中的所有其他任务完成后运行一次。因为处理程序就是任务,所以可以在处理程序中使用他们将用于任何其他任务的模块。通常而言,处理程序被用于重新引导主机和重启服务。处理程序可视为非活动任务,只有在使用notify语句显式调用时才会被触发
例
[root@ansible playbook]# vim tesk.yml
[root@ansible playbook]# cat tesk.yml
---
- hosts: apache
force_handlers: yes
tasks:
- name:
yum:
name: vsftpd
state: present
- name:
copy:
src: fest/vsftpd.conf
dest: /etc/vsftpd/vsftpd.conf
notify:
- restart vsftpd
- name: service
service:
name: vsftpd
state: started
handlers:
- name:
service:
name: vsftpd
service: restarted
[root@ansible playbook]# ansible-playbook tesk.yml
PLAY [apache] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.136.225]
TASK [yum] *********************************************************************
ok: [192.168.136.225]
TASK [copy] ********************************************************************
ok: [192.168.136.225]
TASK [service] *****************************************************************
changed: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.2 使用处理程序的好处
使用处理程序时需要牢记几个重要事项:
- 处理程序始终按照play的handlers部分指定的顺序运行。它们不按在任务中由notify语句列出的顺序运行,或按任务通知它们的顺序运行。
- 处理程序通常在相关play中的所有其他任务完成后运行。playbook的tasks部分中某一任务调用的处理程序,将等到tasks下的所有任务都已处理后才会运行。
- 处理程序名称存在于各play命名空间中。如果两个处理程序被错误地给予相同的名称,则仅会运行一个。
- 即使有多个任务通知处理程序,该处理程序依然仅运行一次。如果没有任务通知处理程序,它就不会运行。
- 如果包含notify语句的任务没有报告changed结果(例如,软件包已安装并且任务报告ok),则处理程序不会获得通知。处理程序将被跳过,直到有其他任务通知它。只有相关任务报告了changed状态,Ansible才会通知处理程序。
处理程序用于在任务对受管主机进行更改时执行额外操作。它们不应用作正常任务的替代
3 处理任务失败
3.1 管理play中的任务错误
Ansible评估任务的返回代码,从而确定任务是成功还是失败。通常而言,当任务失败时,Ansible将立即在该主机上中止play的其余部分并且跳过所有后续任务。但有些时候,可能希望即使在任务失败时也继续执行play。例如,或许预期待定任务有可能会失败,并且希望通过有条件地运行某项其他任务来修复。
Ansible有多种功能可用于管理任务错误
3.2 忽略任务失败
默认情况下,任务失败时play会中止。不过,可以通过忽略失败的任务来覆盖此行为。可以在任务中使用ignore_errors关键字来实现此目的。
例:
[root@ansible playbook]# vim tesk.yml
[root@ansible playbook]# cat tesk.yml
---
- hosts: apache
tasks:
- name:
yum:
name: vsftpdds #错误的名称
state: present
ignore_errors: yes #跳过错误
- name:
copy:
src: fest/vsftpd.conf
dest: /etc/vsftpd/vsftpd.conf
notify:
- restart vsftpd
- name: service
service:
name: vsftpd
state: started
handlers:
- name:
service:
name: vsftpd
service: restarted
[root@ansible playbook]# ansible-playbook tesk.yml
PLAY [apache] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.136.225]
TASK [yum] *********************************************************************
fatal: [192.168.136.225]: FAILED! => {"changed": false, "failures": ["No package vsftpdds available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
...ignoring
TASK [copy] ********************************************************************
ok: [192.168.136.225]
TASK [service] *****************************************************************
ok: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
[root@ansible playbook]#
3.3 任务失败后强制执行处理程序
通常而言,如果任务失败并且play在该主机上中止,则收到play中早前任务通知的处理程序将不会运行。如果在play中设置force_handlers: yes关键字,则即使play因为后续任务失败而中止也会调用被通知的处理程序,处理程序会在任务报告changed结果时获得通知,而在任务报告ok或failed结果时不会获得通知。
例:
[root@ansible playbook]# cat tesk.yml
---
- hosts: apache
force_handlers: yes
tasks:
- name:
yum:
name: httpd
state: present
- name:
copy:
src: fest/vsftpd.conf
dest: /etc/vsftpd/vsftpd.conf
notify:
- restart vsftpd
- name: service
service:
name: vsftpd
state: started
handlers:
- name:
service:
name: vsftpd
service: restarted
[root@ansible playbook]# ansible-playbook tesk.yml
PLAY [apache] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.136.225]
TASK [yum] *********************************************************************
ok: [192.168.136.225]
TASK [copy] ********************************************************************
ok: [192.168.136.225]
TASK [service] *****************************************************************
ok: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3.4 指定任务失败条件
可以在任务中使用failed_when关键字来指定表示任务已失败的条件。这通常与命令模块搭配使用,这些模块可能成功执行了某一命令,但命令的输出可能指示了失败。fail模块用于强制任务失败
例
[root@ansible playbook]# vim user.yml
[root@ansible playbook]# cat user.yml
---
- hosts: apache
gather_facts: no
tasks:
- name: user
command: echo "wqts woller"
register: result
- name: wq
fail:
msg: "执行失败"
when: "'woller' in result['stdout']"
[root@ansible playbook]# ansible-playbook user.yml
PLAY [apache] ******************************************************************
TASK [user] ********************************************************************
changed: [192.168.136.225]
TASK [wq] **********************************************************************
fatal: [192.168.136.225]: FAILED! => {"changed": false, "msg": "执行失败"}
PLAY RECAP *********************************************************************
192.168.136.225 : ok=1 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
使用fail模块为任务提供明确的失败消息。此方法还支持延迟失败,允许在运行中间任务以完成或回滚其他更改
3.5 指定何时任务报告“Changed”结果
当任务对托管主机进行了更改时,会报告 changed 状态并通知处理程序。如果任务不需要进行更改,则会报告ok并且不通知处理程序。changed_when关键字可用于控制任务在何时报告它已进行了更改
例:
[root@ansible playbook]# vim ll.yml
[root@ansible playbook]# cat ll.yml
---
- hosts: apache
gather_facts: no
tasks:
- name: www
copy:
src: fest/vsftpd.conf
dest: /etc/vsftpd/vsftpd.conf
changed_when: true
[root@ansible playbook]# ansible-playbook ll.yml
PLAY [apache] ******************************************************************
TASK [www] *********************************************************************
changed: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible playbook]# vim fest/vsftpd.conf 更改文件内容
[root@ansible playbook]# vim ll.yml
[root@ansible playbook]# cat ll.yml
---
- hosts: apache
gather_facts: no
tasks:
- name: www
copy:
src: fest/vsftpd.conf
dest: /etc/vsftpd/vsftpd.conf
changed_when: false
[root@ansible playbook]# ansible-playbook ll.yml
PLAY [apache] ******************************************************************
TASK [www] *********************************************************************
ok: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3.6 Ansible块和错误处理
在playbook中,块是对任务进行逻辑分组的子句,可用于控制任务的执行方式。例如,任务块可以含有when关键字,以将某一条件应用到多个任务:
- name: block example
hosts: 172.16.103.129
tasks:
- name: installing and configuring Yum versionlock plugin
block:
- name: package needed by yum
yum:
name: yum-plugin-versionlock
state: present
- name: lock version of tadata
lineinfile:
dest: /etc/yum/pluginconf.d/versionlock.list
line: tzdata-2020j-1
state: present
when: ansible_distribution == "Redhat"
通过块,也可结合rescue和always语句来处理错误。如果块中的任何任务失败,则执行其rescue块中的任务来进行恢复。在block子句中的任务以及rescue子句中的任务(如果出现故障)运行之后,always子句中的任务运行。总结:
- block:定义要运行的主要任务
- rescue:定义要在block子句中定义的任务失败时运行的任务
- always:定义始终都独立运行的任务,不论block和rescue子句中定义的任务是成功还是失败
以下示例演示了如何在playbook中实施块。即使block子句中定义的任务失败,rescue和always子句中定义的任务也会执行。
tasks:
- name: Upgrade DB
block:
- name: upgrade the database
shell:
cmd: /usr/local/lib/upgrade-database
rescue:
- name: revert the database upgrade
shell:
cmd: /usr/local/lib/revert-database
always:
- name: always restart the database
service:
name: mariadb
state: restarted
block中的when条件也会应用到其rescue和always子句(若存在)。
4 在被管理节点创建文件或目录
4.1 修改文件并将其复制到主机
4.1.1描述文件模块
Files模块库包含的模块允许用户完成与Linux文件管理相关的大多数任务,如创建、复制、编辑和修改文件的权限和其他属性
常用文件模块
模块名称 | 模块说明 |
---|---|
blockinfile | 插入、更新或删除由可自定义标记线包围的多行文本块 |
copy | 将文件从本地或远程计算机复制到受管主机上的某个位置。 类似于file模块,copy模块还可以设置文件属性,包括SELinux上下文件。 |
fetch | 此模块的作用和copy模块类似,但以相反方式工作。此模块用于从远程计算机获取文件到控制节点, 并将它们存储在按主机名组织的文件树中。 |
file | 设置权限、所有权、SELinux上下文以及常规文件、符号链接、硬链接和目录的时间戳等属性。 此模块还可以创建或删除常规文件、符号链接、硬链接和目录。其他多个与文件相关的 模块支持与file模块相同的属性设置选项,包括copy模块。 |
lineinfile | 确保特定行位于某文件中,或使用反向引用正则表达式来替换现有行。 此模块主要在用户想要更改文件的某一行时使用。 |
stat | 检索文件的状态信息,类似于Linux中的stat命令。 |
synchronize | 围绕rsync命令的一个打包程序,可加快和简化常见任务。 synchronize模块无法提供对rsync命令的完整功能的访问权限,但确实最常见的调用更容易实施。 用户可能仍需通过run command模块直接调用rsync命令。 |
例
blockinfile模块
[root@ansible playbook]# vim f.yml
[root@ansible playbook]# cat f.yml
---
- hosts: apache
gather_facts: no
tasks:
- name: l
blockinfile:
path: /tmp/j
block: |
wwwkk
wwwfjjj
iefjwfjijiw
jwifnvbjnsx
[root@ansible playbook]# ansible-playbook f.yml
PLAY [apache] ******************************************************************
TASK [l] ***********************************************************************
changed: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible playbook]# vim f.yml
[root@ansible playbook]# ansible-playbook f.yml
PLAY [apache] ******************************************************************
TASK [l] ***********************************************************************
changed: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost tmp]# cat j
# BEGIN ANSIBLE MANAGED BLOCK
wwwkk
wwwfjjj
iefjwfjijiw
jwifnvbjnsx
# END ANSIBLE MANAGED BLOCK
[root@ansible playbook]# vim f.yml
[root@ansible playbook]# cat f.yml
---
- hosts: apache
gather_facts: no
tasks:
- name: l
blockinfile:
path: /tmp/j
block: |
wwwkk
wwwfjjj
iefjwfjijiw
jwifnvbjnsx
uijusio
ijijijiij
[root@ansible playbook]# ansible-playbook f.yml
PLAY [apache] ******************************************************************
TASK [l] ***********************************************************************
changed: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost tmp]# cat j
# BEGIN ANSIBLE MANAGED BLOCK
wwwkk
wwwfjjj
iefjwfjijiw
jwifnvbjnsx
uijusio
ijijijiij
# END ANSIBLE MANAGED BLOCK
fetch模块
[root@ansible playbook]# vim fetch.yml
[root@ansible playbook]# cat fetch.yml
[root@ansible playbook]# ansible-playbook fetch.yml
PLAY [apache] ******************************************************************
TASK [fetch] *******************************************************************
changed: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible playbook]# ls /opt/
192.168.136.225 lamp
[root@ansible playbook]# tree /opt/
/opt/
├── 192.168.136.225
│ └── tmp
│ └── j
└── lamp
└── lamp.yml
3 directories, 2 files
stat模块
[root@ansible playbook]# vim yime.yml
[root@ansible playbook]# cat yime.yml
---
- hosts: all
gather_facts: no
tasks:
- name:
stat:
path: /root/anaconda-ks.cfg
register: result
- debug:
var: result
[root@ansible playbook]# ansible-playbook yime.yml
PLAY [all] *********************************************************************
TASK [stat] ********************************************************************
ok: [192.168.136.225]
TASK [debug] *******************************************************************
ok: [192.168.136.225] => {
"result": {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"failed": false,
"stat": {
"atime": 1626846826.8892639,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 8,
"charset": "us-ascii",
"checksum": "640810c6b7df7507016d7ae0348c37820321c470",
"ctime": 1626745293.6330574,
"dev": 64768,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 103156603,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "0600",
"mtime": 1626745293.6330574,
"nlink": 1,
"path": "/root/anaconda-ks.cfg",
"pw_name": "root",
"readable": true,
"rgrp": false,
"roth": false,
"rusr": true,
"size": 1375,
"uid": 0,
"version": "3471356110",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
}
}
PLAY RECAP *********************************************************************
192.168.136.225 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
synchronize模块
[root@ansible playbook]# vim ttt.yml
[root@ansible playbook]# cat ttt.yml
---
- hosts: all
gather_facts: no
tasks:
- name: k
yum:
name: rsync
state: present
- name:
synchronize:
src: fest
dest: /opt
[root@ansible playbook]# ansible-playbook ttt.yml
PLAY [all] *********************************************************************
TASK [k] ***********************************************************************
ok: [192.168.136.225]
TASK [synchronize] *************************************************************
changed: [192.168.136.225]
PLAY RECAP *********************************************************************
192.168.136.225 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost opt]# ls
fest