0

I am trying to figure out how to use Ansible to set permissions on a directory tree so that the default will be 644 as default (755 for directories, of course), except for a directory that needs 664/775 permissions.

The naive implementation would be this:

file:
    path: "mypath"
    mode: "u+rwX,go+rX,go-w"
    recurse: True

file:
    path: "mypath/exception"
    mode: "g+w"
    recurse: True

However, this is obviously not idempotent. With every run, mypath/exception will have the group-write permissions removed, and then immediately re-added.

The alternative is to enumerate each individual subdirectory in mypath/*, which I hope to avoid.

Is there another way to accomplish this in an idempotent way?

1

You can use the find module to generate a list of paths, and then operate on those paths instead of using recurse. For example:

---
- hosts: localhost
  gather_facts: false
  tasks:

    - find:
        paths:
          - mypath
        recurse: true
        file_type: any
      register: results

    - file:
        path: "{{ item.path }}"
        mode: "u+rwX,go+rX,go-w"
      when: >-
        "mypath/exception" not in item.path
      loop: "{{ results.files }}"
      loop_control:
        label: "{{ item.path }}"

    - file:
        path: "{{ item.path }}"
        mode: "g+w"
      when: >-
        "mypath/exception" in item.path
      loop: "{{ results.files }}"
      loop_control:
        label: "{{ item.path }}"

Running the above playbook against a sample directory tree yields something like:

PLAY [localhost] ******************************************************************************

TASK [find] ***********************************************************************************
ok: [localhost]

TASK [file] ***********************************************************************************
skipping: [localhost] => (item=mypath/exception) 
ok: [localhost] => (item=mypath/dir2)
ok: [localhost] => (item=mypath/dir3)
skipping: [localhost] => (item=mypath/exception/file3) 
skipping: [localhost] => (item=mypath/exception/file2) 
skipping: [localhost] => (item=mypath/exception/file1) 
ok: [localhost] => (item=mypath/dir2/dirc)
ok: [localhost] => (item=mypath/dir2/dira)
ok: [localhost] => (item=mypath/dir2/dirb)
ok: [localhost] => (item=mypath/dir2/dirc/somefile)
ok: [localhost] => (item=mypath/dir2/dira/somefile)
ok: [localhost] => (item=mypath/dir2/dirb/somefile)
ok: [localhost] => (item=mypath/dir3/dirc)
ok: [localhost] => (item=mypath/dir3/dira)
ok: [localhost] => (item=mypath/dir3/dirb)
ok: [localhost] => (item=mypath/dir3/dirc/somefile)
ok: [localhost] => (item=mypath/dir3/dira/somefile)
ok: [localhost] => (item=mypath/dir3/dirb/somefile)

TASK [file] ***********************************************************************************
ok: [localhost] => (item=mypath/exception)
skipping: [localhost] => (item=mypath/dir2) 
skipping: [localhost] => (item=mypath/dir3) 
ok: [localhost] => (item=mypath/exception/file3)
ok: [localhost] => (item=mypath/exception/file2)
ok: [localhost] => (item=mypath/exception/file1)
skipping: [localhost] => (item=mypath/dir2/dirc) 
skipping: [localhost] => (item=mypath/dir2/dira) 
skipping: [localhost] => (item=mypath/dir2/dirb) 
skipping: [localhost] => (item=mypath/dir2/dirc/somefile) 
skipping: [localhost] => (item=mypath/dir2/dira/somefile) 
skipping: [localhost] => (item=mypath/dir2/dirb/somefile) 
skipping: [localhost] => (item=mypath/dir3/dirc) 
skipping: [localhost] => (item=mypath/dir3/dira) 
skipping: [localhost] => (item=mypath/dir3/dirb) 
skipping: [localhost] => (item=mypath/dir3/dirc/somefile) 
skipping: [localhost] => (item=mypath/dir3/dira/somefile) 
skipping: [localhost] => (item=mypath/dir3/dirb/somefile) 

PLAY RECAP ************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0   

This playbook will be properly idempotent.

  • Thank you! Perfect. Well, close to it, but that's not your fault. Using the find module is far too slow and uses too much memory in my case; my directory tree has more than 100,000 files. If it wasn't for that, your approach would be the perfect solution! Thanks again! – Kevin Keane Apr 30 '19 at 0:39
  • And an extra thank you for the loop_control ... label construct. Another very useful little trick! – Kevin Keane Apr 30 '19 at 0:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.