copy 复制模块
1. 概要
copy
复制模块将文件从本地或远程计算机复制到远程计算机上的某个位置。- 使用
fetch
复制模块可以将文件从远程位置复制到 ansible 主机文件夹。 - 如果需要在复制的文件中进行大量变量插值,请使用
template
模板模块。 在内容字段中使用变量将导致不可预测的输出。 - 对于 Windows 目标,请使用用
win_copy
模块。 - 递归复制模块的复制功能无法扩展到大量(> 数百个)文件,即当递归复制大量文件时会非常的慢,这时推荐使用
synchronize
模块 (synchronize 同步模块是 rsync 的包装器,它在递归复制大量深层嵌套文件方面非常高效且快速)。 - 源码:https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/copy.py
- 官方文档:https://docs.ansible.com/ansible/latest/modules/copy_module.html
2. 参数
参数 | 可选值 | 默认值 | 说明 |
---|---|---|---|
attributes |
string ,复制后的文件或文件夹的属性,默认是 = ,如果需要进行 + 、- 操作,则需要包含在字符串中。别名 attr 。可以参考 chattr 。 |
||
backup |
yes/no | no | boolean ,创建一个带时间戳的备份文件,以防不小心破坏文件的情况下找到原始文件。 |
checksum |
string ,传输文件的 SHA1 校验和。用于验证文件副本是否成功。如果未提供,则 Ansible 将使用 src 文件的本地计算校验和。 |
||
content |
string , 当代替 src 使用时,将文件的内容直接设置为指定的值。仅在 dest 是文件时有效。 如果文件不存在,则创建它。对于高级格式化,或者如果内容包含变量,请使用 template 模板模块。content 与 src 必须提供一个! |
||
decrypt |
yes/no | yes | boolean ,此选项使用 Vault 控制源文件的自动解密。 |
dest required |
path ,文件应复制到的远程绝对路径。如果 src 是目录,则 dest 必须也是目录;如果 dest 是不存在的路径,并且 dest 以 “/” 结尾或 src 是目录,则创建 dest 目录;如果 dest 是相对路径,则路径开始值由远程主机决定;如果 src 和 dest 是文件,则不会创建 dest 的父目录,如果父目录不存在,则该任务将失败。 |
||
directory_mode |
raw ,如 directory_mode='0770' , 当进行递归复制时,新创建的文件夹使用的文件夹模式,该参数对已经存在的文件夹没有影响,但对子目录有影响。如果目标目录不存在,则会新建目录,并且对目标目录及其子目录都会应用该文件夹权限模式;如果目标目录存在,则不会影响目标目录本身,只会影响目标目录的子目录! |
||
follow |
yes/no | no | 是否跟踪目标系统上面的链接文件。 |
force |
yes/no | yes | 是否强制覆盖已经存在的文件。当设置为 yes 时当远程文件内容与源文件内容不同时就会被替换掉;当设置为 no 时,只会传输远程主机上不存在的文件。 |
group |
string , 用户组的名称。 |
||
local_follow |
yes/no | yes | 是否跟踪源系统上面的链接文件。 |
mode |
path , 目标文件或目录的权限。对于那些习惯于 /usr/bin/chmod 的用户,请记住模式实际上是八进制数。您必须添加一个前导零,以便 Ansible 的 YAML 解析器知道它是一个八进制数 (例如 0644 或 01777 ) 或用引号 (例如'644' 或'1777' ) 来使 Ansible 接收字符串并可以从字符串进行自己的转换成数字。不遵循这些规则的话,Ansible 将会这这些数字当做十进制数,这将引起异常。从 Ansible1.8 开始,可以将模式指定为符号模式(例如,u+rwx 或 u=rw,g=r,o=r )。从 Ansible2.3 开始,该模式也可能是 preserve , 表示保留源文件相同的权限。(The permissions are r for read, w for write and x for execute.) |
||
owner |
string ,文件拥有者名称。 |
||
remote_src |
yes/no | no | boolean ,如果设置为 yes ,则会在远程主机上寻找 src 源文件;如果设置为 no ,则会在 Ansible master 主机上面寻找 src 源文件。 |
src |
path , 本地待复制的文件。可以是相对或绝对路径。如果路径是目录,则会递归复制。如果路径以 “/” 结尾,则仅将该目录的内部内容复制到目标位置。 否则,如果它不以 “ /” 结尾,则将复制路径本身及目录下所有的内容。 此行为类似于 rsync 命令行工具。content 与 src 必须提供一个! |
||
unsafe_writes |
yes/no | no | boolean , 影响何时使用原子操作来防止数据损坏或对目标文件的读取不一致。 默认情况下,此模块使用原子操作来防止数据损坏或对目标文件的读取不一致,但是有时会以防止这种情况的方式配置或破坏系统。一个示例是 docker 挂载的文件,该文件无法从容器内部进行原子更新,只能以不安全的方式写入。 当原子操作失败时,此选项允许 Ansible 退回到不安全的文件更新方法(但是,它不会强制 Ansible 执行不安全的写操作)。 重要!不安全的写入会受到竞争条件的影响,并可能导致数据损坏。 |
validate |
string ,验证命令在复制之前运行,保证命令安全传递。 |
3. 返回值
键 | 何时返回 | 描述信息 |
---|---|---|
backup_file string | backup=yes 时 |
备份文件的路径,如 /path/to/file.txt.2015-02-12@22:09~ |
checksum string | success | 复制后文件的 SHA1 校验和,如 6e642bb8dd5c2e027bf21dd923337cbb4214f827 |
dest string | success | 目标路径 /path/to/file.txt |
gid integer | success | GID, 如 100 |
group string | success | 文件的组名,如 httpd |
md5sum string | when supported | 复制后文件的 MD5 校验和,如 2a5aeecc61dc98c4d780b14b330e3282 |
mode string | success | 目标权限,如 420 |
owner string | success | 文件的 owner, 如 httpd |
size integer | success | 文件的大小,如 1220 |
src string | changed | 用于在目标计算机上进行复制的源文件,如 /home/httpd/.ansible/tmp/ansible-tmp-1423796390.97-147729857856000/source |
state string | success | 执行后目标的状态,如 file |
uid integer | success | 文件的 owner ID, 如 100 |
4. 临时命令的使用
复制家目录下面的文件:
[ansible@master ~]$ ansible node1 -m copy -a 'src=.bashrc dest=/tmp/test.bashrc' node1 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "checksum": "b034d28772e19df759119731956ffd27b21ce399", "dest": "/tmp/test.bashrc", "gid": 1001, "group": "ansible", "md5sum": "2df33d5c8322df0b3e9afa2b923efa37", "mode": "0664", "owner": "ansible", "size": 350, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1595920692.14-3848-131725126874205/source", "state": "file", "uid": 1001 }; [ansible@master ~]$
在 node1 节点上面查看文件信息:
# 查看复制后的文件的权限、所属、大小等信息 [ansible@node1 ~]$ ls -lah /tmp/test.bashrc -rw-rw-r-- 1 ansible ansible 350 Jul 28 15:18 /tmp/test.bashrc # 查看md5sum值 [ansible@node1 ~]$ md5sum /tmp/test.bashrc 2df33d5c8322df0b3e9afa2b923efa37 /tmp/test.bashrc # 查看sha1sum值 [ansible@node1 ~]$ sha1sum /tmp/test.bashrc b034d28772e19df759119731956ffd27b21ce399 /tmp/test.bashrc # 查看用户信息 [ansible@node1 ~]$ id ansible uid=1001(ansible) gid=1001(ansible) groups=1001(ansible) [ansible@node1 ~]$
可以看到 md5 值、sha1 值、文件大小等信息与 Ansible 返回信息中的值是一样的。我们此处简单的使用临时命令进行复制操作。
5. 剧本的使用
5.1 仅指定 dest
参数进行复制
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: # copy no src path - name: copy no src path copy: dest: /tmp/nosrc [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [copy no src path] ************************************************************** fatal: [node1]: FAILED! => {"changed": false, "msg": "src (or content) is required"} PLAY RECAP *************************************************************************** node1 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
可以看到,提示 "src (or content) is required"
, 即至少应指定 src
或 content
参数之一。
5.2 指定 src 和 dest 参数
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: copy .bashrc to /tmp copy: src: .bashrc dest: /tmp [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [copy .bashrc to /tmp] ********************************************************** changed: [node1] => {"changed": true, "checksum": "b034d28772e19df759119731956ffd27b21ce399", "dest": "/tmp/.bashrc", "gid": 1001, "group": "ansible", "md5sum": "2df33d5c8322df0b3e9afa2b923efa37", "mode": "0664", "owner": "ansible", "size": 350, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1595923204.2-3968-122237293978653/source", "state": "file", "uid": 1001} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
可以看到能够正常的复制到 dest
指定目录中,如果 src
指定的文件不是绝对路径,则会在当前用户的家目录或者家目录下面 files
目录查找文件。
我们检查一下是否真的会从 files
目录下面复制文件:
# 首先准备一个files目录,然后里面存放mycopy,yml文件 [ansible@master ~]$ cat files/mycopy.yml - hosts: node1 tasks: # 检查ansible是否会在files路径下面复制文件 - name: copy mycopy.yml to /tmp copy: src: mycopy.yml dest: /tmp/ [ansible@master ~]$ # 查看剧本文件 [ansible@master ~]$ cat copy.yml - hosts: node1 tasks: # 检查ansible是否会在files路径下面复制文件 - name: copy mycopy.yml to /tmp copy: src: mycopy.yml dest: /tmp/ [ansible@master ~]$ # 剧本文件规范性检查 [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ # 剧本文件语法检查 [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ # 执行剧本 [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [copy mycopy.yml to /tmp] ******************************************************* changed: [node1] => {"changed": true, "checksum": "b7e88a61065eee4162a43ecbb964291ff4519465", "dest": "/tmp/mycopy.yml", "gid": 1001, "group": "ansible", "md5sum": "15c25e81393f06a358082f66c3d1606f", "mode": "0664", "owner": "ansible", "size": 178, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596164759.88-3980-121681678092154/source", "state": "file", "uid": 1001} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
可以看到,能够正常执行,我们再在 node1 节点上面检查一下,是否有 mycopy.yml 文件:
[ansible@node1 ~]$ ls -lah /tmp/mycopy.yml -rw-rw-r-- 1 ansible ansible 178 Jul 31 11:06 /tmp/mycopy.yml [ansible@node1 ~]$ md5sum /tmp/mycopy.yml 15c25e81393f06a358082f66c3d1606f /tmp/mycopy.yml [ansible@node1 ~]$ sha1sum /tmp/mycopy.yml b7e88a61065eee4162a43ecbb964291ff4519465 /tmp/mycopy.yml [ansible@node1 ~]$ cat /tmp/mycopy.yml - hosts: node1 tasks: # 检查ansible是否会在files路径下面复制文件 - name: copy mycopy.yml to /tmp copy: src: mycopy.yml dest: /tmp/ [ansible@node1 ~]$
可以看到文件正常复制!
我们现在将 files
文件夹重命名一下:
[ansible@master ~]$ mv files/ files_new [ansible@master ~]$ ls -ld files_new/ drwxrwxr-x 2 ansible ansible 24 Jul 31 11:03 files_new/
然后再执行一下剧本:
[ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [copy mycopy.yml to /tmp] ******************************************************* An exception occurred during task execution. To see the full traceback, use -vvv. The error was: If you are using a module and expect the file to exist on the remote, see the remote_src option fatal: [node1]: FAILED! => {"changed": false, "msg": "Could not find or access 'mycopy.yml'\nSearched in:\n\t/home/ansible/files/mycopy.yml\n\t/home/ansible/mycopy.yml\n\t/home/ansible/files/mycopy.yml\n\t/home/ansible/mycopy.yml on the Ansible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option"} PLAY RECAP *************************************************************************** node1 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
此时,可以看到,执行失败,因为此时没有找到 mycopy.yml
文件!
通过以上可以知道,Ansible 会从用户家目录或者家目录下面的 files
文件夹去搜索需要复制的文件。
5.3 指定文件的 UID/GID 和 mode
我们现在来尝试指定复制后文件的用户、用户组以及权限模式。
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy file with owner and permissions copy: src: /etc/httpd/conf/httpd.conf dest: /etc/foo1.conf owner: jenkins group: zabbix mode: '0644' - name: Copy file with owner and permission, using symbolic representation copy: src: /etc/httpd/conf/httpd.conf dest: /etc/foo2.conf owner: root group: root mode: u=rw,g=r,o=r - name: Another symbolic mode example, adding some permissions and removing others copy: src: /etc/httpd/conf/httpd.conf dest: /etc/foo3.conf owner: root group: tester1 mode: u+rw,g-wx,o-rwx [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy file with owner and permissions] ****************************************** fatal: [node1]: FAILED! => {"changed": false, "checksum": "fdb1090d44c1980958ec96d3e2066b9a73bfda32", "msg": "Destination /etc not writable"} PLAY RECAP *************************************************************************** node1 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
上面可以看到,当复制文件到 Ansible 家目录、/tmp 目录以外其他目录时,没有写权限。需要进行权限提升,我们修改一下剧本文件:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy file with owner and permissions copy: src: /etc/httpd/conf/httpd.conf dest: /etc/foo1.conf owner: jenkins group: zabbix mode: '0644' become: yes - name: Copy file with owner and permission, using symbolic representation copy: src: /etc/httpd/conf/httpd.conf dest: /etc/foo2.conf owner: root group: root mode: u=rw,g=r,o=r become: yes - name: Another symbolic mode example, adding some permissions and removing others copy: src: /etc/httpd/conf/httpd.conf dest: /etc/foo3.conf owner: root group: tester1 mode: u+rw,g-wx,o-rwx become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy file with owner and permissions] ****************************************** changed: [node1] => {"changed": true, "checksum": "fdb1090d44c1980958ec96d3e2066b9a73bfda32", "dest": "/etc/foo1.conf", "gid": 1004, "group": "zabbix", "md5sum": "f5e7449c0f17bc856e86011cb5d152ba", "mode": "0644", "owner": "jenkins", "size": 11753, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596176584.91-13692-7976699276027/source", "state": "file", "uid": 1003} TASK [Copy file with owner and permission, using symbolic representation] ************ changed: [node1] => {"changed": true, "checksum": "fdb1090d44c1980958ec96d3e2066b9a73bfda32", "dest": "/etc/foo2.conf", "gid": 0, "group": "root", "md5sum": "f5e7449c0f17bc856e86011cb5d152ba", "mode": "0644", "owner": "root", "size": 11753, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596176585.51-13708-155970258986390/source", "state": "file", "uid": 0} TASK [Another symbolic mode example, adding some permissions and removing others] **** changed: [node1] => {"changed": true, "checksum": "fdb1090d44c1980958ec96d3e2066b9a73bfda32", "dest": "/etc/foo3.conf", "gid": 1010, "group": "tester1", "md5sum": "f5e7449c0f17bc856e86011cb5d152ba", "mode": "0640", "owner": "root", "size": 11753, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596176585.9-13724-113578652198919/source", "state": "file", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
通过 become: yes
权限提升后,正常复制了文件,我们在 node1 节点上面查看一下:
[ansible@node1 ~]$ ls -lah /etc/foo* -rw-r--r-- 1 jenkins zabbix 12K Jul 31 14:23 /etc/foo1.conf -rw-r--r-- 1 root root 12K Jul 31 14:23 /etc/foo2.conf -rw-r----- 1 root tester1 12K Jul 31 14:23 /etc/foo3.conf [ansible@node1 ~]$
可以看到,权限也如我们期望的一样,用户、用户组都按剧本的要求设置成功了。我们将 node1 节点上测试用的文件删除掉:
[ansible@node1 ~]$ trash-put /tmp/mycopy.yml [ansible@node1 ~]$ trash-empty [ansible@node1 ~]$ sudo trash-put /etc/foo* [ansible@node1 ~]$ sudo trash-empty
5.4 备份文件
我们来准备两个文件 /etc/master.foo
和 /etc/node1.foo
。
Ansible 主机上面准备 /etc/master.foo
文件:
# 直接使用重定向会提示权限拒绝。 # 这是因为重定向符号">"也是bash的命令。sudo只是让echo命令具有了root权限,但是没有让">"命令也具有root权限,所以bash会认为这个命令没有写入信息的权限。 [ansible@master ~]$ sudo echo "foo in master" > /etc/master.foo bash: /etc/master.foo: Permission denied # 写文件 [ansible@master ~]$ echo "foo in master"|sudo tee /etc/master.foo foo in master [ansible@master ~]$ ls -lah /etc/master.foo -rw-r--r-- 1 root root 14 Jul 31 14:46 /etc/master.foo # 查看文件内容 [ansible@master ~]$ cat /etc/master.foo foo in master [ansible@master ~]$
node1 节点上面准备 /etc/node1.foo
文件:
[ansible@node1 ~]$ echo "foo in node1"|sudo tee /etc/node1.foo foo in node1 [ansible@node1 ~]$ ls -lah /etc/node1.foo -rw-r--r-- 1 root root 13 Jul 31 14:49 /etc/node1.foo [ansible@node1 ~]$ cat /etc/node1.foo foo in node1 [ansible@node1 ~]$
下面我们来测试备份功能。
# 查看剧本文件,复制时增加了`backup: yes`参数 [ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy a new node1.foo file into place, backing up the original if it differs from the copied version copy: src: /etc/master.foo dest: /etc/node1.foo mode: '0644' backup: yes become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml # 执行剧本 [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy a new node1.foo file into place, backing up the original if it differs from the copied version] *** changed: [node1] => {"backup_file": "/etc/node1.foo.6098.2020-07-31@14:53:30~", "changed": true, "checksum": "2d389645b886c601eedf448a4c1242c632d59fa4", "dest": "/etc/node1.foo", "gid": 0, "group": "root", "md5sum": "a6a70d7678b826b0020de76cae84444e", "mode": "0644", "owner": "root", "size": 14, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596178410.36-15268-51793262793377/source", "state": "file", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
可以看到返回值时,增加了 "backup_file": "/etc/node1.foo.6098.2020-07-31@14:53:30~"
,即有一个备份文件。
我们在 node1 节点上面检查一下:
[ansible@node1 ~]$ ls -lah /etc/node1* -rw-r--r-- 1 root root 14 Jul 31 14:53 /etc/node1.foo -rw-r--r-- 1 root root 13 Jul 31 14:49 /etc/node1.foo.6098.2020-07-31@14:53:30~ [ansible@node1 ~]$ cat /etc/node1.foo foo in master [ansible@node1 ~]$ cat /etc/node1.foo.6098.2020-07-31\@14\:53\:30~ foo in node1 [ansible@node1 ~]$
可以看到,原来的文件已经成功备份了!可以看到,备份的的目标文件,如果目标文件原来已经存在,就可以进行备份!
5.5 对目标文件进行有效性验证、在远程主机上面复制文件
我们对 /etc/sudoers
文件进行复制,注意此文件的特殊性:
[ansible@master ~]$ ls -lah /etc/sudoers -r--r----- 1 root root 4.3K Jun 15 11:36 /etc/sudoers
默认情况下,除了 root 用户和 root 组外,其他用户是不能查看的,就算我们在剧本中使用 become
权限提升也会出现异常:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy a new "sudoers" file into place, after passing validation with visudo copy: src: /etc/sudoers dest: /etc/sudoers.edit validate: /usr/sbin/visudo -csf %s backup: yes become: yes - name: Copy a "sudoers" file on the remote machine for editing copy: src: /etc/sudoers dest: /etc/sudoers.edit remote_src: yes validate: /usr/sbin/visudo -csf %s backup: yes become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy a new "sudoers" file into place, after passing validation with visudo] **** fatal: [node1]: FAILED! => {"msg": "an error occurred while trying to read the file '/etc/sudoers': [Errno 13] Permission denied: '/etc/sudoers'"} PLAY RECAP *************************************************************************** node1 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
可以看到,虽然我们已经增加了 become: yes
选项,仍然不能读取文件 /etc/sudoers
。原因是,此处的 become: yes
是对远程节点上面的操作进行权限提升,不是对 Ansible 主机上面进行权限提示,默认情况下,ansible 账号是不能读取文件 /etc/sudoers
的,我们试一下就知道:
[ansible@master ~]$ cat /etc/sudoers cat: /etc/sudoers: Permission denied [ansible@master ~]$
为了使得我们能够正常的复制文件 /etc/sudoers
, 我们需要给它的 other 增加 r
读权限!
我们使用临时命令改一下权限 (注意,记得等会改回来!!!):
[ansible@master ~]$ ansible localhost -b -m command -a "chmod o+r -v /etc/sudoers" [WARNING]: Consider using the file module with mode rather than running 'chmod'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. localhost | CHANGED | rc=0 >> mode of ‘/etc/sudoers’ changed from 0440 (r--r-----) to 0444 (r--r--r--) [ansible@master ~]$ ls -lah /etc/sudoers -r--r--r-- 1 root root 4.3K Jun 15 11:36 /etc/sudoers
然后,我们再执行剧本看看:
[ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy a new "sudoers" file into place, after passing validation with visudo] **** changed: [node1] => {"changed": true, "checksum": "fc1b13262ba3f494d09e70b9c16cfb312bb30fa5", "dest": "/etc/sudoers.edit", "gid": 0, "group": "root", "md5sum": "1957e5b5957bbca9eecdeee7a2ecd799", "mode": "0644", "owner": "root", "size": 4360, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596184442.73-20594-199025725859240/source", "state": "file", "uid": 0} TASK [Copy a "sudoers" file on the remote machine for editing] *********************** changed: [node1] => {"backup_file": "/etc/sudoers.edit.12668.2020-07-31@16:34:03~", "changed": true, "checksum": "e4e30f4236105f9314f72b4166fc61c8f1d53560", "dest": "/etc/sudoers.edit", "gid": 0, "group": "root", "md5sum": "ca221b0055d44f1ac93b2e65be3060de", "mode": "0644", "owner": "root", "size": 4366, "src": "/etc/sudoers", "state": "file", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
发现可以正常执行!我们在 node1 节点上面检查一下:
[ansible@node1 ~]$ ls -lah /etc/sudoers* -r--r-----. 1 root root 4.3K Jun 15 11:37 /etc/sudoers -rw-r--r-- 1 root root 4.3K Jun 15 11:37 /etc/sudoers.edit -rw-r--r-- 1 root root 4.3K Jul 31 16:34 /etc/sudoers.edit.12668.2020-07-31@16:34:03~ ls: cannot open directory /etc/sudoers.d: Permission denied [ansible@node1 ~]$ l
可以看到,任务 1 并没有进行备份文件,因为刚开始的时候 /etc/sudoers.edit
并不存在。任务 2 对文件进行了备份!
这个时候,我们不知道 Ansible 是否对新生成的配置文件进行了校验!
我们在 node1 节点上面修改一下 /etc/sudoers.edit
文件,在最后增加一行 notexistuser
,然后检查一下这个文件的有效性:
[ansible@node1 ~]$ nl -ba /etc/sudoers.edit|tail 113 ## cdrom as root 114 # %users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom 115 116 ## Allows members of the users group to shutdown this system 117 # %users localhost=/sbin/shutdown -h now 118 119 ## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment) 120 #includedir /etc/sudoers.d 121 ansible ALL=(ALL) NOPASSWD: ALL 122 notexistuser [ansible@node1 ~]$ sudo visudo -csf /etc/sudoers.edit >>> /etc/sudoers.edit: syntax error near line 122 <<< parse error in /etc/sudoers.edit near line 122 [ansible@node1 ~]$ [ansible@node1 ~]$ ls -lah /etc/sudoers.edit -rw-r--r-- 1 root root 4.3K Jul 31 16:38 /etc/sudoers.edit
可以看到 122 行配置的是有问题的!并且此时权限是 0644
的,即 root
用户也是有 w
写权限的。
我们修改一下剧本文件,并执行:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy a "sudoers" file on the remote machine for editing copy: src: /etc/sudoers.edit dest: /etc/sudoers.edit1 remote_src: yes validate: /usr/sbin/visudo -csf %s owner: root group: root mode: u=r,g=r backup: yes become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy a "sudoers" file on the remote machine for editing] *********************** fatal: [node1]: FAILED! => {"changed": false, "exit_status": 1, "msg": "failed to validate", "stderr": ">>> /etc/sudoers.edit: syntax error near line 122 <<<\n", "stderr_lines": [">>> /etc/sudoers.edit: syntax error near line 122 <<<"], "stdout": "parse error in /etc/sudoers.edit near line 122\n", "stdout_lines": ["parse error in /etc/sudoers.edit near line 122"]} PLAY RECAP *************************************************************************** node1 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
此时可以看到,校验时发生异常,Ansible 剧本执行失败。但是,此时检查 /etc/sudoers.edit
的权限,会发现已经被修改了:
[ansible@node1 ~]$ ls -lah /etc/sudoers.edit -r--r--r-- 1 root root 4.3K Jul 31 16:38 /etc/sudoers.edit
由于有异常,此处修改将权限修改回去:
[ansible@node1 ~]$ ls -lah /etc/sudoers.edit -r--r--r-- 1 root root 4.3K Jul 31 16:38 /etc/sudoers.edit [ansible@node1 ~]$ sudo chmod u+w -v /etc/sudoers.edit mode of ‘/etc/sudoers.edit’ changed from 0444 (r--r--r--) to 0644 (rw-r--r--) [ansible@node1 ~]$ ls -lah /etc/sudoers.edit -rw-r--r-- 1 root root 4.3K Jul 31 16:38 /etc/sudoers.edit [ansible@node1 ~]$
我们使用彩排模式来运行一下:
[ansible@master ~]$ ansible-playbook --check copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy a "sudoers" file on the remote machine for editing] *********************** changed: [node1] => {"changed": true, "checksum": "35c174b6dd6ad47c967fc337033f54d8e34d4ab8", "dest": "/etc/sudoers.edit1", "md5sum": "c66d111bcf71ed350d262109e3bc7298", "src": "/etc/sudoers.edit"} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
彩排模式下并没有发现有任何异常,说明此时并没有检查出配置文件的问题。
好,说明 Ansible 在复制时,是正常进行了校验的!我们再把 /etc/sudoers.edit
最后一行的内容删除掉:
[ansible@node1 ~]$ nl -ba /etc/sudoers.edit|tail 112 ## Allows members of the users group to mount and unmount the 113 ## cdrom as root 114 # %users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom 115 116 ## Allows members of the users group to shutdown this system 117 # %users localhost=/sbin/shutdown -h now 118 119 ## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment) 120 #includedir /etc/sudoers.d 121 ansible ALL=(ALL) NOPASSWD: ALL [ansible@node1 ~]$ ls -lah /etc/sudoers.edit -rw-r--r-- 1 root root 4.3K Jul 31 17:30 /etc/sudoers.edit [ansible@node1 ~]$
再执行剧本:
[ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy a "sudoers" file on the remote machine for editing] *********************** changed: [node1] => {"changed": true, "checksum": "e4e30f4236105f9314f72b4166fc61c8f1d53560", "dest": "/etc/sudoers.edit1", "gid": 0, "group": "root", "md5sum": "ca221b0055d44f1ac93b2e65be3060de", "mode": "0444", "owner": "root", "size": 4366, "src": "/etc/sudoers.edit", "state": "file", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
但是此时并没有进行备份,因为 /etc/sudoers.edit1
本来就不存在,不需要备份。检查配置文件没有出现异常!但是,权限好像并不是我们想要的 -r-r-----
:
ansible@node1 ~]$ ls -lah /etc/sudoers* -r--r-----. 1 root root 4.3K Jun 15 11:37 /etc/sudoers -r--r--r-- 1 root root 4.3K Jul 31 17:30 /etc/sudoers.edit -r--r--r-- 1 root root 4.3K Jul 31 17:30 /etc/sudoers.edit1 -rw-r--r-- 1 root root 4.3K Jul 31 16:34 /etc/sudoers.edit.12668.2020-07-31@16:34:03~ ls: cannot open directory /etc/sudoers.d: Permission denied [ansible@node1 ~]$
然后,/etc/sudoers.edit
的权限又变了!!
我们把生成的文件删除掉,并且把权限改回来:
[ansible@node1 ~]$ ls -lah /etc/sudoers* -r--r-----. 1 root root 4.3K Jun 15 11:37 /etc/sudoers -r--r--r-- 1 root root 4.3K Jul 31 17:30 /etc/sudoers.edit -r--r--r-- 1 root root 4.3K Jul 31 17:30 /etc/sudoers.edit1 -rw-r--r-- 1 root root 4.3K Jul 31 16:34 /etc/sudoers.edit.12668.2020-07-31@16:34:03~ ls: cannot open directory /etc/sudoers.d: Permission denied [ansible@node1 ~]$ [ansible@node1 ~]$ sudo trash-put /etc/sudoers.edit1 [ansible@node1 ~]$ sudo chmod u+w -v /etc/sudoers.edit mode of ‘/etc/sudoers.edit’ changed from 0444 (r--r--r--) to 0644 (rw-r--r--) [ansible@node1 ~]$ ls -lah /etc/sudoers* -r--r-----. 1 root root 4.3K Jun 15 11:37 /etc/sudoers -rw-r--r-- 1 root root 4.3K Jul 31 17:30 /etc/sudoers.edit -rw-r--r-- 1 root root 4.3K Jul 31 16:34 /etc/sudoers.edit.12668.2020-07-31@16:34:03~ ls: cannot open directory /etc/sudoers.d: Permission denied [ansible@node1 ~]$
再改一下剧本文件,将 mode: u=r,g=r
改成 mode: u=r,g=r,o=
试试看:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy a "sudoers" file on the remote machine for editing copy: src: /etc/sudoers.edit dest: /etc/sudoers.edit1 remote_src: yes validate: /usr/sbin/visudo -csf %s owner: root group: root mode: u=r,g=r,o= backup: yes become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy a "sudoers" file on the remote machine for editing] *********************** changed: [node1] => {"changed": true, "checksum": "e4e30f4236105f9314f72b4166fc61c8f1d53560", "dest": "/etc/sudoers.edit1", "gid": 0, "group": "root", "md5sum": "ca221b0055d44f1ac93b2e65be3060de", "mode": "0440", "owner": "root", "size": 4366, "src": "/etc/sudoers.edit", "state": "file", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
此时再看查 node1 节点上面的文件:
[ansible@node1 ~]$ ls -lah /etc/sudoers* -r--r-----. 1 root root 4.3K Jun 15 11:37 /etc/sudoers -r--r----- 1 root root 4.3K Jul 31 17:30 /etc/sudoers.edit -r--r----- 1 root root 4.3K Jul 31 17:30 /etc/sudoers.edit1 -rw-r--r-- 1 root root 4.3K Jul 31 16:34 /etc/sudoers.edit.12668.2020-07-31@16:34:03~ ls: cannot open directory /etc/sudoers.d: Permission denied [ansible@node1 ~]$
此时 /etc/sudoers.edit1
权限是对的,但不知道为什么 /etc/sudoers.edit
的写权限还是被删除了!这应该是一个问题!
最后,记得将 ansible 主机上面的 /etc/sudoer
配置文件权限改回去:
[ansible@master ~]$ sudo chmod o-r -v /etc/sudoers mode of ‘/etc/sudoers’ changed from 0444 (r--r--r--) to 0440 (r--r-----)
5.6 通过 content 进行文本复制
首先查看 node1 节点上面有没有我们需要处理的文件:
[ansible@node1 ~]$ ls /etc/mine.conf ls: cannot access /etc/mine.conf: No such file or directory
可以看到没有 /etc/mine.conf
文件。
我们编写剧本文件,通过指定文件内容来复制文件:
# 查看剧本文件 [ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy using inline content copy: content: '# This file was moved to /etc/other.conf' dest: /etc/mine.conf become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml # 执行剧本 [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy using inline content] ***************************************************** changed: [node1] => {"changed": true, "checksum": "2d81dab6cea6299fe8a036e9ad4fa3cd095a7638", "dest": "/etc/mine.conf", "gid": 0, "group": "root", "md5sum": "26b1d9d389ebe90a542b38b3f3cad9c1", "mode": "0644", "owner": "root", "size": 40, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596437858.92-3653-198445832117442/source", "state": "file", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
可以看到剧本正常执行,并创建了文件 /etc/mine.conf
。
我们在 node1 节点上面检查一下:
[ansible@node1 ~]$ ls -lah /etc/mine.conf -rw-r--r-- 1 root root 40 Aug 3 14:57 /etc/mine.conf [ansible@node1 ~]$ cat /etc/mine.conf # This file was moved to /etc/other.conf[ansible@node1 ~]$ [ansible@node1 ~]$
可以看到,创建成功!
5.6.1 多行处理
- 使用单引号或不用引号时,不能正常处理多行
注意,如果需要输入多行文本,使用 \n
是不起作用的,请看下面的示例:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy multi-line using inline content copy: content: 'Hello\nWorld\n' dest: /etc/mine.conf become: yes [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy multi-line using inline content] ****************************************** changed: [node1] => {"changed": true, "checksum": "726303012e97f909aef582cbb1236e45565a12c3", "dest": "/etc/mine.conf", "gid": 0, "group": "root", "md5sum": "496a18b0116261b3ead17521062a6ec5", "mode": "0644", "owner": "root", "size": 14, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596438877.33-3754-79783084979596/source", "state": "file", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
此时在 node1 节点上面检查,可以发现 \n
没有被正常解析:
[ansible@node1 ~]$ cat /etc/mine.conf Hello\nWorld\n[ansible@node1 ~]$ [ansible@node1 ~]$
如果将 content: 'Hello\nWorld\n'
改成 content: Hello\nWorld\n
,生成的文件也不会自动换行!
- 使用双引号能正常处理多行文本
改用双引号包裹需要换行的字符串:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy multi-line using inline content copy: content: "Hello\nWorld\n" dest: /etc/mine.conf become: yes [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy multi-line using inline content] ****************************************** changed: [node1] => {"changed": true, "checksum": "24742cf4aab04750f8d8ab80c4f2900848acaed7", "dest": "/etc/mine.conf", "gid": 0, "group": "root", "md5sum": "f41121a903eafadf258962abc57c8644", "mode": "0644", "owner": "root", "size": 12, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596439037.9-3796-118403454039117/source", "state": "file", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
此时查看 node1 节点上面的文件:
[ansible@node1 ~]$ cat /etc/mine.conf Hello World [ansible@node1 ~]$
可以看到,此时正常换行了!!
- 使用变量处理多行文本
也可以通过使用变量处理多行文本,可以参考 How can I copy a multi-line string to a file with literal newlines?。
我们将 node1 上面生成的临时文件删除掉,重新来复制:
[ansible@node1 ~]$ sudo trash-put /etc/mine.conf [ansible@node1 ~]$ sudo trash-empty [ansible@node1 ~]$ cat /etc/mine.conf cat: /etc/mine.conf: No such file or directory
说明文件已经删除了,我们再来复制:
[ansible@master ~]$ cat copy.yml - hosts: node1 vars: mytext: | Hello world! tasks: - name: Copy using inline content copy: content: "{{ mytext }}" dest: /etc/mine.conf become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy using inline content] ***************************************************** changed: [node1] => {"changed": true, "checksum": "520297853d3b60208a9670a96dcef080ba4798ed", "dest": "/etc/mine.conf", "gid": 0, "group": "root", "md5sum": "4de8e8c09e399aafdf1d9cf55e6007ce", "mode": "0644", "owner": "root", "size": 13, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596439506.57-3920-116668763239110/source", "state": "file", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
剧本正常执行,此时查看 node1 节点上面的文件:
[ansible@node1 ~]$ cat /etc/mine.conf Hello world! [ansible@node1 ~]$
可以看到,此时也正常生成了多行文本!
5.6.2 动态模板插值
我们也可以使用 copy
模块进行少量的动态模板插值处理,如果你需要编写大量的模板化文件的话,建议使用 template
模块。
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy using inline content copy: content: "Hello, {{ ansible_user_id }} @ {{ ansible_hostname }}\n" dest: /etc/mine.conf become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy using inline content] ***************************************************** changed: [node1] => {"changed": true, "checksum": "3ed88e0737d6bd865389f37292d85648ec547bd4", "dest": "/etc/mine.conf", "gid": 0, "group": "root", "md5sum": "dac6cb7d1d0d30e3c7b9ef7c06eff1a0", "mode": "0644", "owner": "root", "size": 23, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596441196.11-4156-138994193287357/source", "state": "file", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
我们在剧本中使用了两个动态的变量 ansible_user_id
和 ansible_hostname
,此时剧本正常执行,我们在 node1 节点上面检查一下:
[ansible@node1 ~]$ cat /etc/mine.conf Hello, ansible @ node1 [ansible@node1 ~]$
我们把这个 /etc/mine.conf
测试文件删除掉。
5.7 文件夹复制
我们来复制一下 /home/ansible
目录到新的服务器上面,看一下效果。
首先,准备一些基础文件,包含链接文件:
[ansible@master ~]$ ls -li data/ total 16 18231173 lrwxrwxrwx 1 root root 6 Aug 3 16:34 link1 -> origin 18231174 lrwxrwxrwx 1 root root 6 Aug 3 16:34 link2 -> origin 18231177 lrwxrwxrwx 1 root root 11 Aug 3 16:35 link3 -> origin3.txt 18231175 -rw-rw-r-- 2 ansible ansible 9 Aug 3 16:35 link3_hard 18231178 lrwxrwxrwx 1 root root 11 Aug 3 16:35 link4 -> origin4.txt 18231176 -rw-rw-r-- 2 ansible ansible 9 Aug 3 16:35 link4_hard 33608935 drwxrwxr-x 2 ansible ansible 44 Aug 3 16:34 origin 18231175 -rw-rw-r-- 2 ansible ansible 9 Aug 3 16:35 origin3.txt 18231176 -rw-rw-r-- 2 ansible ansible 9 Aug 3 16:35 origin4.txt [ansible@master ~]$ ls -li data/origin total 8 18231170 -rw-rw-r-- 1 ansible ansible 9 Aug 3 16:33 origin1.txt 18231172 -rw-rw-r-- 1 ansible ansible 9 Aug 3 16:33 origin2.txt [ansible@master ~]$ [ansible@master ~]$ tree data data ├── link1 -> origin ├── link2 -> origin ├── link3 -> origin3.txt ├── link3_hard ├── link4 -> origin4.txt ├── link4_hard ├── origin │ ├── origin1.txt │ └── origin2.txt ├── origin3.txt └── origin4.txt 3 directories, 8 files [ansible@master ~]$
注意,通过 -i
参数可以看到文件的 inode 值,可以看到软硬链接的 inode 值。
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy directory without trailing slash copy: src: /home/ansible/data dest: /tmp/data1 become: yes - name: Copy directory with trailing slash copy: src: /home/ansible/data/ dest: /tmp/data2 become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy directory without trailing slash] ***************************************** changed: [node1] => {"changed": true, "dest": "/tmp/data1/", "src": "/home/ansible/data"} TASK [Copy directory with trailing slash] ******************************************** changed: [node1] => {"changed": true, "dest": "/tmp/data2/", "src": "/home/ansible/data/"} PLAY RECAP *************************************************************************** node1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
此时,查看一下 node1 节点上面的文件情况:
[ansible@node1 tmp]$ ll -i data* data1: total 0 17046823 drwxr-xr-x 5 root root 146 Aug 3 16:54 data data2: total 24 33657173 drwxr-xr-x 2 root root 44 Aug 3 16:54 link1 50445909 drwxr-xr-x 2 root root 44 Aug 3 16:54 link2 33657168 -rw-r--r-- 1 root root 9 Aug 3 16:54 link3 33657170 -rw-r--r-- 1 root root 9 Aug 3 16:54 link3_hard 33657169 -rw-r--r-- 1 root root 9 Aug 3 16:54 link4 33657171 -rw-r--r-- 1 root root 9 Aug 3 16:54 link4_hard 314097 drwxr-xr-x 2 root root 44 Aug 3 16:54 origin 33657165 -rw-r--r-- 1 root root 9 Aug 3 16:54 origin3.txt 33657167 -rw-r--r-- 1 root root 9 Aug 3 16:54 origin4.txt [ansible@node1 tmp]$ [ansible@node1 tmp]$ ll -i data1/data/ total 24 33657124 drwxr-xr-x 2 root root 44 Aug 3 16:54 link1 50445906 drwxr-xr-x 2 root root 44 Aug 3 16:54 link2 18061210 -rw-r--r-- 1 root root 9 Aug 3 16:54 link3 16781287 -rw-r--r-- 1 root root 9 Aug 3 16:54 link3_hard 18061222 -rw-r--r-- 1 root root 9 Aug 3 16:54 link4 16777294 -rw-r--r-- 1 root root 9 Aug 3 16:54 link4_hard 211760 drwxr-xr-x 2 root root 44 Aug 3 16:54 origin 18061205 -rw-r--r-- 1 root root 9 Aug 3 16:54 origin3.txt 18061208 -rw-r--r-- 1 root root 9 Aug 3 16:54 origin4.txt [ansible@node1 tmp]$ [ansible@node1 tmp]$ tree data* data1 └── data ├── link1 │ ├── origin1.txt │ └── origin2.txt ├── link2 │ ├── origin1.txt │ └── origin2.txt ├── link3 ├── link3_hard ├── link4 ├── link4_hard ├── origin │ ├── origin1.txt │ └── origin2.txt ├── origin3.txt └── origin4.txt data2 ├── link1 │ ├── origin1.txt │ └── origin2.txt ├── link2 │ ├── origin1.txt │ └── origin2.txt ├── link3 ├── link3_hard ├── link4 ├── link4_hard ├── origin │ ├── origin1.txt │ └── origin2.txt ├── origin3.txt └── origin4.txt 7 directories, 24 files [ansible@node1 tmp]$
此时,可以看出来当 src
路径最后带 /
时,会直接复制文件夹中的子文件夹和文件;当 src
路径最后不带 /
时,会直接复制 src
所指定的文件夹,以及其子文件夹和文件。
另外,文件所属关系是 root:root
。
5.8 跟随链接文件
去们接着分析上节中的示例最后的文件情况。
链接文件文件夹的情况:
由于默认情况下 local_follow
参数是否跟踪源系统上面的链接文件的值是 yes
,即默认会跟踪源系统上面的链接文件。因此我们在复制 link1
和 link2
时,会复制 link1
、link2
所指向的源文件 origin
文件夹下面的文件 origin1.txt
和 origin2.txt
,因此此时,在 node1 节点是 link1
和 link2
变成了文件夹,而不是软链接,并且在这两个文件夹中都有文件 origin1.txt
和 origin2.txt
。
再查看一下软、硬链接文件的情况:
[ansible@node1 tmp]$ cd data1/data/ [ansible@node1 data]$ ls link1 link2 link3 link3_hard link4 link4_hard origin origin3.txt origin4.txt [ansible@node1 data]$ ll -i . total 24 33657124 drwxr-xr-x 2 root root 44 Aug 3 16:54 link1 50445906 drwxr-xr-x 2 root root 44 Aug 3 16:54 link2 18061210 -rw-r--r-- 1 root root 9 Aug 3 16:54 link3 16781287 -rw-r--r-- 1 root root 9 Aug 3 16:54 link3_hard 18061222 -rw-r--r-- 1 root root 9 Aug 3 16:54 link4 16777294 -rw-r--r-- 1 root root 9 Aug 3 16:54 link4_hard 211760 drwxr-xr-x 2 root root 44 Aug 3 16:54 origin 18061205 -rw-r--r-- 1 root root 9 Aug 3 16:54 origin3.txt 18061208 -rw-r--r-- 1 root root 9 Aug 3 16:54 origin4.txt [ansible@node1 data]$ cat link3 origin 3 [ansible@node1 data]$ cat link3_hard origin 3 [ansible@node1 data]$ cat link4 origin 4 [ansible@node1 data]$ cat link4_hard origin 4 [ansible@node1 data]$ cat origin3.txt origin 3 [ansible@node1 data]$ cat origin4.txt origin 4 [ansible@node1 data]$
可以看到,这个时候全部都被当做普通的文件,并没有链接文件。
我们先保留 data1
和 data2
这两个文件夹,以便于后面生成的文件进行对比分析。
我们通过 local_follow
和 follow
来控制一下输出结果。
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy directory with local follow yes and follow no copy: src: /home/ansible/data/ dest: /tmp/local_yes_remote_no local_follow: yes follow: no become: yes - name: Copy directory with local follow yes and follow yes copy: src: /home/ansible/data/ dest: /tmp/local_yes_remote_yes local_follow: yes follow: yes become: yes - name: Copy directory with local follow no and follow no copy: src: /home/ansible/data/ dest: /tmp/local_no_remote_no local_follow: no follow: no become: yes - name: Copy directory with local follow no and follow yes copy: src: /home/ansible/data/ dest: /tmp/local_no_remote_yes local_follow: no follow: yes become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy directory with local follow yes and follow no] **************************** changed: [node1] => {"changed": true, "dest": "/tmp/local_yes_remote_no/", "src": "/home/ansible/data/"} TASK [Copy directory with local follow yes and follow yes] *************************** changed: [node1] => {"changed": true, "dest": "/tmp/local_yes_remote_yes/", "src": "/home/ansible/data/"} TASK [Copy directory with local follow no and follow no] ***************************** changed: [node1] => {"changed": true, "dest": "/tmp/local_no_remote_no/", "src": "/home/ansible/data/"} TASK [Copy directory with local follow no and follow yes] **************************** changed: [node1] => {"changed": true, "dest": "/tmp/local_no_remote_yes/", "src": "/home/ansible/data/"} PLAY RECAP *************************************************************************** node1 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
分四种情况控制复制后的输出。
我们在 node1 节点上面检查一下:
[ansible@node1 tmp]$ ll -i local_* local_no_remote_no: total 16 50442694 lrwxrwxrwx 1 root root 6 Aug 3 17:28 link1 -> origin 50442699 lrwxrwxrwx 1 root root 6 Aug 3 17:28 link2 -> origin 50445918 lrwxrwxrwx 1 root root 11 Aug 3 17:28 link3 -> origin3.txt 138484 -rw-r--r-- 1 root root 9 Aug 3 17:28 link3_hard 50445919 lrwxrwxrwx 1 root root 11 Aug 3 17:28 link4 -> origin4.txt 138485 -rw-r--r-- 1 root root 9 Aug 3 17:28 link4_hard 138487 drwxr-xr-x 2 root root 44 Aug 3 17:28 origin 138469 -rw-r--r-- 1 root root 9 Aug 3 17:28 origin3.txt 138483 -rw-r--r-- 1 root root 9 Aug 3 17:28 origin4.txt local_no_remote_yes: total 16 50418359 lrwxrwxrwx 1 root root 6 Aug 3 17:28 link1 -> origin 50669612 lrwxrwxrwx 1 root root 6 Aug 3 17:28 link2 -> origin 50418356 lrwxrwxrwx 1 root root 11 Aug 3 17:28 link3 -> origin3.txt 138491 -rw-r--r-- 1 root root 9 Aug 3 17:28 link3_hard 50418358 lrwxrwxrwx 1 root root 11 Aug 3 17:28 link4 -> origin4.txt 138492 -rw-r--r-- 1 root root 9 Aug 3 17:28 link4_hard 138494 drwxr-xr-x 2 root root 44 Aug 3 17:28 origin 138482 -rw-r--r-- 1 root root 9 Aug 3 17:28 origin3.txt 138490 -rw-r--r-- 1 root root 9 Aug 3 17:28 origin4.txt local_yes_remote_no: total 24 787855 drwxr-xr-x 2 root root 44 Aug 3 17:27 link1 17046822 drwxr-xr-x 2 root root 44 Aug 3 17:27 link2 400313 -rw-r--r-- 1 root root 9 Aug 3 17:27 link3 787842 -rw-r--r-- 1 root root 9 Aug 3 17:27 link3_hard 400399 -rw-r--r-- 1 root root 9 Aug 3 17:27 link4 787851 -rw-r--r-- 1 root root 9 Aug 3 17:27 link4_hard 33657163 drwxr-xr-x 2 root root 44 Aug 3 17:27 origin 314101 -rw-r--r-- 1 root root 9 Aug 3 17:27 origin3.txt 400312 -rw-r--r-- 1 root root 9 Aug 3 17:27 origin4.txt local_yes_remote_yes: total 24 138476 drwxr-xr-x 2 root root 44 Aug 3 17:28 link1 17430706 drwxr-xr-x 2 root root 44 Aug 3 17:28 link2 138471 -rw-r--r-- 1 root root 9 Aug 3 17:27 link3 138473 -rw-r--r-- 1 root root 9 Aug 3 17:28 link3_hard 138472 -rw-r--r-- 1 root root 9 Aug 3 17:28 link4 138474 -rw-r--r-- 1 root root 9 Aug 3 17:28 link4_hard 33657164 drwxr-xr-x 2 root root 44 Aug 3 17:28 origin 138468 -rw-r--r-- 1 root root 9 Aug 3 17:27 origin3.txt 138470 -rw-r--r-- 1 root root 9 Aug 3 17:27 origin4.txt [ansible@node1 tmp]$
可以看出,复制后的内容权限比较复杂!local_no_remote_no
和 local_no_remote_yes
文件夹内容一样,此时因为不跟随链接文件,软链接仍然存在;local_yes_remote_no
和 local_yes_remote_yes
文件夹内容一样,此时跟随链接文件,会直接复制软链接指向的文件夹中的文件。
可以知道,对于从 Ansible 主机上面复制文件到远程主机,仅 local_follow
起作用,follow
不起作用!
我们在测试一下,在远程主机上面使用 follow
参数进行文件复制。
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy remote directory with follow yes copy: src: /tmp/local_no_remote_no/ dest: /tmp/remote_yes remote_src: yes follow: yes become: yes - name: Copy remote directory with follow no copy: src: /tmp/local_no_remote_no/ dest: /tmp/remote_no remote_src: yes follow: no become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy remote directory with follow yes] ***************************************** changed: [node1] => {"changed": true, "checksum": null, "dest": "/tmp/remote_yes", "gid": 0, "group": "root", "md5sum": null, "mode": "0755", "owner": "root", "size": 146, "src": "/tmp/local_no_remote_no/", "state": "directory", "uid": 0} TASK [Copy remote directory with follow no] ****************************************** changed: [node1] => {"changed": true, "checksum": null, "dest": "/tmp/remote_no", "gid": 0, "group": "root", "md5sum": null, "mode": "0755", "owner": "root", "size": 146, "src": "/tmp/local_no_remote_no/", "state": "directory", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
此时再查看新生成的文件夹:
[ansible@node1 tmp]$ ll -i remote_* remote_no: total 16 33608953 lrwxrwxrwx 1 root root 6 Aug 4 16:52 link1 -> origin 33608955 lrwxrwxrwx 1 root root 6 Aug 4 16:52 link2 -> origin 33608938 lrwxrwxrwx 1 root root 11 Aug 4 16:52 link3 -> origin3.txt 33575000 -rw-r--r-- 1 root root 9 Aug 3 17:28 link3_hard 33608951 lrwxrwxrwx 1 root root 11 Aug 4 16:52 link4 -> origin4.txt 33575002 -rw-r--r-- 1 root root 9 Aug 3 17:28 link4_hard 50442985 drwxr-xr-x 2 root root 44 Aug 3 17:28 origin 33574993 -rw-r--r-- 1 root root 9 Aug 3 17:28 origin3.txt 33574995 -rw-r--r-- 1 root root 9 Aug 3 17:28 origin4.txt remote_yes: total 16 33653763 lrwxrwxrwx 1 root root 6 Aug 4 16:52 link1 -> origin 33653764 lrwxrwxrwx 1 root root 6 Aug 4 16:52 link2 -> origin 33657182 lrwxrwxrwx 1 root root 11 Aug 4 16:52 link3 -> origin3.txt 33657180 -rw-r--r-- 1 root root 9 Aug 3 17:28 link3_hard 33657183 lrwxrwxrwx 1 root root 11 Aug 4 16:52 link4 -> origin4.txt 33657181 -rw-r--r-- 1 root root 9 Aug 3 17:28 link4_hard 50442982 drwxr-xr-x 2 root root 44 Aug 3 17:28 origin 33657161 -rw-r--r-- 1 root root 9 Aug 3 17:28 origin3.txt 33657179 -rw-r--r-- 1 root root 9 Aug 3 17:28 origin4.txt [ansible@node1 tmp]$
可以看到,文件跟随了文件系统,follow
没有起作用!!!有可能我理解错了!
我们把 follow
换成 local_follow
再来试一下:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy remote directory with local_follow yes copy: src: /tmp/local_no_remote_no/ dest: /tmp/local_follow_yes remote_src: yes local_follow: yes become: yes - name: Copy remote directory with local_follow no copy: src: /tmp/local_no_remote_no/ dest: /tmp/local_follow_no remote_src: yes local_follow: no become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy remote directory with local_follow yes] *********************************** changed: [node1] => {"changed": true, "checksum": null, "dest": "/tmp/local_follow_yes", "gid": 0, "group": "root", "md5sum": null, "mode": "0755", "owner": "root", "size": 146, "src": "/tmp/local_no_remote_no/", "state": "directory", "uid": 0} TASK [Copy remote directory with local_follow no] ************************************ changed: [node1] => {"changed": true, "checksum": null, "dest": "/tmp/local_follow_no", "gid": 0, "group": "root", "md5sum": null, "mode": "0755", "owner": "root", "size": 146, "src": "/tmp/local_no_remote_no/", "state": "directory", "uid": 0} PLAY RECAP *************************************************************************** node1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
此时再查看文件系统:
[ansible@node1 tmp]$ ll local_follow_* local_follow_no: total 16 lrwxrwxrwx 1 root root 6 Aug 4 16:59 link1 -> origin lrwxrwxrwx 1 root root 6 Aug 4 16:59 link2 -> origin lrwxrwxrwx 1 root root 11 Aug 4 16:59 link3 -> origin3.txt -rw-r--r-- 1 root root 9 Aug 3 17:28 link3_hard lrwxrwxrwx 1 root root 11 Aug 4 16:59 link4 -> origin4.txt -rw-r--r-- 1 root root 9 Aug 3 17:28 link4_hard drwxr-xr-x 2 root root 44 Aug 3 17:28 origin -rw-r--r-- 1 root root 9 Aug 3 17:28 origin3.txt -rw-r--r-- 1 root root 9 Aug 3 17:28 origin4.txt local_follow_yes: total 24 drwxr-xr-x 2 root root 44 Aug 3 17:28 link1 drwxr-xr-x 2 root root 44 Aug 3 17:28 link2 -rw-r--r-- 1 root root 9 Aug 3 17:28 link3 -rw-r--r-- 1 root root 9 Aug 3 17:28 link3_hard -rw-r--r-- 1 root root 9 Aug 3 17:28 link4 -rw-r--r-- 1 root root 9 Aug 3 17:28 link4_hard drwxr-xr-x 2 root root 44 Aug 3 17:28 origin -rw-r--r-- 1 root root 9 Aug 3 17:28 origin3.txt -rw-r--r-- 1 root root 9 Aug 3 17:28 origin4.txt [ansible@node1 tmp]$
即可以看出 local_follow
是指定是否跟随源文件的,如果源文件是一个软链接文件并且链接到一个目录,则会创建一个同名的目标文件夹,并将源文件软链接指向的文件夹的内容复制到这个目标文件夹中。如果源文件是一个软链接文件,链接到一个文件,则会创建一个同名的目标文件,并将源文件软链接指向的文件的内容复制到这个目标文件中。
我们把 node1 节点上面生成的测试文件删除掉:
[ansible@node1 tmp]$ sudo trash-put data* local_* remote_* [ansible@node1 tmp]$ sudo trash-empty
我们前面对 follow
参数理解有误!
我们重新进行一下测试。
我们来创建一个软链接和一个硬链接:
[ansible@node1 tmp]$ mkdir origin1 [ansible@node1 tmp]$ ln -s origin1 origin1_soft [ansible@node1 tmp]$ mkdir origin2 [ansible@node1 tmp]$ ln -s origin2 origin2_soft [ansible@node1 tmp]$ ll -id origin* 16777294 drwxrwxr-x 2 ansible ansible 6 Aug 4 17:11 origin1 17039808 lrwxrwxrwx 1 ansible ansible 7 Aug 4 17:11 origin1_soft -> origin1 50418355 drwxrwxr-x 2 ansible ansible 6 Aug 4 17:15 origin2 17039809 lrwxrwxrwx 1 ansible ansible 7 Aug 4 17:16 origin2_soft -> origin2
我们重新测试一下,通过控制 follow
参数来复制文件:
[ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy directory with follow yes] ************************************************ An exception occurred during task execution. To see the full traceback, use -vvv. The error was: OSError: [Errno 17] File exists: '/tmp/origin1_soft' fatal: [node1]: FAILED! => {"changed": false, "checksum": "583b2b893e08e60a29a3d1b4d8acef00b08b9fdc", "module_stderr": "Shared connection to node1 closed.\r\n", "module_stdout": "Traceback (most recent call last):\r\n File \"/home/ansible/.ansible/tmp/ansible-tmp-1596533019.5-3995-256786935668312/AnsiballZ_copy.py\", line 102, in <module>\r\n _ansiballz_main()\r\n File \"/home/ansible/.ansible/tmp/ansible-tmp-1596533019.5-3995-256786935668312/AnsiballZ_copy.py\", line 94, in _ansiballz_main\r\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\r\n File \"/home/ansible/.ansible/tmp/ansible-tmp-1596533019.5-3995-256786935668312/AnsiballZ_copy.py\", line 40, in invoke_module\r\n runpy.run_module(mod_name='ansible.modules.files.copy', init_globals=None, run_name='__main__', alter_sys=True)\r\n File \"/usr/lib64/python2.7/runpy.py\", line 176, in run_module\r\n fname, loader, pkg_name)\r\n File \"/usr/lib64/python2.7/runpy.py\", line 82, in _run_module_code\r\n mod_name, mod_fname, mod_loader, pkg_name)\r\n File \"/usr/lib64/python2.7/runpy.py\", line 72, in _run_code\r\n exec code in run_globals\r\n File \"/tmp/ansible_copy_payload_b0y6Zc/ansible_copy_payload.zip/ansible/modules/files/copy.py\", line 790, in <module>\r\n \r\n File \"/tmp/ansible_copy_payload_b0y6Zc/ansible_copy_payload.zip/ansible/modules/files/copy.py\", line 588, in main\r\n \r\n File \"/usr/lib64/python2.7/os.py\", line 157, in makedirs\r\n mkdir(name, mode)\r\nOSError: [Errno 17] File exists: '/tmp/origin1_soft'\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1} PLAY RECAP *************************************************************************** node1 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
复制文件夹出错!因为提示文件夹已经存在!
我们来测试文件看一下。
创建一些文件:
[ansible@node1 tmp]$ echo "file origin 1" > file1_origin [ansible@node1 tmp]$ echo "file origin 2" > file2_origin [ansible@node1 tmp]$ ln -s file1_origin file1_soft [ansible@node1 tmp]$ ln -s file2_origin file2_soft [ansible@node1 tmp]$ ll file* -rw-rw-r-- 1 ansible ansible 14 Aug 4 17:37 file1_origin lrwxrwxrwx 1 ansible ansible 12 Aug 4 17:37 file1_soft -> file1_origin -rw-rw-r-- 1 ansible ansible 14 Aug 4 17:37 file2_origin lrwxrwxrwx 1 ansible ansible 12 Aug 4 17:37 file2_soft -> file2_origin [ansible@node1 tmp]$
再进行复制:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy file with follow yes copy: src: /home/ansible/copy.yml dest: /tmp/file1_soft follow: yes become: yes - name: Copy file with follow no copy: src: /home/ansible/copy.yml dest: /tmp/file2_soft follow: no become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy file with follow yes] ***************************************************** fatal: [node1]: FAILED! => {"msg": "Failed to get information on remote file (/tmp/file1_soft): Permission denied"} PLAY RECAP *************************************************************************** node1 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
oh,no! 又失败了!提示 Failed to get information on remote file (/tmp/file1_soft): Permission denied
,按理说,使用了 become: yes
权限提升后,应该是有权限的!我们通过 root
账号查看 file1_soft
时会提示错误:
[root@node1 tmp]# cat file1_soft cat: file1_soft: Permission denied
可以看到,直接使用 cat
查看软链接文件会提示权限拒绝。
查看文档知道,/tmp
目录由于通常设置了粘滞位,因为 protected_symlinks
拒绝访问 /tmp/file1_soft
,即 /tmp
目录比较特殊。
通过以下命令可以查看已经开启了 fs.protected_symlinks
保护:
# 设置为0时,符号链接跟随行为不受限制。 # 设置为1时,符号链接跟随行为受限制。 [root@node1 ~]# sysctl -n fs.protected_symlinks 1
说明系统开启了 fs.protected_symlinks
保护。
我们看一段粘滞位的介绍。
文件的粘滞位 (sticky) 位是作什么用的?
普通文件的 sticky 位会被 linux 内核忽略,目录的 sticky 位表示这个目录里的文件只能被 owner 和 root 删除。如果用户对目录有写权限,则可以删除其中的文件和子目录,即使该用户不是这些文件的所有者,而且也没有读或写许可。粘滞位出现执行许可的位置上,用
t
表示,设置了该位后,其它用户就不可以删除不属于他的文件和目录。但是该目录下的目录不继承该权限,要再设置才可使用。可以通过以下命令设置粘滞位,
770
前面的1
就表示设置粘滞位:
$ chmod 1770 xxx 举一个 linux 下的常见目录来做例子,也就是 /tmp 目录来说一下粘滞位的作用。
[root@node1 ~]# ls -ld /tmp/ drwxrwxrwt. 11 root root 4096 Aug 5 10:08 /tmp/ [root@node1 ~]# 注意 other 位置的
t
,这便是粘滞位。
我们都知道,/tmp
常被我们用来存放临时文件,是所有用户。但是我们不希望别的用户随随便便的就删除了自己的文件,于是便有了粘滞位,它的作用便是让用户只能删除属于自己的文件。那么原来的执行标志
x
到哪里去了呢?系统是这样规定的,假如本来在该位上有x
, 则这些特别标志 (suid, sgid, sticky) 显示为小写字母 (s, s, t). 否则,显示为大写字母 (S, S, T) 。操作:
$ chmod 777 xxx $ chmod +t xxx 等价于:
chmod 1777 xxx 在以前旧的系统当中,如果一个程序文件一旦设置了粘滞位,那么当该程序中止的时候他的所有指令段将被保存到系统的交换分区当中,
再次运行时可以更快的调入系统.不过现在的操作系统已经不再使用这种功能了。但这并不表示这一功能已经完全被废弃。当一个目录设置为粘滞位时,它将发挥特殊的作用,
即当一个目录被设置为 "粘滞位"(用
chmod a+t
), 则该目录下的文件只能由:
超级管理员删除
该目录的所有者删除
该文件的所有者删除
也就是说,即便该目录是任何人都可以写,但也只有文件的属主才可以删除文件。
好,我们现在不进行权限提升,修改一下剧本文件,再重新运行:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy file with follow yes copy: src: /home/ansible/copy.yml dest: /tmp/file1_soft follow: yes # become: yes - name: Copy file with follow no copy: src: /home/ansible/copy.yml dest: /tmp/file2_soft follow: no # become: yes [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy file with follow yes] ***************************************************** changed: [node1] => {"changed": true, "checksum": "6cbe55a8cc71c4fbc6c5a84b109bb2691e9b86fb", "dest": "/tmp/file1_origin", "gid": 1001, "group": "ansible", "md5sum": "8fc9dd5b009c4b04c69018a441dbb04b", "mode": "0664", "owner": "ansible", "size": 329, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596592106.27-3715-174756753287401/source", "state": "file", "uid": 1001} TASK [Copy file with follow no] ****************************************************** changed: [node1] => {"changed": true, "checksum": "6cbe55a8cc71c4fbc6c5a84b109bb2691e9b86fb", "dest": "/tmp/file2_soft", "gid": 1001, "group": "ansible", "md5sum": "8fc9dd5b009c4b04c69018a441dbb04b", "mode": "0664", "owner": "ansible", "size": 329, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1596592106.91-3731-137128704257098/source", "state": "file", "uid": 1001} PLAY RECAP *************************************************************************** node1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
这次运行成功了!我们来看一下 node1 节点上面的文件变化:
[root@node1 tmp]# ll -i file* 314098 -rw-rw-r-- 1 ansible ansible 329 Aug 5 09:48 file1_origin 17039822 lrwxrwxrwx 1 ansible ansible 12 Aug 4 17:37 file1_soft -> file1_origin 16781287 -rw-rw-r-- 1 ansible ansible 14 Aug 4 17:37 file2_origin 50445901 -rw-rw-r-- 1 ansible ansible 329 Aug 5 09:48 file2_soft [root@node1 tmp]#
由于任务 Copy file with follow yes
开启了 follow: yes
进行目标系统文件的跟随,此时,将 copy.yml
复制到 file1_soft
时,会自动跟踪 file1_soft
指向的文件 file1_origin
, 所以此时会将 file1_origin
进行替换覆盖掉:
[ansible@node1 tmp]$ cat file1_soft - hosts: node1 tasks: - name: Copy file with follow yes copy: src: /home/ansible/copy.yml dest: /tmp/file1_soft follow: yes # become: yes - name: Copy file with follow no copy: src: /home/ansible/copy.yml dest: /tmp/file2_soft follow: no # become: yes [ansible@node1 tmp]$ cat file1_origin - hosts: node1 tasks: - name: Copy file with follow yes copy: src: /home/ansible/copy.yml dest: /tmp/file1_soft follow: yes # become: yes - name: Copy file with follow no copy: src: /home/ansible/copy.yml dest: /tmp/file2_soft follow: no # become: yes [ansible@node1 tmp]$
由于任务 Copy file with follow no
没有开启了 follow
功能,指定的 follow: no
不进行目标系统文件的跟随 , 此时,file2_soft
原来的链接关系将会被打破,file2_soft
变成一个普通的文件,并将 copy.yml
复制到 file2_soft
这个普通文件,而 file2_soft
原先指向的 file2_origin
没有发生变化:
[ansible@node1 tmp]$ cat file2_soft - hosts: node1 tasks: - name: Copy file with follow yes copy: src: /home/ansible/copy.yml dest: /tmp/file1_soft follow: yes # become: yes - name: Copy file with follow no copy: src: /home/ansible/copy.yml dest: /tmp/file2_soft follow: no # become: yes [ansible@node1 tmp]$ cat file2_origin file origin 2 [ansible@node1 tmp]$
我们把测试文件删除掉:
[ansible@node1 tmp]$ trash-put file* [ansible@node1 tmp]$ trash-put origin* [ansible@node1 tmp]$ trash-empty [ansible@node1 tmp]$
5.9 文件夹模式设置
我们可以使用 directory_mode
来设置目标文件夹的文件夹权限模式。当进行递归复制时,新创建的文件夹使用的文件夹模式,该参数对已经存在的文件夹没有影响。
我们先使用临时命令将 Ansible 主机上面的 data
目录复制到 node1 节点上面去。
# 先把权限改回来 [ansible@master ~]$ sudo chown -R ansible:ansible data [ansible@master ~]$ ll data/ total 16 lrwxrwxrwx 1 ansible ansible 6 Aug 3 16:34 link1 -> origin lrwxrwxrwx 1 ansible ansible 6 Aug 3 16:34 link2 -> origin lrwxrwxrwx 1 ansible ansible 11 Aug 3 16:35 link3 -> origin3.txt -rw-rw-r-- 2 ansible ansible 9 Aug 3 16:35 link3_hard lrwxrwxrwx 1 ansible ansible 11 Aug 3 16:35 link4 -> origin4.txt -rw-rw-r-- 2 ansible ansible 9 Aug 3 16:35 link4_hard drwxrwxr-x 2 ansible ansible 44 Aug 3 16:34 origin -rw-rw-r-- 2 ansible ansible 9 Aug 3 16:35 origin3.txt -rw-rw-r-- 2 ansible ansible 9 Aug 3 16:35 origin4.txt [ansible@master ~]$
再进行复制:
[ansible@master ~]$ ansible node1 -m copy -a "src=/home/ansible/data dest=/home/ansible local_follow=no" node1 | CHANGED => { "changed": true, "dest": "/home/ansible/", "src": "/home/ansible/data" } [ansible@master ~]$
查看 node1 节点上面的文件:
[ansible@node1 ~]$ ll data/ total 16 lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link1 -> origin lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link2 -> origin lrwxrwxrwx 1 ansible ansible 11 Aug 5 11:39 link3 -> origin3.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link3_hard lrwxrwxrwx 1 ansible ansible 11 Aug 5 11:39 link4 -> origin4.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link4_hard drwxrwxr-x 2 ansible ansible 44 Aug 5 11:39 origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin3.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin4.txt [ansible@node1 ~]$
好,准备工作做得差不多了,我们现在在 Ansible 主机上面的 data 目录下面创建一些新的文件夹:
[ansible@master ~]$ mkdir -p data/{new1,new11}/{new2,new22}/{new3,new33} [ansible@master ~]$ tree data/ data/ ├── link1 -> origin ├── link2 -> origin ├── link3 -> origin3.txt ├── link3_hard ├── link4 -> origin4.txt ├── link4_hard ├── new1 │ ├── new2 │ │ ├── new3 │ │ └── new33 │ └── new22 │ ├── new3 │ └── new33 ├── new11 │ ├── new2 │ │ ├── new3 │ │ └── new33 │ └── new22 │ ├── new3 │ └── new33 ├── origin │ ├── origin1.txt │ └── origin2.txt ├── origin3.txt └── origin4.txt 17 directories, 8 files [ansible@master ~]$ ls -lah data/new1 total 0 drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 . drwxrwxr-x 5 ansible ansible 171 Aug 5 11:43 .. drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 new2 drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 new22 [ansible@master ~]$ ls -lah data/new11 total 0 drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 . drwxrwxr-x 5 ansible ansible 171 Aug 5 11:43 .. drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 new2 drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 new22 [ansible@master ~]$ ls -lah data/new1/new2 total 0 drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 . drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 .. drwxrwxr-x 2 ansible ansible 6 Aug 5 11:43 new3 drwxrwxr-x 2 ansible ansible 6 Aug 5 11:43 new33 [ansible@master ~]$ ls -lah data/new1/new22 total 0 drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 . drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 .. drwxrwxr-x 2 ansible ansible 6 Aug 5 11:43 new3 drwxrwxr-x 2 ansible ansible 6 Aug 5 11:43 new33 [ansible@master ~]$ ls -lah data/new11/new2 total 0 drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 . drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 .. drwxrwxr-x 2 ansible ansible 6 Aug 5 11:43 new3 drwxrwxr-x 2 ansible ansible 6 Aug 5 11:43 new33 [ansible@master ~]$ ls -lah data/new11/new22 total 0 drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 . drwxrwxr-x 4 ansible ansible 31 Aug 5 11:43 .. drwxrwxr-x 2 ansible ansible 6 Aug 5 11:43 new3 drwxrwxr-x 2 ansible ansible 6 Aug 5 11:43 new33 [ansible@master ~]$ # 更新原来origin目录下的两个文件内容 [ansible@master ~]$ cd data/origin [ansible@master origin]$ echo "origin 1 new" > origin1.txt [ansible@master origin]$ echo "origin 2 new" > origin2.txt [ansible@master origin]$ cat origin1.txt origin 1 new [ansible@master origin]$ cat origin2.txt origin 2 new [ansible@master origin]$ cd [ansible@master ~]$
新创建的文件夹的权限都是 rwxrwxr-x
, 即 775
。并且原来 origin 目录下面的两个文件也已经更新完毕。我们现在使用剧本进行文件夹复制。
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy directory to exist folder with directory_mode='0700' copy: src: /home/ansible/data/ dest: /home/ansible/data directory_mode: '0700' - name: Copy directory to new folder with directory_mode='0700' copy: src: /home/ansible/data/ dest: /home/ansible/newdata directory_mode: '0700' [ansible@master ~]$ ansible-lint copy.yml [ansible@master ~]$ ansible-playbook --syntax-check copy.yml playbook: copy.yml [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy directory to exist folder with directory_mode='0700'] ********************* changed: [node1] => {"changed": true, "dest": "/home/ansible/data/", "src": "/home/ansible/data/"} TASK [Copy directory to new folder with directory_mode='0700'] *********************** changed: [node1] => {"changed": true, "dest": "/home/ansible/newdata/", "src": "/home/ansible/data/"} PLAY RECAP *************************************************************************** node1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
剧本正常执行,我们在 node1 节点上面检查一下:
[ansible@node1 ~]$ ll -d *data drwxrwxr-x 5 ansible ansible 171 Aug 5 14:05 data drwx------ 7 ansible ansible 171 Aug 5 14:05 newdata [ansible@node1 ~]$ ll *data data: total 24 lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link1 -> origin lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link2 -> origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link3_hard -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link4_hard drwx------ 4 ansible ansible 31 Aug 5 14:05 new1 drwx------ 4 ansible ansible 31 Aug 5 14:05 new11 drwx------ 2 ansible ansible 44 Aug 5 14:05 origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin3.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin4.txt newdata: total 24 drwx------ 2 ansible ansible 44 Aug 5 14:05 link1 drwx------ 2 ansible ansible 44 Aug 5 14:05 link2 -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3 -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3_hard -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4 -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4_hard drwx------ 4 ansible ansible 31 Aug 5 14:05 new1 drwx------ 4 ansible ansible 31 Aug 5 14:05 new11 drwx------ 2 ansible ansible 44 Aug 5 14:05 origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 origin3.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 origin4.txt [ansible@node1 ~]$ [ansible@node1 ~]$ ll data/{new1,new11} data/new1: total 0 drwx------ 4 ansible ansible 31 Aug 5 14:05 new2 drwx------ 4 ansible ansible 31 Aug 5 14:05 new22 data/new11: total 0 drwx------ 4 ansible ansible 31 Aug 5 14:05 new2 drwx------ 4 ansible ansible 31 Aug 5 14:05 new22 [ansible@node1 ~]$ ll data/{new1,new11}/{new2,new22} data/new11/new2: total 0 drwx------ 2 ansible ansible 6 Aug 5 14:05 new3 drwx------ 2 ansible ansible 6 Aug 5 14:05 new33 data/new11/new22: total 0 drwx------ 2 ansible ansible 6 Aug 5 14:05 new3 drwx------ 2 ansible ansible 6 Aug 5 14:05 new33 data/new1/new2: total 0 drwx------ 2 ansible ansible 6 Aug 5 14:05 new3 drwx------ 2 ansible ansible 6 Aug 5 14:05 new33 data/new1/new22: total 0 drwx------ 2 ansible ansible 6 Aug 5 14:05 new3 drwx------ 2 ansible ansible 6 Aug 5 14:05 new33 [ansible@node1 ~]$ # 查找权限是700的文件 [ansible@node1 ~]$ find newdata -perm '700' newdata newdata/link1 newdata/link2 newdata/origin newdata/new1 newdata/new1/new2 newdata/new1/new2/new3 newdata/new1/new2/new33 newdata/new1/new22 newdata/new1/new22/new3 newdata/new1/new22/new33 newdata/new11 newdata/new11/new2 newdata/new11/new2/new3 newdata/new11/new2/new33 newdata/new11/new22 newdata/new11/new22/new3 newdata/new11/new22/new33 [ansible@node1 ~]$ find data -perm '700' data/origin data/new1 data/new1/new2 data/new1/new2/new3 data/new1/new2/new33 data/new1/new22 data/new1/new22/new3 data/new1/new22/new33 data/new11 data/new11/new2 data/new11/new2/new3 data/new11/new2/new33 data/new11/new22 data/new11/new22/new3 data/new11/new22/new33 [ansible@node1 ~]$
可以看到,对于原来已经存在在 data
目录,只有新增的 new1
和 new11
及其子目录以及 origin
目录的权限发生变化,都变成了 rwx------
,即 700
的形式,其他文件夹不受影响。而对于 newdata
目录,由于都是新建的文件或文件夹,文件夹都使用 0700
模式。
下面我们再将剧本里面的模式改成 0070
, 这个时候再去复制:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy directory to exist folder with directory_mode='0070' copy: src: /home/ansible/data/ dest: /home/ansible/data directory_mode: '0070' - name: Copy directory to new folder with directory_mode='0070' copy: src: /home/ansible/data/ dest: /home/ansible/newdata directory_mode: '0070' [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy directory to exist folder with directory_mode='0070'] ********************* fatal: [node1]: FAILED! => {"changed": false, "msg": "There was an issue creating /home/ansible/data/new1/new2 as requested: [Errno 13] Permission denied: '/home/ansible/data/new1/new2'", "path": "/home/ansible/data/new1/new2"} PLAY RECAP *************************************************************************** node1 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
kuang! 出错了,因为这个时候改成了所有者也不能读和写!这时候查看 node1 节点上面的权限:
[ansible@node1 data]$ ll total 24 lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link1 -> origin lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link2 -> origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link3_hard -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link4_hard d---rwx--- 4 ansible ansible 31 Aug 5 14:05 new1 d---rwx--- 4 ansible ansible 31 Aug 5 14:05 new11 d---rwx--- 2 ansible ansible 44 Aug 5 14:05 origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin3.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin4.txt [ansible@node1 data]$ ll new1 ls: cannot open directory new1: Permission denied [ansible@node1 data]$ sudo ls -lah new1/ total 0 d---rwx--- 4 ansible ansible 31 Aug 5 14:05 . drwxrwxr-x 5 ansible ansible 171 Aug 5 14:05 .. drwx------ 4 ansible ansible 31 Aug 5 14:05 new2 drwx------ 4 ansible ansible 31 Aug 5 14:05 new22 [ansible@node1 data]$
可以看到,这种随意改权限模式可能会存在问题。
我们把权限改回去:
[ansible@node1 ~]$ ls -lah data/ total 24K drwxrwxr-x 5 ansible ansible 171 Aug 5 14:05 . drwx------ 9 ansible ansible 331 Aug 5 14:05 .. lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link1 -> origin lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link2 -> origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link3_hard -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link4_hard d---rwx--- 4 ansible ansible 31 Aug 5 14:05 new1 d---rwx--- 4 ansible ansible 31 Aug 5 14:05 new11 d---rwx--- 2 ansible ansible 44 Aug 5 14:05 origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin3.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin4.txt [ansible@node1 ~]$ sudo chmod -R 700 data/{new1,new11,origin} [ansible@node1 ~]$ ls -lah data/ total 24K drwxrwxr-x 5 ansible ansible 171 Aug 5 14:05 . drwx------ 9 ansible ansible 331 Aug 5 14:05 .. lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link1 -> origin lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link2 -> origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link3_hard -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link4_hard drwx------ 4 ansible ansible 31 Aug 5 14:05 new1 drwx------ 4 ansible ansible 31 Aug 5 14:05 new11 drwx------ 2 ansible ansible 44 Aug 5 14:05 origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin3.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin4.txt [ansible@node1 ~]$
此时权限已经改回去了。
我们重新设置一下 directory_mode='0770'
, 再运行剧本:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy directory to exist folder with directory_mode='0770' copy: src: /home/ansible/data/ dest: /home/ansible/data directory_mode: '0770' - name: Copy directory to new folder with directory_mode='0770' copy: src: /home/ansible/data/ dest: /home/ansible/newdata directory_mode: '0770' [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy directory to exist folder with directory_mode='0770'] ********************* changed: [node1] => {"changed": true, "dest": "/home/ansible/data/", "src": "/home/ansible/data/"} TASK [Copy directory to new folder with directory_mode='0770'] *********************** changed: [node1] => {"changed": true, "dest": "/home/ansible/newdata/", "src": "/home/ansible/data/"} PLAY RECAP *************************************************************************** node1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
此时检查 node1 节点上面的文件夹情况:
[ansible@node1 ~]$ ls -ld data newdata drwxrwxr-x 5 ansible ansible 171 Aug 5 14:05 data drwx------ 7 ansible ansible 171 Aug 5 14:05 newdata [ansible@node1 ~]$ ls -lah data/ total 24K drwxrwxr-x 5 ansible ansible 171 Aug 5 14:05 . drwx------ 9 ansible ansible 331 Aug 5 14:05 .. lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link1 -> origin lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link2 -> origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link3_hard -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link4_hard drwxrwx--- 4 ansible ansible 31 Aug 5 14:05 new1 drwxrwx--- 4 ansible ansible 31 Aug 5 14:05 new11 drwxrwx--- 2 ansible ansible 44 Aug 5 14:05 origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin3.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin4.txt [ansible@node1 ~]$ ls -lah newdata/ total 24K drwx------ 7 ansible ansible 171 Aug 5 14:05 . drwx------ 9 ansible ansible 331 Aug 5 14:05 .. drwxrwx--- 2 ansible ansible 44 Aug 5 14:05 link1 drwxrwx--- 2 ansible ansible 44 Aug 5 14:05 link2 -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3 -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3_hard -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4 -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4_hard drwxrwx--- 4 ansible ansible 31 Aug 5 14:05 new1 drwxrwx--- 4 ansible ansible 31 Aug 5 14:05 new11 drwxrwx--- 2 ansible ansible 44 Aug 5 14:05 origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 origin3.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 origin4.txt [ansible@node1 ~]$ find data -perm '770' data/origin data/new1 data/new1/new2 data/new1/new2/new3 data/new1/new2/new33 data/new1/new22 data/new1/new22/new3 data/new1/new22/new33 data/new11 data/new11/new2 data/new11/new2/new3 data/new11/new2/new33 data/new11/new22 data/new11/new22/new3 data/new11/new22/new33 [ansible@node1 ~]$ find newdata -perm '770' newdata/link1 newdata/link2 newdata/origin newdata/new1 newdata/new1/new2 newdata/new1/new2/new3 newdata/new1/new2/new33 newdata/new1/new22 newdata/new1/new22/new3 newdata/new1/new22/new33 newdata/new11 newdata/new11/new2 newdata/new11/new2/new3 newdata/new11/new2/new33 newdata/new11/new22 newdata/new11/new22/new3 newdata/new11/new22/new33 [ansible@node1 ~]$
可以看到,虽然父目录的权限没有发生变化,但子目录的权限都发生变化了!可见并不是新建的文件夹才会受影响!
directory_mode
When doing a recursive copy set the mode for the directories.
If this is not set we will use the system defaults.
The mode is only set on directories which are newly created, and will not affect those that already existed.
而官方文档上面这么写的,通过验证可知,这种说法并不准确!
我们再次试一下,将 directory_mode='0777'`, 再运行剧本:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy directory to exist folder with directory_mode='0777' copy: src: /home/ansible/data/ dest: /home/ansible/data directory_mode: '0777' - name: Copy directory to new folder with directory_mode='0777' copy: src: /home/ansible/data/ dest: /home/ansible/newdata directory_mode: '0777' [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy directory to exist folder with directory_mode='0777'] ********************* changed: [node1] => {"changed": true, "dest": "/home/ansible/data/", "src": "/home/ansible/data/"} TASK [Copy directory to new folder with directory_mode='0777'] *********************** changed: [node1] => {"changed": true, "dest": "/home/ansible/newdata/", "src": "/home/ansible/data/"} PLAY RECAP *************************************************************************** node1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
再次查看 node1 节点权限情况:
[ansible@node1 ~]$ ls -ld data newdata drwxrwxr-x 5 ansible ansible 171 Aug 5 14:05 data drwx------ 7 ansible ansible 171 Aug 5 14:05 newdata [ansible@node1 ~]$ ls -lah data/ total 24K drwxrwxr-x 5 ansible ansible 171 Aug 5 14:05 . drwx------ 9 ansible ansible 331 Aug 5 14:05 .. lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link1 -> origin lrwxrwxrwx 1 ansible ansible 6 Aug 5 11:39 link2 -> origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link3_hard -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4 -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 link4_hard drwxrwxrwx 4 ansible ansible 31 Aug 5 14:05 new1 drwxrwxrwx 4 ansible ansible 31 Aug 5 14:05 new11 drwxrwxrwx 2 ansible ansible 44 Aug 5 14:05 origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin3.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 11:39 origin4.txt [ansible@node1 ~]$ ls -lah newdata/ total 24K drwx------ 7 ansible ansible 171 Aug 5 14:05 . drwx------ 9 ansible ansible 331 Aug 5 14:05 .. drwxrwxrwx 2 ansible ansible 44 Aug 5 14:05 link1 drwxrwxrwx 2 ansible ansible 44 Aug 5 14:05 link2 -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3 -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link3_hard -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4 -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 link4_hard drwxrwxrwx 4 ansible ansible 31 Aug 5 14:05 new1 drwxrwxrwx 4 ansible ansible 31 Aug 5 14:05 new11 drwxrwxrwx 2 ansible ansible 44 Aug 5 14:05 origin -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 origin3.txt -rw-rw-r-- 1 ansible ansible 9 Aug 5 14:05 origin4.txt [ansible@node1 ~]$ find data -perm '777' data/origin data/link1 data/link2 data/new1 data/new1/new2 data/new1/new2/new3 data/new1/new2/new33 data/new1/new22 data/new1/new22/new3 data/new1/new22/new33 data/new11 data/new11/new2 data/new11/new2/new3 data/new11/new2/new33 data/new11/new22 data/new11/new22/new3 data/new11/new22/new33 [ansible@node1 ~]$ find newdata -perm '777' newdata/link1 newdata/link2 newdata/origin newdata/new1 newdata/new1/new2 newdata/new1/new2/new3 newdata/new1/new2/new33 newdata/new1/new22 newdata/new1/new22/new3 newdata/new1/new22/new33 newdata/new11 newdata/new11/new2 newdata/new11/new2/new3 newdata/new11/new2/new33 newdata/new11/new22 newdata/new11/new22/new3 newdata/new11/new22/new33 [ansible@node1 ~]$
可以看到,并没有新的文件产生,但是文件夹的权限却发生了变化!
我们再来测试一下子文件夹的复制:
[ansible@node1 ~]$ ll -d data/new1 drwxrwxrwx 4 ansible ansible 31 Aug 5 15:25 data/new1 [ansible@node1 ~]$ ll data/new1 total 0 drwxrwxrwx 4 ansible ansible 31 Aug 5 14:05 new2 drwxrwxrwx 4 ansible ansible 31 Aug 5 14:05 new22
我们复制 new1
目录:
[ansible@master ~]$ cat copy.yml - hosts: node1 tasks: - name: Copy directory to exist folder with directory_mode='0700' copy: src: /home/ansible/data/new1/ dest: /home/ansible/data/new1 directory_mode: '0700' [ansible@master ~]$ ansible-playbook copy.yml -v Using /etc/ansible/ansible.cfg as config file PLAY [node1] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [node1] TASK [Copy directory to exist folder with directory_mode='0700'] ********************* changed: [node1] => {"changed": true, "dest": "/home/ansible/data/new1/", "src": "/home/ansible/data/new1/"} PLAY RECAP *************************************************************************** node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [ansible@master ~]$
再次查看目录权限:
[ansible@node1 ~]$ ll -d data/new1 drwxrwxrwx 4 ansible ansible 31 Aug 5 15:25 data/new1 [ansible@node1 ~]$ ll data/new1 total 0 drwx------ 4 ansible ansible 31 Aug 5 14:05 new2 drwx------ 4 ansible ansible 31 Aug 5 14:05 new22 [ansible@node1 ~]$ ll data/new1/* data/new1/new2: total 0 drwx------ 2 ansible ansible 6 Aug 5 14:05 new3 drwx------ 2 ansible ansible 6 Aug 5 14:05 new33 data/new1/new22: total 0 drwx------ 2 ansible ansible 6 Aug 5 14:05 new3 drwx------ 2 ansible ansible 6 Aug 5 14:05 new33
可以看到目标系统中的目标目录 data/new1
的权限并没有发生变化,但目标目录 data/new1
的子目录权限发生了变化!!!
记得删除测试文件!
6. 总结
- 使用相对路径时,Ansible 会从用户家目录或者家目录下面的
files
文件夹去搜索需要复制的文件。 - 使用
backup
参数可以对目录文件进行备份。 - 使用
mode
修改权限时,应该将 user/group/other 都指定出来! local_follow
是指定是否跟随源文件的,如果源文件是一个软链接文件并且链接到一个目录,则会创建一个同名的目标文件夹,并将源文件软链接指向的文件夹的内容复制到这个目标文件夹中。如果源文件是一个软链接文件,链接到一个文件,则会创建一个同名的目标文件,并将源文件软链接指向的文件的内容复制到这个目标文件中。follow
可以跟踪目标系统上面的文件软链接,设置follow=yes
时,会对软链接指向的文件进行覆盖重写,软链接关系仍然存在。设置follow=no
时,软链接关系被破坏,软链接文件变成一个普通文件,软链接指向的文件保持不变,会将源文件内容复制到这个普通文件中。directory_mode
参数会改变文件夹复制到目标系统上面的文件夹权限模式,如果目标目录不存在,则会新建目录,并且对目标目录及其子目录都会应用该文件夹权限模式;如果目标目录存在,则不会影响目标目录本身,只会影响目标目录的子目录!
参考: