Ansible - 对目录采用755模式,对文件采用644模式进行递归操作

77

我想允许任何人列出并阅读我的目录树中的所有文件,但我不想将这些文件设置为可执行文件:

dir
  \subdir1
      file1
  \subdir2
      file2
  ...
  \subdirX
      fileX
以下任务使我的目录和文件变为可读,但也会将所有文件变为可执行:
- name: Make my directory tree readable
  file:
    path: dir
    mode: 0755
    recurse: yes

另一方面,如果我选择0644模式,则所有文件都不可执行,但无法列出目录。

是否可能为目录树中的所有目录设置755模式,并为目录中的所有文件设置644模式?


一个快速的问题是: 模式:755 是否可以使用其他代替八进制? - Ait Zaid
4个回答

117

自版本1.8起,Ansible支持符号模式。因此,以下操作将执行您想要的任务:

- name: Make my directory tree readable
  file:
    path: dir
    mode: u=rwX,g=rX,o=rX
    recurse: yes

由于X(而不是x)仅适用于至少设置了一个x位的目录或文件。


2
这是最好的且最短的解决方案。 - Quanlong
2
如果我没记错的话,虽然这样可以工作,但它会执行得非常慢,因为它使用stat来逐个检查每个文件/文件夹。在服务器上调用chmod会快得多。 - Jeff Widman
2
chmod 也会使用 stat(2)。你可以通过 strace 看到这一点。这可能会更快,因为 Ansible 可能会在 Python 中实现它。 - Mircea Vutcovici
2
获取 FAILED! => {"changed": false, "failed": true, "msg": "recurse选项要求状态为'directory'", "path": "dir", "state": "absent"} - borisdiakur
10
我不会说这是完整的解决方案。如果您解压缩一些拥有各种权限设置(例如所有文件和目录都设置为755)的东西,这将不会有任何作用。假设您想要仅将文件更改为644,则无法执行此操作,因为其中所有文件至少有一个x位被设置。在ansible中所需的是一种递归遍历目录并仅针对文件进行更新的方法,但似乎没有办法做到这一点,除非使用某些变通方法。 - seeafish
显示剩余4条评论

29
Ansible的文件/copy模块无法根据文件类型提供权限细分,因此您最有可能需要手动完成此操作,具体操作如下:
- name: Ensure directories are 0755
  command: find {{ path }} -type d -exec chmod -c 0755 {} \;
  register: chmod_result
  changed_when: "chmod_result.stdout != \"\""

- name: Ensure files are 0644
  command: find {{ path }} -type f -exec chmod -c 0644 {} \;
  register: chmod_result
  changed_when: "chmod_result.stdout != \"\""

这将递归地遍历 {{ path }} 并将每个文件或目录的权限更改为指定的权限。


4
实际上,这只是一个权宜之计,而不是解决方案。该任务的状态始终为“已更改”,因此无法持续运行以确保配置一致性。 - mykola
6
语义学。除非有人愿意编写一个模块、Shell 脚本等来执行此操作并向 Ansible 报告更改情况,否则这大概是唯一的解决方案。原始问题没有指定需要这样做,只是希望根据文件和目录递归更改权限。 - Bruce P
1
如果权限对于所有者来说是可以的,您还可以使用mode: go=u-w - Penz
4
你可以尝试使用chmod -c命令,并使用changed_when条件进行操作。 - augurar

7
由于实现不足,Ansible仅部分支持符号模式(请参见下面的说明)。
除了使用命令行chmod之外,使用Ansible将模式设置为u=rwX,g=rX,o=rX并不能始终足以使您的文件设置为644。结果的权限还取决于文件的原始模式!
正如在chmod的文档中所述,并且已经由其他答案的一些评论指出的那样: 如果ugo的文件权限是可执行的,则X也会将文件权限设置为x
例如,如果一个文件的模式为740 -rwxr-----,使用ansible设置模式u=rwX,g=rX,o=rX,您将得到755 -rwxr-xr-x,而不是预期的644 -rw-r--r--。尽管这不是您想要的,但它将使文件对组和其他人可执行,从而带来不必要的安全问题。
在这些情况下,使用Ansible需要两个步骤将文件权限设置为644。
- file:
    path: /path/to/dir
    state: directory
    recurse: yes
    mode: '{{ item }}'
  loop:
    - '-x'
    - 'u=rwX,g=rX,o=rX'
  • 请注意,如果您想为文件设置744模式,则需要使用u=rwx,g=rX,o=rX(第一个x小写!)。这在当前的Ansible实现中有效,但这不是命令行chmod的工作方式。请参见下面的**带符号节点的chmod。

为什么会这样:

Ansible在函数_symbolic_mode_to_octal中包含了诸如:u=rw-x+X,g=r-x+X,o=r-x+X之类的内容。

然而,如果给定的模式是g=-x+X,则Ansible会忽略-x权限。

函数_symbolic_mode_to_octal遍历给定的权限时,当涉及到X时,函数_get_octal_mode_from_symbolic_perms不会将请求的权限与已应用的权限进行比较,而是与原始权限进行比较,从而忽略它:

这可能是Ansible中的一个错误。

最简单和高效的方法是委托给一个 shell 命令: 如@BruceP's answer中所提议的。

如果由于某种原因您不想使用“解决办法”并且需要一种类似于 Ansible 的方式来解决问题而且您不关心性能,可以尝试以下操作:

注意:这将根据文件和目录的数量非常非常长时间!

- name: example
  hosts: 192.168.111.123
  become: yes
  gather_facts: no
  vars:
    path_to_dir: /path/to/dir
    target_mode_for_directories: 755
    target_mode_for_files: 644
  tasks:
    - name: collect list of directories '{{ path_to_dir }}'
      find:
        paths: '{{ path_to_dir }}'
        recurse: yes
        file_type: directory
      register: found_directories
    - name: set collected directories to mode '{{ target_mode_for_directories }}'
      file:
        dest: '{{ item.path }}'
        mode: '{{ target_mode_for_directories }}'
      loop: '{{ found_directories.files }}'
    - name: collect list of files under '{{ path_to_dir }}'
      find:
        paths: '{{ path_to_dir }}'
        recurse: yes
        file_type: file
      register: found_files
    - name: set collected files to mode '{{ target_mode_for_files }}'
      file:
        dest: '{{ item.path }}'
        mode: '{{ target_mode_for_files }}'
      loop: '{{ found_files.files }}'

使用chmod设置符号模式

请记住,使用chmod设置符号模式可能非常棘手。 请参考以下示例,它们仅在小写和大写字母X的顺序上有所不同,即u=X,g=X,o=x(o=小写x)与u=x,g=X,o=X(u=小写x),结果为001 ---------x111 ---x--x--x

$ sudo chmod -R 000 path/to/file; \
  sudo chmod -R u=X,g=X,o=x path/to/file; \
  sudo find path/to/file -printf ""%03m" "%M" "%p\\n"";

001 ---------x path/to/file

$ sudo chmod -R 000 path/to/file; \
  sudo chmod -R u=x,g=X,o=X path/to/file; \
  sudo find path/to/file -printf ""%03m" "%M" "%p\\n"";

111 ---x--x--x path/to/file


这是因为权限首先针对u进行处理,然后是g,最后是o。在第一个示例中,由于没有x权限,因此X不适用于文件。在第二种情况下,在设置了u=x之后,X将适用于文件,从而设置了g=xo=x

1
这对我有效:

- file:
    path: dir
    mode: a-x
    recurse: yes
- file:
    path: dir
    mode: u=rwX,g=rX,o=rX
    recurse: yes

首先,需要从所有文件中删除执行权限,否则组和其他用户将获得对文件的执行权限。

有关X指令,请参阅chmod手册页面:

仅在文件是目录或已经对某些用户具有执行权限(X)时才执行/搜索

此外,这也可行:

- shell: "chmod -R a-x,u=rwX,g=rX,o=rX dir"

由于某种原因,这两者的组合不起作用:
- file:
    path: dir
    mode: a-x,u=rwX,g=rX,o=rX
    recurse: yes

当你说它不起作用时,请在问题中添加任何错误。 - somename
1
没有错误。当初始状态为777时,文件只会获得执行权限。 - Jukka A
@JukkaA是正确的。他指出符号模式X和组合符号权限在Ansible中都不起作用。请参阅我的答案中的解释。 - wolfrevo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接